-
-
Save kenkit/fd95e8b328d1c0f6b52f809c14acddfb to your computer and use it in GitHub Desktop.
Feed this your GPT.bin, and out it shoots a partition.xml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# Author : n0fate | |
# E-Mail [email protected], [email protected] | |
# | |
# 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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment