mmc/gpt: Adding support to read backup gpt

Adding support to read backup gpt when the primary gpt has
invalid gpt signature.

Change-Id: I09a8df341a19dfe64011876c30a5c9b53e28f541
CRs-Fixed: 305776
diff --git a/platform/msm_shared/partition_parser.c b/platform/msm_shared/partition_parser.c
index 23d4778..621aa90 100644
--- a/platform/msm_shared/partition_parser.c
+++ b/platform/msm_shared/partition_parser.c
@@ -206,13 +206,16 @@
     int ret = MMC_BOOT_E_SUCCESS;
     unsigned int header_size;
     unsigned long long first_usable_lba;
-    unsigned int max_partition_count;
+    unsigned long long backup_header_lba;
+    unsigned int max_partition_count = 0;
     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];
+    /* LBA of first partition -- 1 Block after Protected MBR + 1 for PT */
+    unsigned long long partition_0 = 2;
 
     /* Print out the GPT first */
     ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
@@ -220,25 +223,46 @@
                                    MMC_BOOT_RD_BLOCK_LEN, \
                                    (unsigned int *)data);
 
-    /* Check GPT Signature */
-    if( ((uint32_t *)data)[0] != GPT_SIGNATURE_2 ||
-        ((uint32_t *)data)[1] != GPT_SIGNATURE_1 )
-    {
-        dprintf(CRITICAL,  "GPT: signature does not match.\n" );
-        return MMC_BOOT_E_FAILURE;
-    }
+    if (ret)
+        dprintf(CRITICAL, "GPT: Could not read primary gpt from mmc\n");
 
-    header_size = GET_LWORD_FROM_BYTE(&data[HEADER_SIZE_OFFSET]);
-    first_usable_lba = GET_LLWORD_FROM_BYTE(&data[FIRST_USABLE_LBA_OFFSET]);
-    max_partition_count = GET_LWORD_FROM_BYTE(&data[PARTITION_COUNT_OFFSET]);
-    partition_entry_size = GET_LWORD_FROM_BYTE(&data[PENTRY_SIZE_OFFSET]);
+    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 */
+        backup_header_lba = GET_LLWORD_FROM_BYTE(&data[BACKUP_HEADER_OFFSET]);
+        ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
+                                       (backup_header_lba * BLOCK_SIZE), \
+                                       MMC_BOOT_RD_BLOCK_LEN, \
+                                       (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 = backup_header_lba - (max_partition_count / 4);
+    }
 
     /* Read GPT Entries */
     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 +
+                                       (partition_0 * BLOCK_SIZE) +
                                        (i * MMC_BOOT_RD_BLOCK_LEN),
                                        MMC_BOOT_RD_BLOCK_LEN,
                                        (uint32_t *)data);
@@ -486,3 +510,26 @@
     }
     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 long * partition_entry_size,
+                                        unsigned long * 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;
+}