/* Copyright (c) 2011-2013, The Linux Foundation. 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 The Linux Foundation. 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 #include #include "mmc.h" #include "partition_parser.h" static uint32_t mmc_boot_read_gpt(); static uint32_t mmc_boot_read_mbr(); static void mbr_fill_name(struct partition_entry *partition_ent, uint32_t type); static uint32_t partition_verify_mbr_signature(uint32_t size, uint8_t *buffer); static uint32_t mbr_partition_get_type(uint32_t size, uint8_t *partition, uint32_t *partition_type); static uint32_t partition_get_type(uint32_t size, uint8_t *partition, uint32_t *partition_type); static uint32_t partition_parse_gpt_header(uint8_t *buffer, uint64_t *first_usable_lba, uint32_t *partition_entry_size, uint32_t *header_size, uint32_t *max_partition_count); static uint32_t write_mbr(uint32_t, uint8_t *mbrImage); static uint32_t write_gpt(uint32_t size, uint8_t *gptImage); 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; unsigned int partition_read_table() { unsigned int ret; /* Read MBR of the card */ ret = mmc_boot_read_mbr(); if (ret) { dprintf(CRITICAL, "MMC Boot: MBR read failed!\n"); return 1; } /* Read GPT of the card if exist */ if (gpt_partitions_exist) { ret = mmc_boot_read_gpt(); if (ret) { dprintf(CRITICAL, "MMC Boot: GPT read failed!\n"); return 1; } } return 0; } /* * Read MBR from MMC card and fill partition table. */ static unsigned int mmc_boot_read_mbr() { BUF_DMA_ALIGN(buffer, BLOCK_SIZE); unsigned int dtype; unsigned int dfirstsec; unsigned int EBR_first_sec; unsigned int EBR_current_sec; int ret = 0; int idx, i; /* Print out the MBR first */ ret = mmc_read(0, (unsigned int *)buffer, BLOCK_SIZE); 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_read((EBR_first_sec * 512), (unsigned int *)buffer, BLOCK_SIZE); if (ret) return ret; /* Loop to parse the EBR */ for (i = 0;; i++) { ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer); if (ret) { ret = 0; 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_read(((EBR_first_sec + dfirstsec) * 512),(unsigned int *)buffer, BLOCK_SIZE); if (ret) return ret; EBR_current_sec = EBR_first_sec + dfirstsec; } return ret; } /* * Read GPT from MMC and fill partition table */ static unsigned int mmc_boot_read_gpt() { BUF_DMA_ALIGN(data, BLOCK_SIZE); int ret = 0; 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 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; uint64_t device_density; partition_count = 0; /* Get the density of the mmc device */ device_density = mmc_get_device_capacity(); /* Print out the GPT first */ ret = mmc_read(PROTECTIVE_MBR_SIZE, (unsigned int *)data, BLOCK_SIZE); 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 = (device_density) / BLOCK_SIZE; ASSERT (card_size_sec > 0); backup_header_lba = card_size_sec - 1; ret = mmc_read((backup_header_lba * BLOCK_SIZE), (unsigned int *)data, BLOCK_SIZE); 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 < (ROUNDUP(max_partition_count, 4)) / 4; i++) { ASSERT(partition_count < NUM_PARTITIONS); ret = mmc_read((partition_0 * BLOCK_SIZE) + (i * BLOCK_SIZE), (uint32_t *) data, BLOCK_SIZE); 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 = ROUNDUP(max_partition_count, 4); 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. */ static unsigned int write_mbr(unsigned size, unsigned char *mbrImage) { 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(); 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 = 1; 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, uint64_t density, 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 = (density) / 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. */ static unsigned int write_gpt(unsigned size, unsigned char *gptImage) { unsigned int ret = 1; 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 */ uint64_t device_density; /* 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; } /* Get the density of the mmc device */ device_density = mmc_get_device_capacity(); /* 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, device_density, partition_entry_array_size, max_partition_count, partition_entry_size); /* Erasing the eMMC card before writing */ ret = mmc_erase_card(0x00000000, device_density); 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(); 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 = 1; unsigned int partition_type; if (partition == 0) { dprintf(CRITICAL, "NULL partition\n"); goto end; } ret = partition_get_type(size, partition, &partition_type); if (ret) goto end; switch (partition_type) { case PARTITION_TYPE_MBR: dprintf(INFO, "Writing MBR partition\n"); ret = write_mbr(size, partition); break; case PARTITION_TYPE_GPT: dprintf(INFO, "Writing GPT partition\n"); ret = write_gpt(size, partition); dprintf(CRITICAL, "Re-Flash all the partitions\n"); break; default: dprintf(CRITICAL, "Invalid partition\n"); ret = 1; 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 */ int 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); } } static unsigned int partition_verify_mbr_signature(unsigned size, unsigned char *buffer) { /* Avoid checking past end of buffer */ if ((TABLE_SIGNATURE + 1) > size) { return 1; } /* 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 1; } return 0; } static 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 0; } static unsigned int partition_get_type(unsigned size, unsigned char *partition, unsigned int *partition_type) { unsigned int ret = 0; /* * 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) { 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) { 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 */ static 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; }