[U-Boot] [PATCH v4 2/2] fastboot: handle flash write to GPT partitions

Lukasz Majewski l.majewski at samsung.com
Mon Jan 26 12:14:30 CET 2015


Hi Rob,

> On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae <srae at broadcom.com> 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 <srae at broadcom.com>
> > ---
> >
> > 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 <l.majewski at samsung.com>)
> >
> > Changes in v2:
> > add validation of the GPT before writing to flash
> > (suggested by: Lukasz Majewski <l.majewski at samsung.com>)
> >
> >  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 <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;
> > 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


More information about the U-Boot mailing list