mmc: Cleanup mmc code and unify mbr and gpt
Move mbr code to partition parser and use a common
struct for both partition table types. Moving partition
related functions and defines to partition_parser from
mmc.
Change-Id: I9726b5a79817f98f86a7932a081c0aba311e3836
diff --git a/platform/msm_shared/partition_parser.c b/platform/msm_shared/partition_parser.c
index 1f68e4b..23d4778 100644
--- a/platform/msm_shared/partition_parser.c
+++ b/platform/msm_shared/partition_parser.c
@@ -31,32 +31,194 @@
#include "mmc.h"
#include "partition_parser.h"
-static struct gpt_entry gpt[NUM_GPT_PARTITIONS];
-static uint32_t gpt_partition_count = 0;
+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[MMC_BOOT_RD_BLOCK_LEN];
+ 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, \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)buffer);
+ if (ret)
+ {
+ dprintf(CRITICAL, "Could not read partition from mmc");
+ return ret;
+ }
+
+ /* Check to see if signature exists */
+ ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, 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), \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)buffer);
+ if (ret)
+ {
+ return ret;
+ }
+ /* Loop to parse the EBR */
+ for (i = 0;; i++)
+ {
+ ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, 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), \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)buffer);
+ if (ret)
+ {
+ return ret;
+ }
+ EBR_current_sec = EBR_first_sec + dfirstsec;
+ }
+ return ret;
+}
/*
* Read GPT from MMC and fill partition table
*/
-uint32_t mmc_boot_read_gpt(struct mmc_boot_host * mmc_host,
- struct mmc_boot_card * mmc_card){
+unsigned int mmc_boot_read_gpt( struct mmc_boot_host * mmc_host,
+ struct mmc_boot_card * mmc_card)
+{
- int32_t ret = MMC_BOOT_E_SUCCESS;
- uint32_t header_size = 0;
- //uint32_t header_crc = 0;
- uint64_t first_usable_lba = 0;
- uint64_t last_usable_lba = 0;
- uint32_t partition_count = 0;
- uint32_t partition_entry_size = 0;
- //uint32_t partition_array_crc;
- uint8_t data[MMC_BOOT_RD_BLOCK_LEN];
- uint32_t i = 0; /* Counter for each 512 block */
- uint32_t j = 0; /* Counter for each 128 entry in the 512 block */
+ int ret = MMC_BOOT_E_SUCCESS;
+ unsigned int header_size;
+ unsigned long long first_usable_lba;
+ unsigned int max_partition_count;
+ unsigned int partition_entry_size;
+ unsigned char data[MMC_BOOT_RD_BLOCK_LEN];
+ 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];
/* Print out the GPT first */
- ret = mmc_boot_read_from_card( mmc_host, mmc_card,
- PROTECTIVE_MBR_SIZE,
- MMC_BOOT_RD_BLOCK_LEN,
- (uint32_t *)data);
+ ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
+ PROTECTIVE_MBR_SIZE, \
+ MMC_BOOT_RD_BLOCK_LEN, \
+ (unsigned int *)data);
/* Check GPT Signature */
if( ((uint32_t *)data)[0] != GPT_SIGNATURE_2 ||
@@ -67,75 +229,260 @@
}
header_size = GET_LWORD_FROM_BYTE(&data[HEADER_SIZE_OFFSET]);
- //header_crc = GET_LWORD_FROM_BYTE(&data[HEADER_CRC_OFFSET]);
first_usable_lba = GET_LLWORD_FROM_BYTE(&data[FIRST_USABLE_LBA_OFFSET]);
- last_usable_lba = GET_LLWORD_FROM_BYTE(&data[LAST_USABLE_LBA_OFFSET]);
- partition_count = GET_LWORD_FROM_BYTE(&data[PARTITION_COUNT_OFFSET]);
+ max_partition_count = GET_LWORD_FROM_BYTE(&data[PARTITION_COUNT_OFFSET]);
partition_entry_size = GET_LWORD_FROM_BYTE(&data[PENTRY_SIZE_OFFSET]);
/* Read GPT Entries */
- for(i = 0; i < (partition_count/4); i++)
+ for(i = 0; i < (max_partition_count/4); i++)
{
ret = mmc_boot_read_from_card( mmc_host, mmc_card,
- PROTECTIVE_MBR_SIZE + PARTITION_TABLE_SIZE +
+ PROTECTIVE_MBR_SIZE +
+ PARTITION_TABLE_SIZE +
(i * MMC_BOOT_RD_BLOCK_LEN),
MMC_BOOT_RD_BLOCK_LEN,
(uint32_t *)data);
if (ret)
{
- dprintf(CRITICAL, "GPT: mmc read card failed reading partition entries.\n" );
+ dprintf(CRITICAL,
+ "GPT: mmc read card failed reading partition entries.\n" );
return ret;
}
for(j=0; j < 4; j++)
{
- memcpy(&(gpt[j+(i*4)].partition_type_guid),
- &data[(j * partition_entry_size)], PARTITION_TYPE_GUID_SIZE);
-
- if (gpt[j+(i*4)].partition_type_guid[0] == 0x00 &&
- gpt[j+(i*4)].partition_type_guid[1] == 0x00)
+ 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 = partition_count;
+ i = max_partition_count;
break;
}
- gpt_partition_count++;
+ 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;
+ partition_entries[partition_count].attribute_flag =
+ GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
+ ATTRIBUTE_FLAG_OFFSET]);
- memcpy(&(gpt[j+(i*4)].unique_partition_guid),
- &data[(j * partition_entry_size) + UNIQUE_GUID_OFFSET], UNIQUE_PARTITION_GUID_SIZE);
- gpt[j+(i*4)].first_lba = GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
- FIRST_LBA_OFFSET]);
- gpt[j+(i*4)].last_lba = GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
- LAST_LBA_OFFSET]);
- gpt[j+(i*4)].attribute_flag = GET_LLWORD_FROM_BYTE(&data[(j * partition_entry_size) +
- ATTRIBUTE_FLAG_OFFSET]);
- memcpy(&(gpt[j+(i*4)].partition_name),
- &data[(j * partition_entry_size) + PARTITION_NAME_OFFSET], MAX_GPT_NAME_SIZE);
+ 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;
}
-uint64_t gpt_lookup(uint8_t * name, unsigned type){
- uint32_t input_string_length = strlen(name);
- uint8_t UTF16_name[MAX_GPT_NAME_SIZE];
+/*
+ * 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;
+ strcpy((char *)partition_ent->name,
+ (const char *)vfat_partitions[vfat_count]);
+ 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:
+ memcpy(partition_ent->name,"aboot",5);
+ 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;
+ strcpy((char *)partition_ent->name,
+ (const char *)ext3_partitions[ext3_count]);
+ 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;
+ };
+}
+
+/*
+ * 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;
- memset(&UTF16_name, 0x00, MAX_GPT_NAME_SIZE);
- /* Currently partition names in partition.xml are UTF-8 and lowercase */
- for(n = 0; n < input_string_length && n < MAX_GPT_NAME_SIZE/2; n++){
- UTF16_name[n*2] = name[n];
- UTF16_name[n*2+1] = 0x00;
- }
- for(n = 0; n < gpt_partition_count; n++){
- if(!memcmp(&UTF16_name, &gpt[n].partition_name, MAX_GPT_NAME_SIZE)){
- if(type == PTN_SIZE)
- return ((uint64_t)(gpt[n].last_lba - gpt[n].first_lba) * MMC_BOOT_RD_BLOCK_LEN);
- else if(type == PTN_OFFSET)
- return ((uint64_t)gpt[n].first_lba * MMC_BOOT_RD_BLOCK_LEN);
- else
- return 0;
+ 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 0;
+ 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 * MMC_BOOT_RD_BLOCK_LEN;
+ }
+}
+
+/* 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 * MMC_BOOT_RD_BLOCK_LEN;
+ }
+}
+
+/* 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;
}