diff mbox

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

Message ID 1418428314-9611-2-git-send-email-srae@broadcom.com
State Accepted
Delegated to: Łukasz Majewski
Headers show

Commit Message

Steve Rae Dec. 12, 2014, 11:51 p.m. UTC
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>
---

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@samsung.com>)

Changes in v2:
add validation of the GPT before writing to flash
(suggested by: Lukasz Majewski <l.majewski@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(-)

Comments

Łukasz Majewski Dec. 16, 2014, 2:17 p.m. UTC | #1
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 <srae@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@samsung.com>)
> 
> Changes in v2:
> add validation of the GPT before writing to flash
> (suggested by: Lukasz Majewski <l.majewski@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 */

Acked-by: Lukasz Majewski <l.majewski@samsung.com>
Tested-by: Lukasz Majewski <l.majewski@samsung.com>
Test HW: Exynos4412 - trats2

To Marek:

This patch cleanly applies to master
(SHA1:b9206e61f3d87535ac4f4b0b858e674fd1edfeaf) not u-boot-usb.

Therefore I cannot apply it to u-boot-usb based -dfu tree.
We can either wait up the moment when -dfu get in sync with mainline or
apply this patch to mainline directly.
Rob Herring Jan. 23, 2015, 5:38 p.m. UTC | #2
On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae <srae@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.

Rob

>
> Signed-off-by: Steve Rae <srae@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@samsung.com>)
>
> Changes in v2:
> add validation of the GPT before writing to flash
> (suggested by: Lukasz Majewski <l.majewski@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@lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot
Tom Rini Jan. 23, 2015, 7:57 p.m. UTC | #3
On Fri, Jan 23, 2015 at 11:38:04AM -0600, Rob Herring wrote:
> On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae <srae@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.

Option two seems "good" from a not firewalling off the details point of
view which means that there'll be a subset that wants to go with one
anyhow.
Steve Rae Jan. 23, 2015, 10:40 p.m. UTC | #4
On 15-01-23 09:38 AM, Rob Herring wrote:
> On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae <srae@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.
>
We use an internal tool -- however, I also note that ALL of the source 
code for our tool is "GPL-2.0+" (expect for one file which is Public Domain)
Is U-Boot (Denx) interested in supporting a "host tool"?

> 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.
>
We also have code which creates the GPT tables from a "fastboot oem 
format" command, and (if I understand correctly) we have code that 
implements a "gpt" command line, which creates the GPT tables from env 
variables...
If there is interest here, I could investigate further.

> I'm not saying we can't support both, but having some standardization
> here would be good.
>
> Rob
>
I wasn't trying to promote an exclusive solution with this patch (which 
has been accepted - Thanks!). I was just trying to have an incremental 
change to the existing "fastboot flash" command (to handle the GPT Tables).

Thanks, Steve

[... snip ...]
Łukasz Majewski Jan. 26, 2015, 11:14 a.m. UTC | #5
Hi Rob,

> On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae <srae@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@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@samsung.com>)
> >
> > Changes in v2:
> > add validation of the GPT before writing to flash
> > (suggested by: Lukasz Majewski <l.majewski@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@lists.denx.de
> > http://lists.denx.de/mailman/listinfo/u-boot
Rob Herring Jan. 26, 2015, 2:52 p.m. UTC | #6
On Fri, Jan 23, 2015 at 4:40 PM, Steve Rae <srae@broadcom.com> wrote:
>
>
> On 15-01-23 09:38 AM, Rob Herring wrote:
>>
>> On Fri, Dec 12, 2014 at 5:51 PM, Steve Rae <srae@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.
>>
> We use an internal tool -- however, I also note that ALL of the source code
> for our tool is "GPL-2.0+" (expect for one file which is Public Domain)
> Is U-Boot (Denx) interested in supporting a "host tool"?
>
>> 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.
>>
> We also have code which creates the GPT tables from a "fastboot oem format"
> command, and (if I understand correctly) we have code that implements a
> "gpt" command line, which creates the GPT tables from env variables...
> If there is interest here, I could investigate further.

I have patches I'm working on to do this. I hope to get them sent out soon.

Rob
diff mbox

Patch

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 */