GPT: Enable partition table to be flashed using fastboot command.

The partition table can be flashed using the command "fastboot flash partition
<name of the file>". Code detects the GPT partition table and flashes it
to the eMMC card.

Change-Id: I93c9a204ba0a7c0328a9cfd30331ea6cbe7d5df4
diff --git a/platform/msm_shared/include/mmc.h b/platform/msm_shared/include/mmc.h
index bba854a..33dc336 100644
--- a/platform/msm_shared/include/mmc.h
+++ b/platform/msm_shared/include/mmc.h
@@ -535,15 +535,6 @@
 

 #define GET_PAR_NUM_FROM_POS(x) (((x & 0x0000FF00) >> 8) + (x & 0x000000FF))

 

-/* Some useful define used to access the MBR/EBR table */

-#define BLOCK_SIZE                0x200

-#define TABLE_ENTRY_0             0x1BE

-#define TABLE_ENTRY_1             0x1CE

-#define TABLE_ENTRY_2             0x1DE

-#define TABLE_ENTRY_3             0x1EE

-#define TABLE_SIGNATURE           0x1FE

-#define TABLE_ENTRY_SIZE          0x010

-

 #define OFFSET_STATUS             0x00

 #define OFFSET_TYPE               0x04

 #define OFFSET_FIRST_SEC          0x08

@@ -554,8 +545,6 @@
 

 #define MMC_RCA 2

 

-extern unsigned gpt_partitions_exist;

-

 /* Can be used to unpack array of upto 32 bits data */

 #define UNPACK_BITS(array, start, len, size_of)                               \

     ({                                                             \

@@ -612,11 +601,11 @@
                                      unsigned int data_len,

                                      unsigned int *in );

 

-unsigned int mmc_write_partition (unsigned size, unsigned char *partition);

-unsigned int mmc_write_mbr_in_blocks(unsigned size, unsigned char *mbrImage);

-unsigned int mmc_write_mbr(unsigned size, unsigned char *mbrImage);

-unsigned int mmc_erase_card(unsigned long long data_addr,

-                              unsigned long long data_len);

-

+
+unsigned int mmc_erase_card(unsigned long long data_addr,
+                            unsigned long long data_len);
+
+struct mmc_boot_host* get_mmc_host( void );

+struct mmc_boot_card* get_mmc_card( void );
 #endif

 

diff --git a/platform/msm_shared/include/partition_parser.h b/platform/msm_shared/include/partition_parser.h
index 057f4ce..6df3902 100644
--- a/platform/msm_shared/include/partition_parser.h
+++ b/platform/msm_shared/include/partition_parser.h
@@ -43,6 +43,7 @@
 #define PROTECTIVE_MBR_SIZE       BLOCK_SIZE
 #define HEADER_SIZE_OFFSET        12
 #define HEADER_CRC_OFFSET         16
+#define PRIMARY_HEADER_OFFSET     24
 #define BACKUP_HEADER_OFFSET      32
 #define FIRST_USABLE_LBA_OFFSET   40
 #define LAST_USABLE_LBA_OFFSET    48
@@ -51,6 +52,8 @@
 #define PENTRY_SIZE_OFFSET        84
 #define PARTITION_CRC_OFFSET      88
 
+#define MIN_PARTITION_ARRAY_SIZE  0x4000
+
 #define PARTITION_ENTRY_LAST_LBA  40
 
 #define ENTRY_SIZE              0x080
@@ -112,6 +115,25 @@
         ((unsigned long long)*(x+6) << 48) | \
         ((unsigned long long)*(x+7) << 56))
 
+#define GET_LONG(x)    ((uint32_t)*(x) | \
+            ((uint32_t)*(x+1) << 8) | \
+            ((uint32_t)*(x+2) << 16) | \
+            ((uint32_t)*(x+3) << 24))
+
+#define PUT_LONG(x, y)   *(x) = y & 0xff;     \
+    *(x+1) = (y >> 8) & 0xff;     \
+    *(x+2) = (y >> 16) & 0xff;    \
+    *(x+3) = (y >> 24) & 0xff;
+
+#define PUT_LONG_LONG(x,y)    *(x) =(y) & 0xff; \
+     *((x)+1) = (((y) >> 8) & 0xff);    \
+     *((x)+2) = (((y) >> 16) & 0xff);   \
+     *((x)+3) = (((y) >> 24) & 0xff);   \
+     *((x)+4) = (((y) >> 32) & 0xff);   \
+     *((x)+5) = (((y) >> 40) & 0xff);   \
+     *((x)+6) = (((y) >> 48) & 0xff);   \
+     *((x)+7) = (((y) >> 56) & 0xff);
+
 /* Unified mbr and gpt entry types */
 struct partition_entry
 {
@@ -145,5 +167,15 @@
                                         unsigned int * partition_entry_size,
                                         unsigned int * header_size,
                                         unsigned int * max_partition_count);
+
+unsigned int write_mbr(unsigned size, unsigned char *mbrImage,
+                       struct mmc_boot_host *mmc_host,
+                       struct mmc_boot_card *mmc_card);
+unsigned int write_gpt(unsigned size, unsigned char *gptImage,
+                       struct mmc_boot_host *mmc_host,
+                       struct mmc_boot_card *mmc_card);
+unsigned int write_partition(unsigned size, unsigned char* partition);
+
+
 /* For Debugging */
 void partition_dump(void);
diff --git a/platform/msm_shared/mmc.c b/platform/msm_shared/mmc.c
index 6ca37d2..8836933 100644
--- a/platform/msm_shared/mmc.c
+++ b/platform/msm_shared/mmc.c
@@ -33,7 +33,7 @@
 #include "mmc.h"

 #include <partition_parser.h>

 #include <platform/iomap.h>

-#include <platform/timer.h>
+#include <platform/timer.h>

 

 #if MMC_BOOT_ADM

 #include "adm.h"

@@ -2266,146 +2266,10 @@
     return val;

 }

 
-
-
-
-unsigned int mmc_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, MMC_BOOT_RD_BLOCK_LEN, (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 + MMC_BOOT_RD_BLOCK_LEN;
-    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) * MMC_BOOT_RD_BLOCK_LEN);
-        ret = mmc_write((ebrSectorOffset + dfirstsec) * MMC_BOOT_RD_BLOCK_LEN,
-                        MMC_BOOT_RD_BLOCK_LEN, (unsigned int *) ebrImage);
-        if (ret)
-        {
-            dprintf(CRITICAL, "Failed to write EBR block to sector 0x%X", dfirstsec);
-            goto end;
-        }
-        dfirstsec = GET_LWORD_FROM_BYTE(&ebrImage[TABLE_ENTRY_1 + OFFSET_FIRST_SEC]);
-        ebrImage += MMC_BOOT_RD_BLOCK_LEN;
-    }
-    dprintf(INFO, "MBR written to mmc successfully");
-end:
-    return ret;
-}
-
-
-
-/* Write the MBR/EBR to the MMC. */
-unsigned int mmc_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 = mmc_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;
-}
-
-unsigned int mmc_write_partition(unsigned size, unsigned char* partition)
-{
-    unsigned int ret = MMC_BOOT_E_INVAL;
-    unsigned int partition_type;
-
-    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;
-    }
-    switch (partition_type)
-    {
-        case PARTITION_TYPE_MBR:
-            dprintf(INFO, "Writing MBR partition\n");
-            ret = mmc_write_mbr(size, partition);
-            break;
-        case PARTITION_TYPE_GPT:
-            dprintf(INFO, "Writing GPT partition\n");
-            dprintf(CRITICAL, "Flash of GPT not implemented\n");
-            ret = MMC_BOOT_E_INVAL;
-            break;
-        case PARTITION_TYPE_GPT_BACKUP:
-            dprintf(INFO, "Writing GPT backup partition\n");
-            dprintf(CRITICAL, "Flash of GPT backup not implemented\n");
-            ret = MMC_BOOT_E_INVAL;
-            break;
-        default:
-            dprintf(CRITICAL, "Invalid partition\n");
-            ret = MMC_BOOT_E_INVAL;
-            goto end;
-    }
-end:
-    return ret;
-}
-
 /*

  * MMC read function

  */

+

 unsigned int mmc_read (unsigned long long data_addr, unsigned int* out, unsigned int data_len)

 {

     int val = 0;

@@ -2649,8 +2513,7 @@
     memset(wp_status_buf, 0, 8);

 

     rc = mmc_boot_read_reg(card, 8, CMD31_SEND_WRITE_PROT_TYPE, sector,
-		(unsigned int *) wp_status_buf);

-

+                           (unsigned int *) wp_status_buf);

     return rc;

 }

 

@@ -2852,6 +2715,7 @@
     } while(1);

     return mmc_ret;

 }

+
 

 /*

  * CMD35_ERASE_GROUP_START

@@ -3024,7 +2888,7 @@
 

     if(size % erase_grp_size)

     {

-          dprintf(CRITICAL, "Overflow beyond ERASE_GROUP_SIZE:%llu \n",

+          dprintf(CRITICAL, "Overflow beyond ERASE_GROUP_SIZE:%llu\n",

                          (size % erase_grp_size));

 

     }

@@ -3063,5 +2927,15 @@
     }

     dprintf(SPEW, "ERASE SUCCESSFULLY COMPLETED\n");

     return MMC_BOOT_E_SUCCESS;

+}
+
+struct mmc_boot_host* get_mmc_host ( void )

+{

+    return &mmc_host;

+}

+

+struct mmc_boot_card* get_mmc_card( void )

+{

+    return &mmc_card;

 }

 

diff --git a/platform/msm_shared/partition_parser.c b/platform/msm_shared/partition_parser.c
index e99d2ee..e131185 100644
--- a/platform/msm_shared/partition_parser.c
+++ b/platform/msm_shared/partition_parser.c
@@ -72,7 +72,7 @@
 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 char buffer[BLOCK_SIZE];
     unsigned int dtype;
     unsigned int dfirstsec;
     unsigned int EBR_first_sec;
@@ -81,17 +81,17 @@
     int idx, i;
 
     /* Print out the MBR first */
-    ret = mmc_boot_read_from_card( mmc_host, mmc_card, 0, \
-                                   MMC_BOOT_RD_BLOCK_LEN,   \
+    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");
+        dprintf(CRITICAL, "Could not read partition from mmc\n");
         return ret;
     }
 
     /* Check to see if signature exists */
-    ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
+    ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
     if (ret)
     {
        return ret;
@@ -112,18 +112,18 @@
             return ret;
         }
         partition_entries[partition_count].dtype = dtype;
-        partition_entries[partition_count].attribute_flag = \
+        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 + \
+        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 + \
+        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],  \
+        mbr_fill_name(&partition_entries[partition_count],
                       partition_entries[partition_count].dtype);
         partition_count++;
         if (partition_count == NUM_PARTITIONS)
@@ -139,9 +139,9 @@
     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, \
+    ret = mmc_boot_read_from_card( mmc_host, mmc_card,
+                                   (EBR_first_sec * 512),
+                                   BLOCK_SIZE,
                                    (unsigned int *)buffer);
     if (ret)
     {
@@ -150,24 +150,24 @@
     /* Loop to parse the EBR */
     for (i = 0;; i++)
     {
-        ret = partition_verify_mbr_signature(MMC_BOOT_RD_BLOCK_LEN, buffer);
+        ret = partition_verify_mbr_signature(BLOCK_SIZE, buffer);
         if (ret)
         {
            ret = MMC_BOOT_E_SUCCESS;
            break;
         }
-        partition_entries[partition_count].attribute_flag = \
+        partition_entries[partition_count].attribute_flag =
                     buffer[TABLE_ENTRY_0 + OFFSET_STATUS];
-        partition_entries[partition_count].dtype   = \
+        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])    + \
+        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 + \
+        partition_entries[partition_count].size =
+                    GET_LWORD_FROM_BYTE(&buffer[TABLE_ENTRY_0 +
                                         OFFSET_SIZE]);
-        mbr_fill_name(&(partition_entries[partition_count]), \
+        mbr_fill_name(&(partition_entries[partition_count]),
                       partition_entries[partition_count].dtype);
         partition_count++;
         if (partition_count == NUM_PARTITIONS)
@@ -183,9 +183,9 @@
         /* 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, \
+        ret = mmc_boot_read_from_card( mmc_host, mmc_card,
+                                       ((EBR_first_sec + dfirstsec) * 512),
+                                       BLOCK_SIZE,
                                        (unsigned int *)buffer);
         if (ret)
         {
@@ -209,36 +209,35 @@
     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 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 = 2;
+    partition_count = 0;
 
     /* Print out the GPT first */
-    ret = mmc_boot_read_from_card( mmc_host, mmc_card, \
-                                   PROTECTIVE_MBR_SIZE, \
-                                   MMC_BOOT_RD_BLOCK_LEN, \
+    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 */
         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, \
+        ret = mmc_boot_read_from_card( mmc_host, mmc_card,
+                                       (backup_header_lba * BLOCK_SIZE),
+                                       BLOCK_SIZE,
                                        (unsigned int *)data);
 
         if (ret)
@@ -263,8 +262,8 @@
     {
         ret = mmc_boot_read_from_card( mmc_host, mmc_card,
                                        (partition_0 * BLOCK_SIZE) +
-                                       (i * MMC_BOOT_RD_BLOCK_LEN),
-                                       MMC_BOOT_RD_BLOCK_LEN,
+                                       (i * BLOCK_SIZE),
+                                       BLOCK_SIZE,
                                        (uint32_t *)data);
 
         if (ret)
@@ -315,10 +314,432 @@
             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.
  */
@@ -409,7 +830,7 @@
     if (index == INVALID_PTN)
         return 0;
     else{
-        return partition_entries[index].size * MMC_BOOT_RD_BLOCK_LEN;
+        return partition_entries[index].size * BLOCK_SIZE;
     }
 }
 
@@ -419,7 +840,7 @@
     if (index == INVALID_PTN)
         return 0;
     else{
-        return partition_entries[index].first_lba * MMC_BOOT_RD_BLOCK_LEN;
+        return partition_entries[index].first_lba * BLOCK_SIZE;
     }
 }
 
@@ -445,10 +866,10 @@
         return MMC_BOOT_E_FAILURE;
     }
     /* Check to see if signature exists */
-    if ((buffer[TABLE_SIGNATURE] != MMC_MBR_SIGNATURE_BYTE_0) || \
+    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" );
+        dprintf(CRITICAL,  "MBR signature does not match.\n" );
         return MMC_BOOT_E_FAILURE;
     }
     return MMC_BOOT_E_SUCCESS;
@@ -524,8 +945,8 @@
                                         unsigned int * max_partition_count)
 {
     /* Check GPT Signature */
-    if( ((uint32_t *)buffer)[0] != GPT_SIGNATURE_2 ||
-        ((uint32_t *)buffer)[1] != GPT_SIGNATURE_1 )
+    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]);