From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lukasz Majewski Date: Mon, 26 Jan 2015 12:14:30 +0100 Subject: [U-Boot] [PATCH v4 2/2] fastboot: handle flash write to GPT partitions In-Reply-To: References: <1418428314-9611-1-git-send-email-srae@broadcom.com> <1418428314-9611-2-git-send-email-srae@broadcom.com> Message-ID: <20150126121430.364ccbaf@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 Rob, > On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae wrote: > > 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. > > I've been looking at how to do the same thing here. This is an area > that suffers from each vendor doing whatever they want. Using vendor > download/flash tools here is painful. They are all different because > that is where the value add is. ;) What tool do you use on the host > side to create the image? I have seen some vendor code to do it, or > you could use parted plus a disk file and extract the partition table > from it. I find either method a bit fragile and non-standard IMHO. > > The 2 options I've come up with are 1) enable USB MS and use whatever > host side tool you like or 2) use the existing "gpt write" command in > u-boot and tie that into fastboot "oem format" command. The advantage > and disadvantage of the latter is that it hides the partitioning > details in u-boot from the user, but requires changing the u-boot env > to change partition layout. The partitioning requirements are pretty > SOC specific it seems. > > I'm not saying we can't support both, but having some standardization > here would be good. On Exynos4/5 it is possible to use both. One can use mass storage (UMS) and also gpt write. Moreover, there is the dfu (which is slow but standardized) support in u-boot, which seems SoC vendor agnostic. One can use dfu-util tools on host side too. I can share one way to update GPT by using dfu with 'gpt write' u-boot command. 1. It is possible to extract default variables when u-boot is build: { # Generate params.bin cp `find . -name "env_common.o"` copy_env_common.o objcopy -O binary --only-section=.rodata.default_environment `find . -name "copy_env_common.o"` tr '\0' '\n' < copy_env_common.o > default_envs.txt mkenvimage -s 16384 -o params.bin default_envs.txt rm copy_env_common.o default_envs.txt } 2. Store params.bin in a known location (the location is soc dependent). 3. Reset board and execute 'gpt write mmc 0 $partitions' to default $partitions from params.bin This works on Exynos. Another option would be to add special alt setting for dfu - GPT and MBR which would accept binary partition layout and store them to proper location. > > Rob > > > > > Signed-off-by: Steve Rae > > --- > > > > Changes in v4: > > fix bug with partition_entry_lba in Backup GPT > > use common static functions > > > > 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 | 93 > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > include/part.h | 20 +++++++++++++ 4 files changed, 145 > > 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..6ea3938 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(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; > > diff --git a/disk/part_efi.c b/disk/part_efi.c > > index 2c77f29..338010e 100644 > > --- a/disk/part_efi.c > > +++ b/disk/part_efi.c > > @@ -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 > > > > /* > > diff --git a/include/part.h b/include/part.h > > index a496a4a..8ea9b30 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 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 */ > > -- > > 1.8.5 > > > > _______________________________________________ > > U-Boot mailing list > > U-Boot at lists.denx.de > > http://lists.denx.de/mailman/listinfo/u-boot -- Best regards, Lukasz Majewski Samsung R&D Institute Poland (SRPOL) | Linux Platform Group