Skip to content

Instantly share code, notes, and snippets.

@shangdawei
Forked from culots/gpt_parser.py
Last active March 25, 2024 05:52
Show Gist options
  • Save shangdawei/f0010f96bd3fe1c7e4bdc5695d2ae640 to your computer and use it in GitHub Desktop.
Save shangdawei/f0010f96bd3fe1c7e4bdc5695d2ae640 to your computer and use it in GitHub Desktop.
Feed this your GPT.bin, and out it shoots a partition.xml
#!/usr/bin/python
# Author : n0fate
# E-Mail rapfer@gmail.com, n0fate@live.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Using structures defined in Wikipedia('http://en.wikipedia.org/wiki/GUID_Partition_Table')
import sys,os,getopt
import random,math
import struct
import hashlib
import uuid
import zlib
if sys.version_info < (2,5):
sys.stdout.write("\n\nERROR: This script needs Python version 2.5 or greater, detected as ")
print sys.version_info
sys.exit() # error
LBA_SIZE = 512
PRIMARY_GPT_LBA = 1
OFFSET_CRC32_OF_HEADER = 16
GPT_HEADER_FORMAT = '<8sIIIIQQQQ16sQIII420x'
GUID_PARTITION_ENTRY_FORMAT = '<16s16sQQQ72s'
## gpt parser code start
def get_lba(fhandle, entry_number, count):
fhandle.seek(LBA_SIZE*entry_number)
fbuf = fhandle.read(LBA_SIZE*count)
return fbuf
def unsigned32(n):
return n & 0xFFFFFFFFL
def get_gpt_header(fhandle, fbuf, lba):
fbuf = get_lba(fhandle, lba, 1)
gpt_header = struct.unpack(GPT_HEADER_FORMAT, fbuf)
crc32_header_value = calc_header_crc32(fbuf, gpt_header[2])
return gpt_header, crc32_header_value, fbuf
def make_nop(byte):
nop_code = 0x00
pk_nop_code = struct.pack('=B', nop_code)
nop = pk_nop_code*byte
return nop
def calc_header_crc32(fbuf, header_size):
nop = make_nop(4)
clean_header = fbuf[:OFFSET_CRC32_OF_HEADER] + nop + fbuf[OFFSET_CRC32_OF_HEADER+4:header_size]
crc32_header_value = unsigned32(zlib.crc32(clean_header))
return crc32_header_value
def an_gpt_header(gpt_header, crc32_header_value, gpt_buf):
md5 = hashlib.md5()
md5.update(gpt_buf)
md5 = md5.hexdigest()
signature = gpt_header[0]
revision = gpt_header[1]
headersize = gpt_header[2]
crc32_header = gpt_header[3]
reserved = gpt_header[4]
currentlba = gpt_header[5]
backuplba = gpt_header[6]
first_use_lba_for_partitions = gpt_header[7]
last_use_lba_for_partitions = gpt_header[8]
disk_guid = uuid.UUID(bytes_le=gpt_header[9])
part_entry_start_lba = gpt_header[10]
num_of_part_entry = gpt_header[11]
size_of_part_entry = gpt_header[12]
crc32_of_partition_array = gpt_header[13]
print '<?xml version="1.0"?>'
print '\t<configuration>'
print '\t\t<!-- Primary GPT header: -->'
print '\t\t<!-- MD5: %s -->' %md5
print '\t\t<!-- Signature: %s -->' %signature
print '\t\t<!-- Revision: %d -->' %revision
print '\t\t<!-- Header Size: %d -->' %headersize
if crc32_header_value == crc32_header:
print '\t\t<!-- CRC32 of header: %X (VALID) => Real: %X -->'%(crc32_header, crc32_header_value)
else:
print '\t\t<!-- WARNING!! CRC32 of header: %X (INVALID) => Real: %X -->'%(crc32_header, crc32_header_value)
print '\t\t<!-- Current LBA: 0x%.8X -->'%currentlba
print '\t\t<!-- Backup LBA: 0x%.8X -->'%backuplba
print '\t\t<!-- First usable LBA for partitions: 0x%.8X -->'%first_use_lba_for_partitions
print '\t\t<!-- Last usable LBA for partitions: 0x%.8X -->'%last_use_lba_for_partitions
print '\t\t<!-- Disk GUID: %s -->'%str(disk_guid).upper()
print '\t\t<!-- Partition entries starting LBA: 0x%.8X -->'%part_entry_start_lba
print '\t\t<!-- Number of partition entries: %d -->'%num_of_part_entry
print '\t\t<!-- Size of partition entry: 0x%.8X -->'%size_of_part_entry
print '\t\t<!-- CRC32 of partition array: 0x%.8X -->'%crc32_of_partition_array
print '\t\t<parser_instructions>'
print '\t\t\t<!-- NOTE: entries here are used by the parser when generating output -->'
print '\t\t\t<!-- NOTE: each filename must be on it\'s own line as in variable=value-->'
print '\t\t\tWRITE_PROTECT_BOUNDARY_IN_KB = 32768'
print '\t\t\tGROW_LAST_PARTITION_TO_FILL_DISK = true'
print '\t\t</parser_instructions>\n'
print '\t\t<!-- NOTE: "physical_partition" are listed in order and apply to devices such as eMMC cards that have (for example) 3 physical partitions -->'
print '\t\t<!-- This is physical partition 0 -->'
print '\t\t<physical_partition>'
print '\t\t\t<!-- NOTE: Define information for each partition, which will be created in order listed here -->'
print '\t\t\t<!-- NOTE: Place all "readonly=true" partitions side by side for optimum space usage -->'
print '\t\t\t<!-- NOTE: If OPTIMIZE_READONLY_PARTITIONS=true, then partitions won\'t be in the order listed here -->'
print '\t\t\t<!-- they will instead be placed side by side at the beginning of the disk -->'
# get partition entry
def get_part_entry(fbuf, offset, size):
return struct.unpack(GUID_PARTITION_ENTRY_FORMAT, fbuf[offset:offset+size])
def get_part_table_area(f, gpt_header):
part_entry_start_lba = gpt_header[10]
first_use_lba_for_partitions = gpt_header[7]
fbuf = get_lba(f, part_entry_start_lba, first_use_lba_for_partitions - part_entry_start_lba)
return fbuf
def part_attribute(value):
if value == 0:
return 'System Partition'
elif value == 2:
return 'Legacy BIOS Bootable'
elif value == 60:
return 'Read-Only'
elif value == 62:
return 'Hidden'
elif value == 63:
return 'Do not automount'
else:
return 'UNKNOWN'
def check_partition_guid_type(guid):
if guid == '024DEE41-33E7-11D3-9D69-0008C781F39F':
return 'MBR partition scheme', 'None'
elif guid == 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B':
return 'EFI System partition', 'None'
elif guid == '21686148-6449-6E6F-744E-656564454649':
return 'BIOS Boot partition', 'None'
# Windows
elif guid == 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE':
return 'Microsoft Reserved Partition', 'Windows'
elif guid == 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7':
return 'Basic data partition / Linux filesystem data', 'Windows / Linux'
elif guid == '5808C8AA-7E8F-42E0-85D2-E1E90434CFB3':
return 'Logical Disk Manager metadata partition', 'Windows'
elif guid == 'AF9B60A0-1431-4F62-BC68-3311714A69AD':
return 'Logical Disk Manager data partition', 'Windows'
elif guid == 'DE94BBA4-06D1-4D40-A16A-BFD50179D6AC':
return 'Windows Recovery Environment', 'Windows'
elif guid == '37AFFC90-EF7D-4E96-91C3-2D7AE055B174':
return 'IBM General Parallel File System (GPFS) partition', 'Windows'
elif guid == 'DB97DBA9-0840-4BAE-97F0-FFB9A327C7E1':
return 'Cluster metadata partition', 'Windows'
# HP-UX
elif guid == '75894C1E-3AEB-11D3-B7C1-7B03A0000000':
return 'Data partition', 'HP-UX'
elif guid == 'E2A1E728-32E3-11D6-A682-7B03A0000000':
return 'Service partition', 'HP-UX'
# Linux
elif guid == '0FC63DAF-8483-4772-8E79-3D69D8477DE4':
return 'Linux filesystem data', 'Linux'
elif guid == 'A19D880F-05FC-4D3B-A006-743F0F84911E':
return 'RAID partition', 'Linux'
elif guid == '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F':
return 'Swao partition', 'Linux'
elif guid == 'E6D6D379-F507-44C2-A23C-238F2A3DF928':
return 'Logical Volume Manager (LVM) partition', 'Linux'
elif guid == '8DA63339-0007-60C0-C436-083AC8230908':
return 'Reserved', 'Linux'
# FreeBSD
elif guid == '83BD6B9D-7F41-11DC-BE0B-001560B84F0F':
return 'Boot partition', 'FreeBSD'
elif guid == '516E7CB4-6ECF-11D6-8FF8-00022D09712B':
return 'Data partition', 'FreeBSD'
elif guid == '516E7CB5-6ECF-11D6-8FF8-00022D09712B':
return 'Swap partition', 'FreeBSD'
elif guid == '516E7CB6-6ECF-11D6-8FF8-00022D09712B':
return 'Unix File System(UFS) partition', 'FreeBSD'
elif guid == '516E7CB8-6ECF-11D6-8FF8-00022D09712B':
return 'Vinum volume manager partition', 'FreeBSD'
elif guid == '516E7CB8-6ECF-11D6-8FF8-00022D09712B':
return 'ZFS partition', 'FreeBSD'
# Mac OS X
elif guid == '48465300-0000-11AA-AA11-00306543ECAC':
return 'Hierarchical File System Plus (HFS+) partition', 'Mac OS X'
elif guid == '55465300-0000-11AA-AA11-00306543ECAC':
return 'Apple UFS', 'Mac OS X'
elif guid == '6A898CC3-1DD2-11B2-99A6-080020736631':
return 'ZFS / /usr partition', 'Mac OS X / Solaris'
elif guid == '52414944-0000-11AA-AA11-00306543ECAC':
return 'Apple RAID partition', 'Mac OS X'
elif guid == '52414944-5F4F-11AA-AA11-00306543ECAC':
return 'Apple RAID partition, offline', 'Mac OS X'
elif guid == '426F6F74-0000-11AA-AA11-00306543ECAC':
return 'Apple Boot partition', 'Mac OS X'
elif guid == '4C616265-6C00-11AA-AA11-00306543ECAC':
return 'Apple Label', 'Mac OS X'
elif guid == '5265636F-7665-11AA-AA11-00306543ECAC':
return 'Apple TV Recovery partition', 'Mac OS X'
elif guid == '53746F72-6167-11AA-AA11-00306543ECAC':
return 'Apple Core Storage (i.e. Lion FileVault) partition', 'Mac OS X'
# Solaris
elif guid == '6A82CB45-1DD2-11B2-99A6-080020736631':
return 'Boot partition', 'Solaris'
elif guid == '6A85CF4D-1DD2-11B2-99A6-080020736631':
return 'Root partition', 'Solaris'
elif guid == '6A87C46F-1DD2-11B2-99A6-080020736631':
return 'Swap partition', 'Solaris'
elif guid == '6A8B642B-1DD2-11B2-99A6-080020736631':
return 'Backup partition', 'Solaris'
#elif guid == '6A898CC3-1DD2-11B2-99A6-080020736631':
# return '/usr partition', 'Solaris'
elif guid == '6A8EF2E9-1DD2-11B2-99A6-080020736631':
return '/var partition', 'Solaris'
elif guid == '6A90BA39-1DD2-11B2-99A6-080020736631':
return '/home partition', 'Solaris'
elif guid == '6A9283A5-1DD2-11B2-99A6-080020736631':
return 'Alternate sector', 'Solaris'
elif guid == '6A945A3B-1DD2-11B2-99A6-080020736631' or \
guid == '6A9630D1-1DD2-11B2-99A6-080020736631' or \
guid == '6A980767-1DD2-11B2-99A6-080020736631' or \
guid == '6A96237F-1DD2-11B2-99A6-080020736631' or \
guid == '6A8D2AC7-1DD2-11B2-99A6-080020736631':
return 'Reserved partition', 'Solaris'
# NetBSD
elif guid == '49F48D32-B10E-11DC-B99B-0019D1879648':
return 'Swap partition', 'NetBSD'
elif guid == '49F48D5A-B10E-11DC-B99B-0019D1879648':
return 'FFS partition', 'NetBSD'
elif guid == '49F48D82-B10E-11DC-B99B-0019D1879648':
return 'LFS partition', 'NetBSD'
elif guid == '49F48DAA-B10E-11DC-B99B-0019D1879648':
return 'RAID partition', 'NetBSD'
elif guid == '2DB519C4-B10F-11DC-B99B-0019D1879648':
return 'Concatenated partition', 'NetBSD'
elif guid == '2DB519EC-B10F-11DC-B99B-0019D1879648':
return 'Encrypted partition', 'NetBSD'
# Chrome OS
elif guid == 'FE3A2A5D-4F32-41A7-B725-ACCC3285A309':
return 'ChromeOS kernel', 'Chrome OS'
elif guid == '3CB8E202-3B7E-47DD-8A3C-7FF2A13CFCEC':
return 'ChromeOS rootfs', 'Chrome OS'
elif guid == '2E0A753D-9E48-43B0-8337-B15192CB1B5E':
return 'ChromeOS future use', 'Chrome OS'
# VMware ESX
elif guid == 'AA31E02A-400F-11DB-9590-000C2911D1B8':
return 'VMFS partition', 'VMware ESX'
elif guid == '9D275380-40AD-11DB-BF97-000C2911D1B8':
return 'vmkcore crash partition', 'VMware ESX'
# Midnight BSD
elif guid == '85D5E45E-237C-11E1-B4B3-E89A8F7FC3A7':
return 'Boot partition', 'MidnightBSD'
elif guid == '85D5E45A-237C-11E1-B4B3-E89A8F7FC3A7':
return 'Data partition', 'MidnightBSD'
elif guid == '85D5E45B-237C-11E1-B4B3-E89A8F7FC3A7':
return 'Swap partition', 'MidnightBSD'
elif guid == '0394Ef8B-237E-11E1-B4B3-E89A8F7FC3A7':
return 'Unix File System (UFS) partition', 'MidnightBSD'
elif guid == '85D5E45C-237C-11E1-B4B3-E89A8F7FC3A7':
return 'Vinum volume manager partition', 'MidnightBSD'
elif guid == '85D5E45D-237C-11E1-B4B3-E89A8F7FC3A7':
return 'ZFS partition', 'MidnightBSD'
# Qualcomm Boot GPT Partition IDs
elif guid == 'DEA0BA2C-CBDD-4805-B4F9-F428251C3E98':
return 'SBL1 partition', 'Qualcomm'
elif guid == '8C6B52AD-8A9E-4398-AD09-AE916E53AE2D':
return 'SBL2 partition', 'Qualcomm'
elif guid == '05E044DF-92F1-4325-B69E-374A82E97D6E':
return 'SBL3 partition', 'Qualcomm'
elif guid == '400FFDCD-22E0-47E7-9A23-F16ED9382388':
return 'APPSBL partition', 'Qualcomm'
elif guid == 'A053AA7F-40B8-4B1C-BA08-2F68AC71A4F4':
return 'QSEE partition', 'Qualcomm'
elif guid == 'E1A6A689-0C8D-4CC6-B4E8-55A4320FBD8A':
return 'QHEE partition', 'Qualcomm'
elif guid == '098DF793-D712-413D-9D4E-89D711772228':
return 'RPM partition', 'Qualcomm'
elif guid == 'D4E0D938-B7FA-48C1-9D21-BC5ED5C4B203':
return 'WDOG debug partition', 'Qualcomm'
elif guid == '20A0C19C-286A-42FA-9CE7-F64C3226A794':
return 'DDR partition', 'Qualcomm'
elif guid == 'A19F205F-CCD8-4B6D-8F1E-2D9BC24CFFB1':
return 'CDT partition', 'Qualcomm'
elif guid == '66C9B323-F7FC-48B6-BF96-6F32E335A428':
return 'RAM dump partition', 'Qualcomm'
elif guid == '303E6AC3-AF15-4C54-9E9B-D9A8FBECF401':
return 'SEC partition', 'Qualcomm'
elif guid == 'C00EEF24-7709-43D6-9799-DD2B411E7A3C':
return 'PMIC config data partition', 'Qualcomm'
elif guid == '82ACC91F-357C-4A68-9C8F-689E1B1A23A1':
return 'MISC? partition', 'Qualcomm'
elif guid == '10A0C19C-516A-5444-5CE3-664C3226A794':
return 'LIMITS? partition', 'Qualcomm'
elif guid == '65ADDCF4-0C5C-4D9A-AC2D-D90B5CBFCD03':
return 'DEVINFO? partition', 'Qualcomm'
elif guid == 'E6E98DA2-E22A-4D12-AB33-169E7DEAA507':
return 'APDP? partition', 'Qualcomm'
elif guid == 'ED9E8101-05FA-46B7-82AA-8D58770D200B':
return 'MSADP? partition', 'Qualcomm'
elif guid == '11406F35-1173-4869-807B-27DF71802812':
return 'DPO? partition', 'Qualcomm'
elif guid == 'DF24E5ED-8C96-4B86-B00B-79667DC6DE11':
return 'SPARE1? partition', 'Qualcomm'
elif guid == '6C95E238-E343-4BA8-B489-8681ED22AD0B':
return 'PERSIST? partition', 'Qualcomm'
elif guid == 'EBBEADAF-22C9-E33B-8F5D-0E81686A68CB':
return 'MODEMST1 partition', 'Qualcomm'
elif guid == '0A288B1F-22C9-E33B-8F5D-0E81686A68CB':
return 'MODEMST2 partition', 'Qualcomm'
elif guid == 'EBBEADAF-22C9-E33B-8F5D-0E81686A68CB':
return 'MODEMST1 partition', 'Qualcomm'
elif guid == '638FF8E2-22C9-E33B-8F5D-0E81686A68CB':
return 'FSG? partition', 'Qualcomm'
elif guid == '57B90A16-22C9-E33B-8F5D-0E81686A68CB':
return 'FSC? partition', 'Qualcomm'
elif guid == '2C86E742-745E-4FDD-BFD8-B6A7AC638772':
return 'SSD? partition', 'Qualcomm'
elif guid == 'DE7D4029-0F5B-41C8-AE7E-F6C023A02B33':
return 'KEYSTORE? partition', 'Qualcomm'
elif guid == '323EF595-AF7A-4AFA-8060-97BE72841BB9':
return 'ENCRYPT? partition', 'Qualcomm'
elif guid == '45864011-CF89-46E6-A445-85262E065604':
return 'EKSST? partition', 'Qualcomm'
elif guid == '8ED8AE95-597F-4C8A-A5BD-A7FF8E4DFAA9':
return 'RCT partition', 'Qualcomm'
elif guid == '7C29D3AD-78B9-452E-9DEB-D098D542F092':
return 'SPARE2? partition', 'Qualcomm'
elif guid == '9D72D4E4-9958-42DA-AC26-BEA7A90B0434':
return 'RECOVERY? partition', 'Qualcomm'
elif guid == '4627AE27-CFEF-48A1-88FE-99C3509ADE26':
return 'raw_resources? partition', 'Qualcomm'
elif guid == '20117F86-E985-4357-B9EE-374BC1D8487D':
return 'BOOT partition', 'Qualcomm'
elif guid == '379D107E-229E-499D-AD4F-61F5BCF87BD4':
return 'SPARE3? partition', 'Qualcomm'
elif guid == '86A7CB80-84E1-408C-99AB-694F1A410FC7':
return 'FOTA? partition', 'Qualcomm'
elif guid == '0DEA65E5-A676-4CDF-823C-77568B577ED5':
return 'SPARE4? partition', 'Qualcomm'
elif guid == '97D7B011-54DA-4835-B3C4-917AD6E73D74':
return 'SYSTEM? partition', 'Qualcomm'
elif guid == '5594C694-C871-4B5F-90B1-690A6F68E0F7':
return 'CACHE? partition', 'Qualcomm'
elif guid == '1B81E7E6-F50D-419B-A739-2AEEF8DA3335':
return 'USERDATA? partition', 'Qualcomm'
# LG Advanced Flasher Partition
elif guid == '98523EC6-90FE-4C67-B50A-0FC59ED6F56D':
return 'LG Advanced Flasher partition', 'LG'
# else
else:
return 'unknown partition', 'UNKNOWN'
# analysis partition table
def an_part_table(partition_table, gpt_header, fbuf):
md5 = hashlib.md5()
md5.update(fbuf)
md5 = md5.hexdigest()
num_of_part_entry = gpt_header[11]
size_of_part_entry = gpt_header[12]
crc32_of_partition_array = gpt_header[13]
part_list = []
crc32_part_value = unsigned32(zlib.crc32(partition_table))
print '\n\t\t\t<!-- Partition table: -->'
print '\t\t\t\t<!-- MD5: %s -->'%md5
if crc32_part_value == crc32_of_partition_array:
print '\t\t\t\t<!-- CRC32 Check : %.8X (VALID) -->\n'%crc32_part_value
else:
print '\t\t\t\t<!-- WARNING!! CRC32 Check : %.8X (INVALID) -->\n'%crc32_part_value
for part_entry_num in range(0, num_of_part_entry):
part_entry = get_part_entry(partition_table, size_of_part_entry*part_entry_num, size_of_part_entry)
# first LBA, last LBA
if part_entry[2] == 0 or part_entry[3] == 0:
continue
part_list.append(part_entry)
count = 1
for part_entry in part_list:
part_type = check_partition_guid_type(str(uuid.UUID(bytes_le=part_entry[0])).upper())
part_guid = str(uuid.UUID(bytes_le=part_entry[1])).upper()
part_label = unicode(part_entry[5].replace('\0',''))
part_type = str(uuid.UUID(bytes_le=part_entry[0])).upper()
part_type_label = check_partition_guid_type(part_type)
part_bootable = 'false'
part_lba_first = part_entry[2]
part_lba_first_offset = (part_entry[2] * LBA_SIZE)
part_lba_last = part_entry[3]
part_lba_last_offset = (part_entry[3] * LBA_SIZE)
part_size = (((part_lba_last - part_lba_first) + 1) / 2)
print '\t\t\t<!-- #%02d -->' %count
print '\t\t\t<!-- First LBA: %s /' %part_lba_first,
print 'Disk Offset: %s -->' %part_lba_first_offset
print '\t\t\t<!-- Last LBA : %s /' %part_lba_last,
print 'Disk Offset: %s -->' %part_lba_last_offset
print '\t\t\t<!-- %s |' %part_type_label[0],
print '%s -->' %part_type_label[1]
print '\t\t\t<!-- GUID: %s -->' %part_guid
print '\t\t\t<partition',
print 'label="%s"' %part_label,
print 'size_in_kb="%d"' %part_size,
print 'type="%s"'%part_type,
print 'bootable="%s"' %part_bootable,
part_attr_tag = part_entry[4]
if part_attr_tag == 0:
print 'system="true"',
elif part_attr_tag == 60:
print 'readonly="true"',
elif part_attr_tag == 62:
print 'hidden="true"',
elif part_attr_tag == 63:
print 'automount="true"',
part_filename = ''
part_match = part_label
part_list_bak = ['rpm','sdi','hyp','sbl1','tz','pmic','aboot','raw_resources']
part_list_img = ['persist','laf','drm','sns','mpt','eri','system','cache','userdata']
for party in part_list_bak:
if party in part_match:
part_filename = '%s.mbn' %part_match.replace('bak','')
for party in part_list_img:
if party in part_match:
part_filename = '%s.img' %party
if part_match == str('modem'):
part_filename = 'NON-HLOS.bin'
elif part_match == str('DDR'):
part_filename = 'DDR.bin'
elif part_match == str('sec'):
part_filename = 'sec.dat'
elif part_match == 'aboot':
part_filename = 'emmc_appsboot.mbn'
print 'filename="%s"/>\n' %part_filename
count += 1
def usage(argv):
print '%s <DISK IMAGE>'%argv[0]
sys.exit()
def main():
try:
option, args = getopt.getopt(sys.argv[1:], '')
except getopt.GetoptError, err:
usage(sys.argv)
sys.exit()
try:
if len(sys.argv) != 2:
usage(sys.argv)
sys.exit()
except IndexError:
usage()
sys.exit()
try:
f = open(sys.argv[1], 'rb')
except IOError:
print '[+] WARNING!! Can not open disk image.'
#usage(sys.argv)
sys.exit()
fbuf = ''
# Protected MBR
# You can use mbr_parser.py at http://gleeda.blogspot.com/2012/04/mbr-parser.html
# Primary GPT header
gpt_header, crc32_header_value, gpt_buf = get_gpt_header(f, fbuf, PRIMARY_GPT_LBA)
an_gpt_header(gpt_header, crc32_header_value, gpt_buf)
# Partition entries
fbuf = get_part_table_area(f, gpt_header)
an_part_table(fbuf, gpt_header, fbuf)
## backup GPT header
# print ''
# try:
# gpt_header, crc32_header_value, gpt_buf = get_gpt_header(f, fbuf, gpt_header[6])
# an_gpt_header(gpt_header, crc32_header_value, gpt_buf)
# h = hashlib.md5()
# h.update(gpt_buf)
# print '\t\t\t<!-- [+] Backup GPT header md5: %s -->'%h.hexdigest()
# except struct.error:
# print '\t\t\t<!-- [+] WARNING!! Backup GPT header can not found. Check your disk image. -->'
# print '\t\t\t<!-- [+] WARNING!! Backup GPT header offset: 0x%.8X -->'%(gpt_header[6] * LBA_SIZE)
print '\t\t</physical_partition>'
print '\t</configuration>'
f.close()
if __name__ == "__main__":
main()
/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <string.h>
#include "mmc.h"
#include "partition_parser.h"
char *ext3_partitions[] =
{ "system", "userdata", "persist", "cache", "tombstones" };
char *vfat_partitions[] = { "modem", "mdm", "NONE" };
unsigned int ext3_count = 0;
unsigned int vfat_count = 0;
struct partition_entry partition_entries[NUM_PARTITIONS];
unsigned gpt_partitions_exist = 0;
unsigned partition_count = 0;
//TODO: Remove the dependency of mmc in these functions
unsigned int
partition_read_table(struct mmc_boot_host *mmc_host,
struct mmc_boot_card *mmc_card)
{
unsigned int ret;
/* Read MBR of the card */
ret = mmc_boot_read_mbr(mmc_host, mmc_card);
if (ret != MMC_BOOT_E_SUCCESS) {
dprintf(CRITICAL, "MMC Boot: MBR read failed!\n");
return MMC_BOOT_E_FAILURE;
}
/* Read GPT of the card if exist */
if (gpt_partitions_exist) {
ret = mmc_boot_read_gpt(mmc_host, mmc_card);
if (ret != MMC_BOOT_E_SUCCESS) {
dprintf(CRITICAL, "MMC Boot: GPT read failed!\n");
return MMC_BOOT_E_FAILURE;
}
}
return MMC_BOOT_E_SUCCESS;
}
/*
* Read MBR from MMC card and fill partition table.
*/
unsigned int
mmc_boot_read_mbr(struct mmc_boot_host *mmc_host,
struct mmc_boot_card *mmc_card)
{
unsigned char buffer[BLOCK_SIZE];
unsigned int dtype;
unsigned int dfirstsec;
unsigned int EBR_first_sec;
unsigned int EBR_current_sec;
int ret = MMC_BOOT_E_SUCCESS;
int idx, i;
/* Print out the MBR first */
ret = mmc_boot_read_from_card(mmc_host, mmc_card, 0,
BLOCK_SIZE, (unsigned int *)buffer);
if (ret) {
dprintf(CRITICAL, "Could not read partition from mmc\n");
return ret;
}
/* Check to see if signature exists */
ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
if (ret) {
return ret;
}
/*
* Process each of the four partitions in the MBR by reading the table
* information into our mbr table.
*/
partition_count = 0;
idx = TABLE_ENTRY_0;
for (i = 0; i < 4; i++) {
/* Type 0xEE indicates end of MBR and GPT partitions exist */
dtype = buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
if (dtype == MBR_PROTECTED_TYPE) {
gpt_partitions_exist = 1;
return ret;
}
partition_entries[partition_count].dtype = dtype;
partition_entries[partition_count].attribute_flag =
buffer[idx + i * TABLE_ENTRY_SIZE + OFFSET_STATUS];
partition_entries[partition_count].first_lba =
GET_LWORD_FROM_BYTE(&buffer[idx +
i * TABLE_ENTRY_SIZE +
OFFSET_FIRST_SEC]);
partition_entries[partition_count].size =
GET_LWORD_FROM_BYTE(&buffer[idx +
i * TABLE_ENTRY_SIZE +
OFFSET_SIZE]);
dfirstsec = partition_entries[partition_count].first_lba;
mbr_fill_name(&partition_entries[partition_count],
partition_entries[partition_count].dtype);
partition_count++;
if (partition_count == NUM_PARTITIONS)
return ret;
}
/* See if the last partition is EBR, if not, parsing is done */
if (dtype != MBR_EBR_TYPE) {
return ret;
}
EBR_first_sec = dfirstsec;
EBR_current_sec = dfirstsec;
ret = mmc_boot_read_from_card(mmc_host, mmc_card,
(EBR_first_sec * 512),
BLOCK_SIZE, (unsigned int *)buffer);
if (ret) {
return ret;
}
/* Loop to parse the EBR */
for (i = 0;; i++) {
ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
if (ret) {
ret = MMC_BOOT_E_SUCCESS;
break;
}
partition_entries[partition_count].attribute_flag =
buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
partition_entries[partition_count].dtype =
buffer[TABLE_ENTRY_0 + OFFSET_TYPE];
partition_entries[partition_count].first_lba =
GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
OFFSET_FIRST_SEC]) +
EBR_current_sec;
partition_entries[partition_count].size =
GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 + OFFSET_SIZE]);
mbr_fill_name(&(partition_entries[partition_count]),
partition_entries[partition_count].dtype);
partition_count++;
if (partition_count == NUM_PARTITIONS)
return ret;
dfirstsec =
GET_LWORD_FROM_BYTE(&buffer
[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
if (dfirstsec == 0) {
/* Getting to the end of the EBR tables */
break;
}
/* More EBR to follow - read in the next EBR sector */
dprintf(SPEW, "Reading EBR block from 0x%X\n", EBR_first_sec
+ dfirstsec);
ret = mmc_boot_read_from_card(mmc_host, mmc_card,
((EBR_first_sec +
dfirstsec) * 512), BLOCK_SIZE,
(unsigned int *)buffer);
if (ret) {
return ret;
}
EBR_current_sec = EBR_first_sec + dfirstsec;
}
return ret;
}
/*
* Read GPT from MMC and fill partition table
*/
unsigned int
mmc_boot_read_gpt(struct mmc_boot_host *mmc_host,
struct mmc_boot_card *mmc_card)
{
int ret = MMC_BOOT_E_SUCCESS;
unsigned int header_size;
unsigned long long first_usable_lba;
unsigned long long backup_header_lba;
unsigned long long card_size_sec;
unsigned int max_partition_count = 0;
unsigned int partition_entry_size;
unsigned char data[BLOCK_SIZE];
unsigned int i = 0; /* Counter for each 512 block */
unsigned int j = 0; /* Counter for each 128 entry in the 512 block */
unsigned int n = 0; /* Counter for UTF-16 -> 8 conversion */
unsigned char UTF16_name[MAX_GPT_NAME_SIZE];
/* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
unsigned long long partition_0;
partition_count = 0;
/* Print out the GPT first */
ret = mmc_boot_read_from_card(mmc_host, mmc_card,
PROTECTIVE_MBR_SIZE,
BLOCK_SIZE, (unsigned int *)data);
if (ret){
dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
}
ret = partition_parse_gpt_header(data, &first_usable_lba,
&partition_entry_size, &header_size,
&max_partition_count);
if (ret) {
dprintf(INFO, "GPT: (WARNING) Primary signature invalid\n");
/* Check the backup gpt */
/* Get size of MMC */
card_size_sec = (mmc_card->capacity) / BLOCK_SIZE;
ASSERT (card_size_sec > 0);
backup_header_lba = card_size_sec - 1;
ret =
mmc_boot_read_from_card(mmc_host, mmc_card,
(backup_header_lba * BLOCK_SIZE),
BLOCK_SIZE, (unsigned int *)data);
if (ret) {
dprintf(CRITICAL,
"GPT: Could not read backup gpt from mmc\n");
return ret;
}
ret = partition_parse_gpt_header(data, &first_usable_lba,
&partition_entry_size,
&header_size,
&max_partition_count);
if (ret) {
dprintf(CRITICAL,
"GPT: Primary and backup signatures invalid\n");
return ret;
}
}
partition_0 = GET_LLWORD_FROM_BYTE(&data[PARTITION_ENTRIES_OFFSET]);
/* Read GPT Entries */
for (i = 0; i < (max_partition_count / 4); i++) {
ASSERT(partition_count < NUM_PARTITIONS);
ret = mmc_boot_read_from_card(mmc_host, mmc_card,
(partition_0 * BLOCK_SIZE) +
(i * BLOCK_SIZE),
BLOCK_SIZE, (uint32_t *) data);
if (ret) {
dprintf(CRITICAL,
"GPT: mmc read card failed reading partition entries.\n");
return ret;
}
for (j = 0; j < 4; j++) {
memcpy(&(partition_entries[partition_count].type_guid),
&data[(j * partition_entry_size)],
PARTITION_TYPE_GUID_SIZE);
if (partition_entries[partition_count].type_guid[0] ==
0x00
&& partition_entries[partition_count].
type_guid[1] == 0x00) {
i = max_partition_count;
break;
}
memcpy(&
(partition_entries[partition_count].
unique_partition_guid),
&data[(j * partition_entry_size) +
UNIQUE_GUID_OFFSET],
UNIQUE_PARTITION_GUID_SIZE);
partition_entries[partition_count].first_lba =
GET_LLWORD_FROM_BYTE(&data
[(j * partition_entry_size) +
FIRST_LBA_OFFSET]);
partition_entries[partition_count].last_lba =
GET_LLWORD_FROM_BYTE(&data
[(j * partition_entry_size) +
LAST_LBA_OFFSET]);
partition_entries[partition_count].size =
partition_entries[partition_count].last_lba -
partition_entries[partition_count].first_lba + 1;
partition_entries[partition_count].attribute_flag =
GET_LLWORD_FROM_BYTE(&data
[(j * partition_entry_size) +
ATTRIBUTE_FLAG_OFFSET]);
memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
memcpy(UTF16_name, &data[(j * partition_entry_size) +
PARTITION_NAME_OFFSET],
MAX_GPT_NAME_SIZE);
/*
* Currently partition names in *.xml are UTF-8 and lowercase
* Only supporting english for now so removing 2nd byte of UTF-16
*/
for (n = 0; n < MAX_GPT_NAME_SIZE / 2; n++) {
partition_entries[partition_count].name[n] =
UTF16_name[n * 2];
}
partition_count++;
}
}
return ret;
}
static unsigned int write_mbr_in_blocks(unsigned size, unsigned char *mbrImage)
{
unsigned int dtype;
unsigned int dfirstsec;
unsigned int ebrSectorOffset;
unsigned char *ebrImage;
unsigned char *lastAddress;
int idx, i;
unsigned int ret;
/* Write the first block */
ret = mmc_write(0, BLOCK_SIZE, (unsigned int *)mbrImage);
if (ret) {
dprintf(CRITICAL, "Failed to write mbr partition\n");
goto end;
}
dprintf(SPEW, "write of first MBR block ok\n");
/*
Loop through the MBR table to see if there is an EBR.
If found, then figure out where to write the first EBR
*/
idx = TABLE_ENTRY_0;
for (i = 0; i < 4; i++) {
dtype = mbrImage[idx + i * TABLE_ENTRY_SIZE + OFFSET_TYPE];
if (MBR_EBR_TYPE == dtype) {
dprintf(SPEW, "EBR found.\n");
break;
}
}
if (MBR_EBR_TYPE != dtype) {
dprintf(SPEW, "No EBR in this image\n");
goto end;
}
/* EBR exists. Write each EBR block to mmc */
ebrImage = mbrImage + BLOCK_SIZE;
ebrSectorOffset =
GET_LWORD_FROM_BYTE(&mbrImage
[idx + i * TABLE_ENTRY_SIZE +
OFFSET_FIRST_SEC]);
dfirstsec = 0;
dprintf(SPEW, "first EBR to be written at sector 0x%X\n", dfirstsec);
lastAddress = mbrImage + size;
while (ebrImage < lastAddress) {
dprintf(SPEW, "writing to 0x%X\n",
(ebrSectorOffset + dfirstsec) * BLOCK_SIZE);
ret =
mmc_write((ebrSectorOffset + dfirstsec) * BLOCK_SIZE,
BLOCK_SIZE, (unsigned int *)ebrImage);
if (ret) {
dprintf(CRITICAL,
"Failed to write EBR block to sector 0x%X\n",
dfirstsec);
goto end;
}
dfirstsec =
GET_LWORD_FROM_BYTE(&ebrImage
[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
ebrImage += BLOCK_SIZE;
}
dprintf(INFO, "MBR written to mmc successfully\n");
end:
return ret;
}
/* Write the MBR/EBR to the MMC. */
unsigned int
write_mbr(unsigned size, unsigned char *mbrImage,
struct mmc_boot_host *mmc_host, struct mmc_boot_card *mmc_card)
{
unsigned int ret;
/* Verify that passed in block is a valid MBR */
ret = partition_verify_mbr_signature(size, mbrImage);
if (ret) {
goto end;
}
/* Write the MBR/EBR to mmc */
ret = write_mbr_in_blocks(size, mbrImage);
if (ret) {
dprintf(CRITICAL, "Failed to write MBR block to mmc.\n");
goto end;
}
/* Re-read the MBR partition into mbr table */
ret = mmc_boot_read_mbr(mmc_host, mmc_card);
if (ret) {
dprintf(CRITICAL, "Failed to re-read mbr partition.\n");
goto end;
}
partition_dump();
end:
return ret;
}
/*
* A8h reflected is 15h, i.e. 10101000 <--> 00010101
*/
int reflect(int data, int len)
{
int ref = 0;
for (int i = 0; i < len; i++) {
if (data & 0x1) {
ref |= (1 << ((len - 1) - i));
}
data = (data >> 1);
}
return ref;
}
/*
* Function to calculate the CRC32
*/
unsigned int calculate_crc32(unsigned char *buffer, int len)
{
int byte_length = 8; /*length of unit (i.e. byte) */
int msb = 0;
int polynomial = 0x104C11DB7; /* IEEE 32bit polynomial */
unsigned int regs = 0xFFFFFFFF; /* init to all ones */
int regs_mask = 0xFFFFFFFF; /* ensure only 32 bit answer */
int regs_msb = 0;
unsigned int reflected_regs;
for (int i = 0; i < len; i++) {
int data_byte = buffer[i];
data_byte = reflect(data_byte, 8);
for (int j = 0; j < byte_length; j++) {
msb = data_byte >> (byte_length - 1); /* get MSB */
msb &= 1; /* ensure just 1 bit */
regs_msb = (regs >> 31) & 1; /* MSB of regs */
regs = regs << 1; /* shift regs for CRC-CCITT */
if (regs_msb ^ msb) { /* MSB is a 1 */
regs = regs ^ polynomial; /* XOR with generator poly */
}
regs = regs & regs_mask; /* Mask off excess upper bits */
data_byte <<= 1; /* get to next bit */
}
}
regs = regs & regs_mask;
reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;
return reflected_regs;
}
/*
* Write the GPT Partition Entry Array to the MMC.
*/
static unsigned int
write_gpt_partition_array(unsigned char *header,
unsigned int partition_array_start,
unsigned int array_size)
{
unsigned int ret = MMC_BOOT_E_INVAL;
unsigned long long partition_entry_lba;
unsigned long long partition_entry_array_start_location;
partition_entry_lba =
GET_LLWORD_FROM_BYTE(&header[PARTITION_ENTRIES_OFFSET]);
partition_entry_array_start_location = partition_entry_lba * BLOCK_SIZE;
ret = mmc_write(partition_entry_array_start_location, array_size,
(unsigned int *)partition_array_start);
if (ret) {
dprintf(CRITICAL,
"GPT: FAILED to write the partition entry array\n");
goto end;
}
end:
return ret;
}
static void
patch_gpt(unsigned char *gptImage,
struct mmc_boot_card *mmc_card,
unsigned int array_size,
unsigned int max_part_count, unsigned int part_entry_size)
{
unsigned int partition_entry_array_start;
unsigned char *primary_gpt_header;
unsigned char *secondary_gpt_header;
unsigned int offset;
unsigned long long card_size_sec;
int total_part = 0;
unsigned int last_part_offset;
unsigned int crc_value;
/* Get size of MMC */
card_size_sec = (mmc_card->capacity) / 512;
/* Working around cap at 4GB */
if (card_size_sec == 0) {
card_size_sec = 4 * 1024 * 1024 * 2 - 1;
}
/* Patching primary header */
primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
PUT_LONG_LONG(primary_gpt_header + BACKUP_HEADER_OFFSET,
((long long)(card_size_sec - 1)));
PUT_LONG_LONG(primary_gpt_header + LAST_USABLE_LBA_OFFSET,
((long long)(card_size_sec - 34)));
/* Patching backup GPT */
offset = (2 * array_size);
secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
PUT_LONG_LONG(secondary_gpt_header + PRIMARY_HEADER_OFFSET,
((long long)(card_size_sec - 1)));
PUT_LONG_LONG(secondary_gpt_header + LAST_USABLE_LBA_OFFSET,
((long long)(card_size_sec - 34)));
PUT_LONG_LONG(secondary_gpt_header + PARTITION_ENTRIES_OFFSET,
((long long)(card_size_sec - 33)));
/* Find last partition */
while (*(primary_gpt_header + BLOCK_SIZE + total_part * ENTRY_SIZE) !=
0) {
total_part++;
}
/* Patching last partition */
last_part_offset =
(total_part - 1) * ENTRY_SIZE + PARTITION_ENTRY_LAST_LBA;
PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset,
(long long)(card_size_sec - 34));
PUT_LONG_LONG(primary_gpt_header + BLOCK_SIZE + last_part_offset +
array_size, (long long)(card_size_sec - 34));
/* Updating CRC of the Partition entry array in both headers */
partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
crc_value = calculate_crc32(partition_entry_array_start,
max_part_count * part_entry_size);
PUT_LONG(primary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
crc_value = calculate_crc32(partition_entry_array_start + array_size,
max_part_count * part_entry_size);
PUT_LONG(secondary_gpt_header + PARTITION_CRC_OFFSET, crc_value);
/* Clearing CRC fields to calculate */
PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, 0);
crc_value = calculate_crc32(primary_gpt_header, 92);
PUT_LONG(primary_gpt_header + HEADER_CRC_OFFSET, crc_value);
PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, 0);
crc_value = (calculate_crc32(secondary_gpt_header, 92));
PUT_LONG(secondary_gpt_header + HEADER_CRC_OFFSET, crc_value);
}
/*
* Write the GPT to the MMC.
*/
unsigned int
write_gpt(unsigned size, unsigned char *gptImage,
struct mmc_boot_host *mmc_host, struct mmc_boot_card *mmc_card)
{
unsigned int ret = MMC_BOOT_E_INVAL;
unsigned int header_size;
unsigned long long first_usable_lba;
unsigned long long backup_header_lba;
unsigned int max_partition_count = 0;
unsigned int partition_entry_size;
unsigned int partition_entry_array_start;
unsigned char *primary_gpt_header;
unsigned char *secondary_gpt_header;
unsigned int offset;
unsigned int partition_entry_array_size;
unsigned long long primary_header_location; /* address on the emmc card */
unsigned long long secondary_header_location; /* address on the emmc card */
/* Verify that passed block has a valid GPT primary header */
primary_gpt_header = (gptImage + PROTECTIVE_MBR_SIZE);
ret = partition_parse_gpt_header(primary_gpt_header, &first_usable_lba,
&partition_entry_size, &header_size,
&max_partition_count);
if (ret) {
dprintf(CRITICAL,
"GPT: Primary signature invalid cannot write GPT\n");
goto end;
}
/* Verify that passed block has a valid backup GPT HEADER */
partition_entry_array_size = partition_entry_size * max_partition_count;
if (partition_entry_array_size < MIN_PARTITION_ARRAY_SIZE) {
partition_entry_array_size = MIN_PARTITION_ARRAY_SIZE;
}
offset = (2 * partition_entry_array_size);
secondary_gpt_header = offset + BLOCK_SIZE + primary_gpt_header;
ret =
partition_parse_gpt_header(secondary_gpt_header, &first_usable_lba,
&partition_entry_size, &header_size,
&max_partition_count);
if (ret) {
dprintf(CRITICAL,
"GPT: Backup signature invalid cannot write GPT\n");
goto end;
}
/* Patching the primary and the backup header of the GPT table */
patch_gpt(gptImage, mmc_card, partition_entry_array_size,
max_partition_count, partition_entry_size);
/* Erasing the eMMC card before writing */
ret = mmc_erase_card(0x00000000, mmc_card->capacity);
if (ret) {
dprintf(CRITICAL, "Failed to erase the eMMC card\n");
goto end;
}
/* Writing protective MBR */
ret = mmc_write(0, PROTECTIVE_MBR_SIZE, (unsigned int *)gptImage);
if (ret) {
dprintf(CRITICAL, "Failed to write Protective MBR\n");
goto end;
}
/* Writing the primary GPT header */
primary_header_location = PROTECTIVE_MBR_SIZE;
ret = mmc_write(primary_header_location, BLOCK_SIZE,
(unsigned int *)primary_gpt_header);
if (ret) {
dprintf(CRITICAL, "Failed to write GPT header\n");
goto end;
}
/* Writing the backup GPT header */
backup_header_lba = GET_LLWORD_FROM_BYTE
(&primary_gpt_header[BACKUP_HEADER_OFFSET]);
secondary_header_location = backup_header_lba * BLOCK_SIZE;
ret = mmc_write(secondary_header_location, BLOCK_SIZE,
(unsigned int *)secondary_gpt_header);
if (ret) {
dprintf(CRITICAL, "Failed to write GPT backup header\n");
goto end;
}
/* Writing the partition entries array for the primary header */
partition_entry_array_start = primary_gpt_header + BLOCK_SIZE;
ret = write_gpt_partition_array(primary_gpt_header,
partition_entry_array_start,
partition_entry_array_size);
if (ret) {
dprintf(CRITICAL,
"GPT: Could not write GPT Partition entries array\n");
goto end;
}
/*Writing the partition entries array for the backup header */
partition_entry_array_start = primary_gpt_header + BLOCK_SIZE +
partition_entry_array_size;
ret = write_gpt_partition_array(secondary_gpt_header,
partition_entry_array_start,
partition_entry_array_size);
if (ret) {
dprintf(CRITICAL,
"GPT: Could not write GPT Partition entries array\n");
goto end;
}
/* Re-read the GPT partition table */
dprintf(INFO, "Re-reading the GPT Partition Table\n");
ret = mmc_boot_read_gpt(mmc_host, mmc_card);
if (ret) {
dprintf(CRITICAL,
"GPT: Failure to re- read the GPT Partition table\n");
goto end;
}
partition_dump();
dprintf(CRITICAL, "GPT: Partition Table written\n");
memset(primary_gpt_header, 0x00, size);
end:
return ret;
}
unsigned int write_partition(unsigned size, unsigned char *partition)
{
unsigned int ret = MMC_BOOT_E_INVAL;
unsigned int partition_type;
struct mmc_boot_host *mmc_host;
struct mmc_boot_card *mmc_card;
if (partition == 0) {
dprintf(CRITICAL, "NULL partition\n");
goto end;
}
ret = partition_get_type(size, partition, &partition_type);
if (ret != MMC_BOOT_E_SUCCESS) {
goto end;
}
mmc_host = get_mmc_host();
mmc_card = get_mmc_card();
switch (partition_type) {
case PARTITION_TYPE_MBR:
dprintf(INFO, "Writing MBR partition\n");
ret = write_mbr(size, partition, mmc_host, mmc_card);
break;
case PARTITION_TYPE_GPT:
dprintf(INFO, "Writing GPT partition\n");
ret = write_gpt(size, partition, mmc_host, mmc_card);
dprintf(CRITICAL, "Re-Flash all the partitions\n");
break;
default:
dprintf(CRITICAL, "Invalid partition\n");
ret = MMC_BOOT_E_INVAL;
goto end;
}
end:
return ret;
}
/*
* Fill name for android partition found.
*/
static void
mbr_fill_name(struct partition_entry *partition_ent, unsigned int type)
{
switch (type) {
memset(partition_ent->name, 0, MAX_GPT_NAME_SIZE);
case MBR_MODEM_TYPE:
case MBR_MODEM_TYPE2:
/* if already assigned last name available then return */
if (!strcmp((const char *)vfat_partitions[vfat_count], "NONE"))
return;
strlcpy((char *)partition_ent->name,
(const char *)vfat_partitions[vfat_count],
sizeof(partition_ent->name));
vfat_count++;
break;
case MBR_SBL1_TYPE:
memcpy(partition_ent->name, "sbl1", 4);
break;
case MBR_SBL2_TYPE:
memcpy(partition_ent->name, "sbl2", 4);
break;
case MBR_SBL3_TYPE:
memcpy(partition_ent->name, "sbl3", 4);
break;
case MBR_RPM_TYPE:
memcpy(partition_ent->name, "rpm", 3);
break;
case MBR_TZ_TYPE:
memcpy(partition_ent->name, "tz", 2);
break;
case MBR_ABOOT_TYPE:
#if PLATFORM_MSM7X27A
memcpy(partition_ent->name, "FOTA", 4);
#else
memcpy(partition_ent->name, "aboot", 5);
#endif
break;
case MBR_BOOT_TYPE:
memcpy(partition_ent->name, "boot", 4);
break;
case MBR_MODEM_ST1_TYPE:
memcpy(partition_ent->name, "modem_st1", 9);
break;
case MBR_MODEM_ST2_TYPE:
memcpy(partition_ent->name, "modem_st2", 9);
break;
case MBR_EFS2_TYPE:
memcpy(partition_ent->name, "efs2", 4);
break;
case MBR_USERDATA_TYPE:
if (ext3_count == sizeof(ext3_partitions) / sizeof(char *))
return;
strlcpy((char *)partition_ent->name,
(const char *)ext3_partitions[ext3_count],
sizeof(partition_ent->name));
ext3_count++;
break;
case MBR_RECOVERY_TYPE:
memcpy(partition_ent->name, "recovery", 8);
break;
case MBR_MISC_TYPE:
memcpy(partition_ent->name, "misc", 4);
break;
case MBR_SSD_TYPE:
memcpy(partition_ent->name, "ssd", 3);
break;
};
}
/*
* Find index of parition in array of partition entries
*/
unsigned partition_get_index(const char *name)
{
unsigned int input_string_length = strlen(name);
unsigned n;
if( partition_count >= NUM_PARTITIONS)
{
return INVALID_PTN;
}
for (n = 0; n < partition_count; n++) {
if (!memcmp
(name, &partition_entries[n].name, input_string_length)
&& input_string_length ==
strlen((const char *)&partition_entries[n].name)) {
return n;
}
}
return INVALID_PTN;
}
/* Get size of the partition */
unsigned long long partition_get_size(int index)
{
if (index == INVALID_PTN)
return 0;
else {
return partition_entries[index].size * BLOCK_SIZE;
}
}
/* Get offset of the partition */
unsigned long long partition_get_offset(int index)
{
if (index == INVALID_PTN)
return 0;
else {
return partition_entries[index].first_lba * BLOCK_SIZE;
}
}
/* Debug: Print all parsed partitions */
void partition_dump()
{
unsigned i = 0;
for (i = 0; i < partition_count; i++) {
dprintf(SPEW,
"ptn[%d]:Name[%s] Size[%llu] Type[%u] First[%llu] Last[%llu]\n",
i, partition_entries[i].name, partition_entries[i].size,
partition_entries[i].dtype,
partition_entries[i].first_lba,
partition_entries[i].last_lba);
}
}
unsigned int
partition_verify_mbr_signature(unsigned size, unsigned char *buffer)
{
/* Avoid checking past end of buffer */
if ((TABLE_SIGNATURE + 1) > size) {
return MMC_BOOT_E_FAILURE;
}
/* Check to see if signature exists */
if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) ||
(buffer[TABLE_SIGNATURE + 1] != MMC_MBR_SIGNATURE_BYTE_1)) {
dprintf(CRITICAL, "MBR signature does not match.\n");
return MMC_BOOT_E_FAILURE;
}
return MMC_BOOT_E_SUCCESS;
}
unsigned int
mbr_partition_get_type(unsigned size, unsigned char *partition,
unsigned int *partition_type)
{
unsigned int type_offset = TABLE_ENTRY_0 + OFFSET_TYPE;
if (size < type_offset) {
goto end;
}
*partition_type = partition[type_offset];
end:
return MMC_BOOT_E_SUCCESS;
}
unsigned int
partition_get_type(unsigned size, unsigned char *partition,
unsigned int *partition_type)
{
unsigned int ret = MMC_BOOT_E_SUCCESS;
/*
* If the block contains the MBR signature, then it's likely either
* MBR or MBR with protective type (GPT). If the MBR signature is
* not there, then it could be the GPT backup.
*/
/* First check the MBR signature */
ret = partition_verify_mbr_signature(size, partition);
if (ret == MMC_BOOT_E_SUCCESS) {
unsigned int mbr_partition_type = PARTITION_TYPE_MBR;
/* MBR signature verified. This could be MBR, MBR + EBR, or GPT */
ret =
mbr_partition_get_type(size, partition,
&mbr_partition_type);
if (ret != MMC_BOOT_E_SUCCESS) {
dprintf(CRITICAL, "Cannot get TYPE of partition");
} else if (MBR_PROTECTED_TYPE == mbr_partition_type) {
*partition_type = PARTITION_TYPE_GPT;
} else {
*partition_type = PARTITION_TYPE_MBR;
}
} else {
/*
* This could be the GPT backup. Make that assumption for now.
* Anybody who treats the block as GPT backup should check the
* signature.
*/
*partition_type = PARTITION_TYPE_GPT_BACKUP;
}
return ret;
}
/*
* Parse the gpt header and get the required header fields
* Return 0 on valid signature
*/
unsigned int
partition_parse_gpt_header(unsigned char *buffer,
unsigned long long *first_usable_lba,
unsigned int *partition_entry_size,
unsigned int *header_size,
unsigned int *max_partition_count)
{
/* Check GPT Signature */
if (((uint32_t *) buffer)[0] != GPT_SIGNATURE_2 ||
((uint32_t *) buffer)[1] != GPT_SIGNATURE_1)
return 1;
*header_size = GET_LWORD_FROM_BYTE(&buffer[HEADER_SIZE_OFFSET]);
*first_usable_lba =
GET_LLWORD_FROM_BYTE(&buffer[FIRST_USABLE_LBA_OFFSET]);
*max_partition_count =
GET_LWORD_FROM_BYTE(&buffer[PARTITION_COUNT_OFFSET]);
*partition_entry_size =
GET_LWORD_FROM_BYTE(&buffer[PENTRY_SIZE_OFFSET]);
return 0;
}
@YangHuiDef
Copy link

how do i use it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment