fastboot: handle flash write to GPT partitions
authorSteve Rae <srae@broadcom.com>
Fri, 12 Dec 2014 23:51:54 +0000 (15:51 -0800)
committerLukasz Majewski <l.majewski@samsung.com>
Thu, 18 Dec 2014 11:26:06 +0000 (12:26 +0100)
Implement a feature to allow fastboot to write the downloaded image
to the space reserved for the Protective MBR and the Primary GUID
Partition Table.
Additionally, prepare and write the Backup GUID Partition Table.

Signed-off-by: Steve Rae <srae@broadcom.com>
Tested-by: Lukasz Majewski <l.majewski@samsung.com>
[Test HW: Exynos4412 - Trats2]

README
common/fb_mmc.c
disk/part_efi.c
include/part.h

diff --git a/README b/README
index 4ca04d0489ed3dcd3f04f403cc527f633746f1c2..42ece994739cd4f56f39e32861d57c78503bc3bc 100644 (file)
--- a/README
+++ b/README
@@ -1773,6 +1773,15 @@ The following options need to be configured:
                regarding the non-volatile storage device. Define this to
                the eMMC device that fastboot should use to store the image.
 
+               CONFIG_FASTBOOT_GPT_NAME
+               The fastboot "flash" command supports writing the downloaded
+               image to the Protective MBR and the Primary GUID Partition
+               Table. (Additionally, this downloaded image is post-processed
+               to generate and write the Backup GUID Partition Table.)
+               This occurs when the specified "partition name" on the
+               "fastboot flash" command line matches this value.
+               Default is GPT_ENTRY_NAME (currently "gpt") if undefined.
+
 - Journaling Flash filesystem support:
                CONFIG_JFFS2_NAND, CONFIG_JFFS2_NAND_OFF, CONFIG_JFFS2_NAND_SIZE,
                CONFIG_JFFS2_NAND_DEV
index fb06d8a557fb9bc34f4452b537f93f11624ebf4f..6ea3938d83f29467feb874c8156a200b4641b2a7 100644 (file)
@@ -4,12 +4,17 @@
  * SPDX-License-Identifier:    GPL-2.0+
  */
 
+#include <config.h>
 #include <common.h>
 #include <fb_mmc.h>
 #include <part.h>
 #include <aboot.h>
 #include <sparse_format.h>
 
+#ifndef CONFIG_FASTBOOT_GPT_NAME
+#define CONFIG_FASTBOOT_GPT_NAME GPT_ENTRY_NAME
+#endif
+
 /* The 64 defined bytes plus the '\0' */
 #define RESPONSE_LEN   (64 + 1)
 
@@ -62,7 +67,6 @@ static void write_raw_image(block_dev_desc_t *dev_desc, disk_partition_t *info,
 void fb_mmc_flash_write(const char *cmd, void *download_buffer,
                        unsigned int download_bytes, char *response)
 {
-       int ret;
        block_dev_desc_t *dev_desc;
        disk_partition_t info;
 
@@ -76,8 +80,24 @@ void fb_mmc_flash_write(const char *cmd, void *download_buffer,
                return;
        }
 
-       ret = get_partition_info_efi_by_name(dev_desc, cmd, &info);
-       if (ret) {
+       if (strcmp(cmd, CONFIG_FASTBOOT_GPT_NAME) == 0) {
+               printf("%s: updating MBR, Primary and Backup GPT(s)\n",
+                      __func__);
+               if (is_valid_gpt_buf(dev_desc, download_buffer)) {
+                       printf("%s: invalid GPT - refusing to write to flash\n",
+                              __func__);
+                       fastboot_fail("invalid GPT partition");
+                       return;
+               }
+               if (write_mbr_and_gpt_partitions(dev_desc, download_buffer)) {
+                       printf("%s: writing GPT partitions failed\n", __func__);
+                       fastboot_fail("writing GPT partitions failed");
+                       return;
+               }
+               printf("........ success\n");
+               fastboot_okay("");
+               return;
+       } else if (get_partition_info_efi_by_name(dev_desc, cmd, &info)) {
                error("cannot find partition: '%s'\n", cmd);
                fastboot_fail("cannot find partition");
                return;
index 2c77f29d4546d3a74caeab314ca919f538437b0a..338010e148e24c5f2eecc1c0097529e5bd9d878b 100644 (file)
@@ -161,6 +161,8 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
        val = le64_to_cpu(gpt_h->my_lba);
        gpt_h->my_lba = gpt_h->alternate_lba;
        gpt_h->alternate_lba = cpu_to_le64(val);
+       gpt_h->partition_entry_lba =
+                       cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1);
        gpt_h->header_crc32 = 0;
 
        calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
@@ -545,6 +547,97 @@ err:
        free(gpt_h);
        return ret;
 }
+
+int is_valid_gpt_buf(block_dev_desc_t *dev_desc, void *buf)
+{
+       gpt_header *gpt_h;
+       gpt_entry *gpt_e;
+
+       /* determine start of GPT Header in the buffer */
+       gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
+                      dev_desc->blksz);
+       if (validate_gpt_header(gpt_h, GPT_PRIMARY_PARTITION_TABLE_LBA,
+                               dev_desc->lba))
+               return -1;
+
+       /* determine start of GPT Entries in the buffer */
+       gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
+                      dev_desc->blksz);
+       if (validate_gpt_entries(gpt_h, gpt_e))
+               return -1;
+
+       return 0;
+}
+
+int write_mbr_and_gpt_partitions(block_dev_desc_t *dev_desc, void *buf)
+{
+       gpt_header *gpt_h;
+       gpt_entry *gpt_e;
+       int gpt_e_blk_cnt;
+       lbaint_t lba;
+       int cnt;
+
+       if (is_valid_gpt_buf(dev_desc, buf))
+               return -1;
+
+       /* determine start of GPT Header in the buffer */
+       gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
+                      dev_desc->blksz);
+
+       /* determine start of GPT Entries in the buffer */
+       gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
+                      dev_desc->blksz);
+       gpt_e_blk_cnt = BLOCK_CNT((le32_to_cpu(gpt_h->num_partition_entries) *
+                                  le32_to_cpu(gpt_h->sizeof_partition_entry)),
+                                 dev_desc);
+
+       /* write MBR */
+       lba = 0;        /* MBR is always at 0 */
+       cnt = 1;        /* MBR (1 block) */
+       if (dev_desc->block_write(dev_desc->dev, lba, cnt, buf) != cnt) {
+               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+                      __func__, "MBR", cnt, lba);
+               return 1;
+       }
+
+       /* write Primary GPT */
+       lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
+       cnt = 1;        /* GPT Header (1 block) */
+       if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_h) != cnt) {
+               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+                      __func__, "Primary GPT Header", cnt, lba);
+               return 1;
+       }
+
+       lba = le64_to_cpu(gpt_h->partition_entry_lba);
+       cnt = gpt_e_blk_cnt;
+       if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_e) != cnt) {
+               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+                      __func__, "Primary GPT Entries", cnt, lba);
+               return 1;
+       }
+
+       prepare_backup_gpt_header(gpt_h);
+
+       /* write Backup GPT */
+       lba = le64_to_cpu(gpt_h->partition_entry_lba);
+       cnt = gpt_e_blk_cnt;
+       if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_e) != cnt) {
+               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+                      __func__, "Backup GPT Entries", cnt, lba);
+               return 1;
+       }
+
+       lba = le64_to_cpu(gpt_h->my_lba);
+       cnt = 1;        /* GPT Header (1 block) */
+       if (dev_desc->block_write(dev_desc->dev, lba, cnt, gpt_h) != cnt) {
+               printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
+                      __func__, "Backup GPT Header", cnt, lba);
+               return 1;
+       }
+
+       return 0;
+}
 #endif
 
 /*
index a496a4ad4a9061012939a513f1f5298207b5dbba..8ea9b3049a4989daa02fa06dda99f3f00232f47b 100644 (file)
@@ -244,6 +244,26 @@ int gpt_fill_header(block_dev_desc_t *dev_desc, gpt_header *gpt_h,
  */
 int gpt_restore(block_dev_desc_t *dev_desc, char *str_disk_guid,
                disk_partition_t *partitions, const int parts_count);
+
+/**
+ * is_valid_gpt_buf() - Ensure that the Primary GPT information is valid
+ *
+ * @param dev_desc - block device descriptor
+ * @param buf - buffer which contains the MBR and Primary GPT info
+ *
+ * @return - '0' on success, otherwise error
+ */
+int is_valid_gpt_buf(block_dev_desc_t *dev_desc, void *buf);
+
+/**
+ * write_mbr_and_gpt_partitions() - write MBR, Primary GPT and Backup GPT
+ *
+ * @param dev_desc - block device descriptor
+ * @param buf - buffer which contains the MBR and Primary GPT info
+ *
+ * @return - '0' on success, otherwise error
+ */
+int write_mbr_and_gpt_partitions(block_dev_desc_t *dev_desc, void *buf);
 #endif
 
 #endif /* _PART_H */