From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lukasz Majewski Date: Thu, 11 Dec 2014 11:12:21 +0100 Subject: [U-Boot] [PATCH v3] fastboot: handle flash write to GPT partitions In-Reply-To: <1418262002-14194-1-git-send-email-srae@broadcom.com> References: <1418262002-14194-1-git-send-email-srae@broadcom.com> Message-ID: <20141211111221.77c3ba63@amdc2363> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de Hi Steve, > 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 > --- > > Changes in v3: > - prefer leXX_to_cpu() over cpu_to_leXX() > - enhance calculation of pointer to GPT Entries > - prepare and write the Backup GPT > (requested by: Lukasz Majewski ) > > Changes in v2: > add validation of the GPT before writing to flash > (suggested by: Lukasz Majewski ) > > README | 9 +++++ > common/fb_mmc.c | 26 ++++++++++++-- > disk/part_efi.c | 107 > ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > include/part.h | 20 +++++++++++ 4 files changed, 159 insertions(+), > 3 deletions(-) > > diff --git a/README b/README > index 4ca04d0..42ece99 100644 > --- 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 > diff --git a/common/fb_mmc.c b/common/fb_mmc.c > index fb06d8a..5acc8df 100644 > --- a/common/fb_mmc.c > +++ b/common/fb_mmc.c > @@ -4,12 +4,17 @@ > * SPDX-License-Identifier: GPL-2.0+ > */ > > +#include > #include > #include > #include > #include > #include > > +#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(download_buffer, > dev_desc->blksz)) { > + 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; > diff --git a/disk/part_efi.c b/disk/part_efi.c > index efed58f..9cc04da 100644 > --- a/disk/part_efi.c > +++ b/disk/part_efi.c > @@ -455,6 +455,113 @@ err: > free(gpt_h); > return ret; > } > + > +int is_valid_gpt_buf(void *buf, unsigned long blksz) Please see my comment to v2 regarding this function. > +{ > + int rc = 0; > + gpt_header *gpt_h; > + gpt_entry *gpt_e; > + gpt_header gpt_hdr; > + uint32_t calc_crc32; > + > + /* GPT Header starts at "LBA[1]" in the buffer */ > + gpt_h = buf + blksz; > + if (le64_to_cpu(gpt_h->signature) != GPT_HEADER_SIGNATURE) { > + printf("%s: 'signature' is invalid\n", __func__); > + return -1; > + } > + > + memcpy(&gpt_hdr, gpt_h, sizeof(gpt_header)); > + gpt_hdr.header_crc32 = 0; > + calc_crc32 = efi_crc32((const unsigned char *)&gpt_hdr, > + le32_to_cpu(gpt_h->header_size)); > + if (le32_to_cpu(gpt_h->header_crc32) != calc_crc32) { > + printf("%s: 'header_crc32' is invalid\n", __func__); > + rc += 1; > + } > + > + /* determine start of GPT Entries in the buffer */ > + gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) * > blksz); > + calc_crc32 = efi_crc32((const unsigned char *)gpt_e, > + > le32_to_cpu(gpt_h->num_partition_entries) * > + > le32_to_cpu(gpt_h->sizeof_partition_entry)); > + if (le32_to_cpu(gpt_h->partition_entry_array_crc32) != > calc_crc32) { > + printf("%s: 'partition_entry_array_crc32' is > invalid\n", > + __func__); > + rc += 1; > + } > + return rc; > +} > + > +int write_mbr_and_gpt_partitions(block_dev_desc_t *dev_desc, void > *buf) +{ I think that this function is redundant since in part_efi.c is already defined "write_gpt_table()" function. It shouldn't be difficult to overlay gpt_header and gpt_entry pointers on the buf. > + gpt_header *gpt_h; > + gpt_entry *gpt_e; > + int gpt_e_blk_cnt; > + uint32_t calc_crc32; > + uint64_t val; > + lbaint_t lba; > + int cnt; > + > + if (is_valid_gpt_buf(buf, dev_desc->blksz)) > + return -1; > + > + /* GPT Header starts at "LBA[1]" in the buffer */ > + gpt_h = buf + 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 plus Primary GPT */ > + lba = 0; /* MBR is always at 0 */ > + cnt = 2; /* MBR + GPT Header (2 blocks) */ > + 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 + 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; > + } > + > + /* recalculate the values for the Backup GPT Header */ > + 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->header_crc32 = 0; > + > + calc_crc32 = efi_crc32((const unsigned char *)gpt_h, > + le32_to_cpu(gpt_h->header_size)); > + gpt_h->header_crc32 = cpu_to_le32(calc_crc32); > + > + /* write Backup GPT */ > + lba = le64_to_cpu(gpt_h->last_usable_lba) + 1; > + 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 > > /* > diff --git a/include/part.h b/include/part.h > index a496a4a..fee1c2d 100644 > --- a/include/part.h > +++ b/include/part.h > @@ -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 buf - buffer which contains the MBR and Primary GPT info > + * @param blksz - block size (in bytes) > + * > + * @return - '0' on success, otherwise error > + */ > +int is_valid_gpt_buf(void *buf, unsigned long blksz); > + > +/** > + * 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 */ -- Best regards, Lukasz Majewski Samsung R&D Institute Poland (SRPOL) | Linux Platform Group