[U-Boot] [RFC PATCH v2 0/8] GPT over MTD

I have a request to support GPT over MTD to be able to have dynamic MTD informations without U-Boot environment(CONFIG_ENV_IS_NOWHERE is a other requirement of my project).
The idea is to use the GPT header to save partitioning information directly in flash device (NOR or NAND), then the MTD variables are rebuild from these GPT partitions and can be used by DISTRO to search bootable binary.
I make a first prototyping for this request but I want ask you if this feature is acceptable for U-Boot and if this patches, after some update and cleanups, would be merged in U-Boot mainline. Do you see already some blocking points ?
- added code is under a new CONFIG : CONFIG_EFI_PARTITION_MTD - for implementation details, see doc/README.gpt.mtd
TODO: - full support for modified command today I limit the support for the command used by DISTRO macro: + gpt write + part list - DISTRO macro update for automatic boot on GPT bootable partition found in MTD devices
the current level is tested manually on sandbox with :
make O=sandbox sandbox/u-boot -d sandbox/arch/sandbox/dts/test.dtb
=> sf probe SF: Detected M25P16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB
=> setenv nor_part "name=part1,size=64KiB;name=part2,size=128KiB;\ name=boot,type=linux,bootable,size=512KiB" => gpt write nor 0 $nor_part Writing GPT: success!
=> part list nor 0 Part Start LBA End LBA Name Attributes Type GUID Partition GUID 1 0x00000080 0x000000ff "part1" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 type: data guid: d117f98e-6f2c-0040-00b2-331a19f91cb2 2 0x00000100 0x000001ff "part2" attrs: 0x0000000000000000 type: ebd0a0a2-b9e5-4433-87c0-68b6b72699c7 type: data guid: 25718777-d0ad-0000-8060-02cb591c9737 3 0x00000200 0x000005ff "boot" attrs: 0x0000000000000004 type: 0fc63daf-8483-4772-8e79-3d69d8477de4 type: linux guid: 8a4bb8b4-e304-0040-0036-aff5c9c495b1
=> setenv mtdids "nor0=nor0" => setenv mtdparts "mtdparts=" => mtdparts gpt nor0 => mtdparts device nor0 <nor0>, # parts = 3 #: name size offset mask_flags 0: part1 0x00010000 0x00010000 0 1: part2 0x00020000 0x00020000 0 2: boot 0x00080000 0x00040000 0
active partition: nor0,0 - (part1) 0x00010000 @ 0x00010000
defaults: mtdids : none mtdparts: none
=> part list nor 0 -bootable nor_boot_part => printenv nor_boot_part nor_boot_part=3
test filtering feature (can be used to mask some partitions to linux according the GUID) 1/ only add MTD for some guid = linux 2/ then add MTD for some guid = data
=> mtdparts delall => setenv mtdparts "mtdparts=" => setenv mtdids "nor0=nor0" => mtdparts gpt nor0 linux => mtdparts
device nor0 <nor0>, # parts = 1 #: name size offset mask_flags 0: boot 0x00080000 0x00040000 0
active partition: nor0,0 - (boot) 0x00080000 @ 0x00040000
defaults: mtdids : none mtdparts: none
=> mtdparts gpt nor0 data => mtdparts
device nor0 <nor0>, # parts = 3 #: name size offset mask_flags 0: part1 0x00010000 0x00010000 0 1: part2 0x00020000 0x00020000 0 2: boot 0x00080000 0x00040000 0
active partition: nor0,2 - (boot) 0x00080000 @ 0x00040000
defaults: mtdids : none mtdparts: none
Changes in v2: - split serie to reduce patches size (seperate disk part and cmd impact and add precursor patch) - split large function
Patrick Delaunay (8): uuid: add function for GUID string parsing disk: part: refactor to prepare GPT over MTD disk: part: add support of GPT partitioning over MTD cmd: gpt: update command to support GPT over MTD cmd: part: update command to support GPT over MTD cmd: mtdparts: update command to support GPT over MTD uuid: remove dependency with io.h sandbox: GPT over MTD test
Kconfig | 12 + cmd/gpt.c | 98 ++++++-- cmd/mtdparts.c | 121 +++++++++- cmd/part.c | 48 +++- configs/sandbox_defconfig | 2 + disk/part_efi.c | 560 +++++++++++++++++++++++++++++++++++++++++----- doc/README.gpt.mtd | 189 ++++++++++++++++ include/configs/sandbox.h | 7 + include/part.h | 13 +- include/uuid.h | 1 + lib/uuid.c | 46 +++- 11 files changed, 1011 insertions(+), 86 deletions(-) create mode 100644 doc/README.gpt.mtd

Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: - split serie to reduce patches size (seperate disk part and cmd impact and add precursor patch) - split large function
include/uuid.h | 1 + lib/uuid.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
diff --git a/include/uuid.h b/include/uuid.h index c3f423f..f444095 100644 --- a/include/uuid.h +++ b/include/uuid.h @@ -40,6 +40,7 @@ void uuid_bin_to_str(unsigned char *uuid_bin, char *uuid_str, int str_format); int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin); int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str); #endif +int uuid_guid_parse_str(const char *str, char *guid_str); void gen_rand_uuid(unsigned char *uuid_bin); void gen_rand_uuid_str(char *uuid_str, int str_format); #endif diff --git a/lib/uuid.c b/lib/uuid.c index c8584ed..eb8d8eb 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -136,6 +136,39 @@ int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str) #endif
/* + * uuid_guid_parse_str() - this function parse string for GUID. + * + * @param guid_str - pointer to string with partition type guid [37B] + * or GUID shorcut + * @param guid_str - pointer to allocated partition type string [37B] + */ +int uuid_guid_parse_str(const char *str, char *guid_str) +{ +#ifdef CONFIG_PARTITION_TYPE_GUID + int i; +#endif + + if (guid_str == NULL) + return -ENODEV; + + if (uuid_str_valid(str)) { + memcpy(guid_str, str, UUID_STR_LEN + 1); + return 0; + } + +#ifdef CONFIG_PARTITION_TYPE_GUID + for (i = 0; i < ARRAY_SIZE(list_guid); i++) { + if (!strcmp(list_guid[i].string, str)) { + uuid_bin_to_str((unsigned char *)list_guid[i].guid.b, + guid_str, UUID_STR_FORMAT_GUID); + return 0; + } + } +#endif + return -ENODEV; +} + +/* * uuid_str_to_bin() - convert string UUID or GUID to big endian binary data. * * @param uuid_str - pointer to UUID or GUID string [37B] or GUID shorcut

Hi Patrick,
On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2:
- split serie to reduce patches size (seperate disk part and cmd impact and add precursor patch)
- split large function
include/uuid.h | 1 + lib/uuid.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
Nit below
diff --git a/include/uuid.h b/include/uuid.h index c3f423f..f444095 100644 --- a/include/uuid.h +++ b/include/uuid.h @@ -40,6 +40,7 @@ void uuid_bin_to_str(unsigned char *uuid_bin, char *uuid_str, int str_format); int uuid_guid_get_bin(const char *guid_str, unsigned char *guid_bin); int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str); #endif +int uuid_guid_parse_str(const char *str, char *guid_str); void gen_rand_uuid(unsigned char *uuid_bin); void gen_rand_uuid_str(char *uuid_str, int str_format); #endif diff --git a/lib/uuid.c b/lib/uuid.c index c8584ed..eb8d8eb 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -136,6 +136,39 @@ int uuid_guid_get_str(unsigned char *guid_bin, char *guid_str) #endif
/*
- uuid_guid_parse_str() - this function parse string for GUID.
parses?
What exactly does it do to parse it? i.e. what is the purpose of this function?
- @param guid_str - pointer to string with partition type guid [37B]
or GUID shorcut
- @param guid_str - pointer to allocated partition type string [37B]
Which one is the input param and which is the output. These comments are a bit unclear.
- */
@return ...(document return value)
+int uuid_guid_parse_str(const char *str, char *guid_str) +{ +#ifdef CONFIG_PARTITION_TYPE_GUID
int i;
+#endif
if (guid_str == NULL)
return -ENODEV;
if (uuid_str_valid(str)) {
memcpy(guid_str, str, UUID_STR_LEN + 1);
return 0;
}
+#ifdef CONFIG_PARTITION_TYPE_GUID
for (i = 0; i < ARRAY_SIZE(list_guid); i++) {
if (!strcmp(list_guid[i].string, str)) {
uuid_bin_to_str((unsigned char *)list_guid[i].guid.b,
guid_str, UUID_STR_FORMAT_GUID);
return 0;
}
}
+#endif
return -ENODEV;
+}
+/*
- uuid_str_to_bin() - convert string UUID or GUID to big endian binary data.
- @param uuid_str - pointer to UUID or GUID string [37B] or GUID shorcut
-- 1.9.1
Regards, Simon

From: Patrick Delaunay patrick.delaunay@st.com
- udpate prepare_backup_gpt_header(): calculate partition_entry_lba and no more assumed last lba + 1
- split part_print_efi : create sub-functions part_print_gpt() part_get_disk_info()
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
disk/part_efi.c | 115 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 50 deletions(-)
diff --git a/disk/part_efi.c b/disk/part_efi.c index 1924338..a23c8ea 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -10,6 +10,7 @@ * when CONFIG_SYS_64BIT_LBA is not defined, lbaint_t is 32 bits; this * limits the maximum size of addressable storage to < 2 Terra Bytes */ + #include <asm/unaligned.h> #include <common.h> #include <command.h> @@ -159,11 +160,12 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h) uint64_t val;
/* 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->partition_entry_lba = - cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1); + val = le64_to_cpu(gpt_h->alternate_lba); + gpt_h->alternate_lba = gpt_h->my_lba; + gpt_h->my_lba = cpu_to_le64(val); + val -= (le32_to_cpu(gpt_h->num_partition_entries) * + le32_to_cpu(gpt_h->sizeof_partition_entry)); + gpt_h->partition_entry_lba = cpu_to_le64(val); gpt_h->header_crc32 = 0;
calc_crc32 = efi_crc32((const unsigned char *)gpt_h, @@ -171,36 +173,16 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h) gpt_h->header_crc32 = cpu_to_le32(calc_crc32); }
+ #ifdef CONFIG_EFI_PARTITION -/* - * Public Functions (include/part.h) - */
-void part_print_efi(struct blk_desc *dev_desc) +static void part_print_gpt(gpt_header *gpt_head, + gpt_entry *gpt_pte) { - ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz); - gpt_entry *gpt_pte = NULL; int i = 0; char uuid[37]; unsigned char *uuid_bin;
- /* This function validates AND fills in the GPT header and PTE */ - if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA, - gpt_head, &gpt_pte) != 1) { - printf("%s: *** ERROR: Invalid GPT ***\n", __func__); - if (is_gpt_valid(dev_desc, (dev_desc->lba - 1), - gpt_head, &gpt_pte) != 1) { - printf("%s: *** ERROR: Invalid Backup GPT ***\n", - __func__); - return; - } else { - printf("%s: *** Using Backup GPT ***\n", - __func__); - } - } - - debug("%s: gpt-entry at %p\n", __func__, gpt_pte); - printf("Part\tStart LBA\tEnd LBA\t\tName\n"); printf("\tAttributes\n"); printf("\tType GUID\n"); @@ -227,6 +209,60 @@ void part_print_efi(struct blk_desc *dev_desc) uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID); printf("\tguid:\t%s\n", uuid); } +} + +static void part_get_disk_info(int part, unsigned int blksz, + gpt_entry *gpt_pte, disk_partition_t *info) +{ + /* The 'lbaint_t' casting may limit the maximum disk size to 2 TB */ + info->start = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].starting_lba); + /* The ending LBA is inclusive, to calculate size, add 1 to it */ + info->size = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1 + - info->start; + info->blksz = blksz; + + sprintf((char *)info->name, "%s", print_efiname(&gpt_pte[part - 1])); + strcpy((char *)info->type, "U-Boot"); + info->bootable = is_bootable(&gpt_pte[part - 1]); +#ifdef CONFIG_PARTITION_UUIDS + uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b, info->uuid, + UUID_STR_FORMAT_GUID); +#endif +#ifdef CONFIG_PARTITION_TYPE_GUID + uuid_bin_to_str(gpt_pte[part - 1].partition_type_guid.b, + info->type_guid, UUID_STR_FORMAT_GUID); +#endif + + debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__, + info->start, info->size, info->name); +} + +/* + * Public Functions (include/part.h) + */ +void part_print_efi(struct blk_desc *dev_desc) +{ + ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz); + gpt_entry *gpt_pte = NULL; + + /* This function validates AND fills in the GPT header and PTE */ + if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA, + gpt_head, &gpt_pte) != 1) { + printf("%s: *** ERROR: Invalid GPT ***\n", __func__); + if (is_gpt_valid(dev_desc, (dev_desc->lba - 1), + gpt_head, &gpt_pte) != 1) { + printf("%s: *** ERROR: Invalid Backup GPT ***\n", + __func__); + return; + } else { + printf("%s: *** Using Backup GPT ***\n", + __func__); + } + } + + debug("%s: gpt-entry at %p\n", __func__, gpt_pte); + + part_print_gpt(gpt_head, gpt_pte);
/* Remember to free pte */ free(gpt_pte); @@ -268,28 +304,7 @@ int part_get_info_efi(struct blk_desc *dev_desc, int part, return -1; }
- /* The 'lbaint_t' casting may limit the maximum disk size to 2 TB */ - info->start = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].starting_lba); - /* The ending LBA is inclusive, to calculate size, add 1 to it */ - info->size = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1 - - info->start; - info->blksz = dev_desc->blksz; - - sprintf((char *)info->name, "%s", - print_efiname(&gpt_pte[part - 1])); - strcpy((char *)info->type, "U-Boot"); - info->bootable = is_bootable(&gpt_pte[part - 1]); -#ifdef CONFIG_PARTITION_UUIDS - uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b, info->uuid, - UUID_STR_FORMAT_GUID); -#endif -#ifdef CONFIG_PARTITION_TYPE_GUID - uuid_bin_to_str(gpt_pte[part - 1].partition_type_guid.b, - info->type_guid, UUID_STR_FORMAT_GUID); -#endif - - debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__, - info->start, info->size, info->name); + part_get_disk_info(part, dev_desc->blksz, gpt_pte, info);
/* Remember to free pte */ free(gpt_pte);

Hi Patrick,
On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
From: Patrick Delaunay patrick.delaunay@st.com
udpate prepare_backup_gpt_header(): calculate partition_entry_lba and no more assumed last lba + 1
split part_print_efi : create sub-functions part_print_gpt() part_get_disk_info()
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2: None
disk/part_efi.c | 115 ++++++++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 50 deletions(-)
To my mind there is too much going on in this one patch? I think it should be perhaps 3 patches.
diff --git a/disk/part_efi.c b/disk/part_efi.c index 1924338..a23c8ea 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -10,6 +10,7 @@
- when CONFIG_SYS_64BIT_LBA is not defined, lbaint_t is 32 bits; this
- limits the maximum size of addressable storage to < 2 Terra Bytes
*/
Unrelated change?
#include <asm/unaligned.h> #include <common.h> #include <command.h> @@ -159,11 +160,12 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h) uint64_t val;
/* 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->partition_entry_lba =
cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1);
val = le64_to_cpu(gpt_h->alternate_lba);
gpt_h->alternate_lba = gpt_h->my_lba;
gpt_h->my_lba = cpu_to_le64(val);
val -= (le32_to_cpu(gpt_h->num_partition_entries) *
le32_to_cpu(gpt_h->sizeof_partition_entry));
gpt_h->partition_entry_lba = cpu_to_le64(val);
I'm not sure what these changes are for, but they probably need their own commit.
Regards, Simon

From: Patrick Delaunay patrick.delaunay@st.com
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
Kconfig | 12 ++ disk/part_efi.c | 445 +++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/README.gpt.mtd | 189 +++++++++++++++++++++++ include/part.h | 13 +- 4 files changed, 657 insertions(+), 2 deletions(-) create mode 100644 doc/README.gpt.mtd
diff --git a/Kconfig b/Kconfig index 529858a..1ce39d5 100644 --- a/Kconfig +++ b/Kconfig @@ -309,6 +309,18 @@ config ARCH_FIXUP_FDT
endmenu # Boot images
+config EFI_PARTITION_MTD + bool "Support GPT over MTD" + help + The GPT partition is normally defined only for block device with + built-in controller which manage flash translation layer + This option activate the GPT partition support over RAW device + using the MTD framework + - manage partition over MTD devices (as flash: NOR and NAND) + - extract MTD information + - update command gpt, mtdparts and part + NB: depends on EFI_PARTITION + source "common/Kconfig"
source "cmd/Kconfig" diff --git a/disk/part_efi.c b/disk/part_efi.c index a23c8ea..f409bb0 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -21,6 +21,10 @@ #include <part_efi.h> #include <linux/ctype.h>
+#ifdef CONFIG_EFI_PARTITION_MTD +#include <linux/mtd/mtd.h> +#endif + DECLARE_GLOBAL_DATA_PTR;
#ifdef HAVE_BLOCK_DEVICE @@ -960,3 +964,444 @@ U_BOOT_PART_TYPE(a_efi) = { .test = part_test_efi, }; #endif + +#ifdef CONFIG_EFI_PARTITION_MTD +static int is_primary_gpt_valid_mtd(struct mtd_info *mtd, + lbaint_t lba, + void **buf, + gpt_header **pgpt_head, + gpt_entry **pgpt_pte) +{ + gpt_header *gpt_h; + gpt_entry *gpt_e; + uint32_t size; + uint64_t offset; + int ret; + size_t retlen; + lbaint_t my_lba; + u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), + MTD_LBA_SIZE); + + size = gpt_e_size + 2 * MTD_LBA_SIZE; + /* skip bad block */ + offset = 0; + while (mtd_block_isbad(mtd, offset)) { + printf("bad block at 0x%llx\n", offset); + offset += mtd->erasesize; + if (offset >= mtd->size) { + printf("*** ERROR: too many bad block ***\n"); + return -1; + } + } + + debug("primary offset = 0x%llx\n", offset); + /* Read primary GPT from device */ + ret = mtd_read(mtd, offset, size, &retlen, *buf); + if (ret || (retlen != size)) { + printf("*** ERROR: Can't read primary GPT ***\n"); + return -1; + } + + /* determine start of GPT Header & Entries in the buffer */ + gpt_h = *buf + (1 * MTD_LBA_SIZE); + gpt_e = *buf + (2 * MTD_LBA_SIZE); + my_lba = lldiv(offset, MTD_LBA_SIZE) + GPT_PRIMARY_PARTITION_TABLE_LBA; + + if (!validate_gpt_header(gpt_h, my_lba, lba) && + !validate_gpt_entries(gpt_h, gpt_e)) { + *pgpt_head = gpt_h; + *pgpt_pte = gpt_e; + return 0; + } + return -1; +} + +static int is_secondary_gpt_valid_mtd(struct mtd_info *mtd, + lbaint_t lba, + void **buf, + gpt_header **pgpt_head, + gpt_entry **pgpt_pte) +{ + gpt_header *gpt_h; + gpt_entry *gpt_e; + uint32_t size; + uint64_t offset; + int ret; + size_t retlen; + lbaint_t my_lba; + u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), + MTD_LBA_SIZE); + + size = gpt_e_size + 2 * MTD_LBA_SIZE; + /* skip bad block */ + offset = mtd->size; + while (mtd_block_isbad(mtd, offset - mtd->erasesize)) { + offset -= mtd->erasesize; + printf("bad block at 0x%llx\n", offset); + if (offset <= mtd->erasesize) { + printf("*** ERROR: too many bad block ***\n"); + return -1; + } + } + + /* Read backup GPT from device : end of the last valid block */ + size = gpt_e_size + MTD_LBA_SIZE; + offset -= size; + + debug("backup offset = 0x%llx\n", offset); + ret = mtd_read(mtd, offset, size, &retlen, *buf); + if (ret || (retlen != size)) { + printf("*** ERROR: Can't read backup GPT ***\n"); + return -1; + } + + /* determine start of GPT Header & Entries in the buffer */ + gpt_h = *buf + gpt_e_size; + gpt_e = *buf; + my_lba = lldiv(offset, MTD_LBA_SIZE) - 1; + + if (!validate_gpt_header(gpt_h, my_lba, lba) && + !validate_gpt_entries(gpt_h, gpt_e)) { + *pgpt_head = gpt_h; + *pgpt_pte = gpt_e; + return 0; + } + return -1; +} + +/** + * is_gpt_valid_mtd() - tests one GPT header and PTEs for validity + * + * lba is the logical block address of the GPT header to test + * pgpt_head is a GPT header ptr, filled on return. + * pgpt_pte is a PTEs ptr, filled on return. + * + * Description: returns 1 if valid, 0 on error. + * If valid, returns pointers to PTEs. + */ + +static int is_gpt_valid_mtd(struct mtd_info *mtd, + void **buf, + gpt_header **pgpt_head, + gpt_entry **pgpt_pte) +{ + u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), + MTD_LBA_SIZE); + lbaint_t lba; + + if (!mtd || !pgpt_head || !pgpt_pte) { + printf("%s: Invalid Argument(s)\n", __func__); + return 0; + } + *pgpt_head = NULL; + *pgpt_pte = NULL; + *buf = malloc(gpt_e_size + 2 * MTD_LBA_SIZE); + lba = lldiv(mtd->size, MTD_LBA_SIZE); + + if (!is_primary_gpt_valid_mtd(mtd, lba, buf, pgpt_head, pgpt_pte)) + return 1; + + printf("%s: *** ERROR: Invalid GPT ***\n", __func__); + + if (!is_secondary_gpt_valid_mtd(mtd, lba, buf, pgpt_head, pgpt_pte)) { + printf("%s: *** Using Backup GPT ***\n", __func__); + return 1; + } + printf("%s: *** ERROR: Invalid Backup GPT ***\n", __func__); + + free(*buf); + return 0; +} + + +static int gpt_fill_header_mtd(struct mtd_info *mtd, gpt_header *gpt_h, + char *str_guid, int parts_count) +{ + uint32_t erasesize; + uint64_t offset_p_gpt, offset_s_gpt; + __le64 my_lba; + __le64 alternate_lba; + u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), + MTD_LBA_SIZE); + + /* one mtd block is not enought for MBR and GPT */ + if ((gpt_e_size + 2 * MTD_LBA_SIZE) > mtd->erasesize) + return -1; + + erasesize = lldiv(mtd->erasesize, MTD_LBA_SIZE); + + /* GPT location : skip bad block */ + offset_p_gpt = 0; + while (mtd_block_isbad(mtd, offset_p_gpt)) { + printf("bad block at 0x%llx\n", offset_p_gpt); + offset_p_gpt += mtd->erasesize; + if (offset_p_gpt >= mtd->size) + return -1; + } + /* primary GPT : 17 first LBA of last good block */ + my_lba = lldiv(offset_p_gpt, MTD_LBA_SIZE) + 1; + + offset_s_gpt = mtd->size; + while (mtd_block_isbad(mtd, offset_s_gpt - mtd->erasesize)) { + offset_s_gpt -= mtd->erasesize; + printf("bad block at 0x%llx\n", offset_s_gpt); + if (offset_s_gpt <= mtd->erasesize) + return -1; + } + /* secondary GPT : 16 LBA of last good block */ + alternate_lba = lldiv(offset_s_gpt, MTD_LBA_SIZE) - 1; + + /* only one good block (primary and secondary on same block) */ + if (offset_p_gpt == ((offset_s_gpt - mtd->erasesize))) + return -1; + + gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE); + gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1); + gpt_h->header_size = cpu_to_le32(sizeof(gpt_header)); + gpt_h->my_lba = cpu_to_le64(my_lba); + gpt_h->alternate_lba = cpu_to_le64(alternate_lba); + gpt_h->first_usable_lba = cpu_to_le64(my_lba - 1 + erasesize); + gpt_h->last_usable_lba = cpu_to_le64(alternate_lba - erasesize); + gpt_h->partition_entry_lba = cpu_to_le64(my_lba + 1); + gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS); + gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry)); + gpt_h->header_crc32 = 0; + gpt_h->partition_entry_array_crc32 = 0; + + if (uuid_str_to_bin(str_guid, gpt_h->disk_guid.b, UUID_STR_FORMAT_GUID)) + return -1; + + return 0; +} + +static int mtd_erase_write_block(struct mtd_info *mtd, + uint64_t offset, + void *buf, + size_t len) +{ + struct erase_info erase; + int ret; + size_t retlen; + u_char *verify_buf; + + erase.mtd = mtd; + erase.len = mtd->erasesize; + erase.addr = offset & ~(mtd->erasesize - 1); /* aligned erase offset */ + erase.callback = NULL; + + debug(" erase at 0x%llx\n", erase.addr); + ret = mtd_erase(mtd, &erase); + if (ret != 0) { + printf("** mark bad block 0x%llx on MTD device %s **\n", + erase.addr, mtd->name); + ret = mtd_block_markbad(mtd, erase.addr); + if (ret) + error("cannot mark bad at offset 0x%llx, error %d", + offset, ret); + return -1; + } + + /* mtd write */ + ret = mtd_write(mtd, offset, len, &retlen, buf); + if (ret != 0 || retlen != len) { + error("Write error %d\n", ret); + return -2; + } + + verify_buf = malloc(len); + ret = mtd_read(mtd, offset, len, &retlen, verify_buf); + if (ret) { + error("Read failed 0x%x, %d\n", (u32)offset, ret); + free(verify_buf); + return -3; + } + + if (memcmp(buf, verify_buf, len)) { + error("Verify failed at 0x%x\n", (u32)offset); + return -4; + } + + free(verify_buf); + + return 0; +} + +static void prepare_mbr_gpt_header_mtd(void *buf, + struct mtd_info *mtd, + gpt_header *gpt_h, + gpt_entry *gpt_e) +{ + legacy_mbr *p_mbr = buf; + u32 calc_crc32; + + /* Generate CRC for the Primary GPT Header */ + 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)); + gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32); + + 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); + + /* Setup the Protective MBR */ + p_mbr->signature = MSDOS_MBR_SIGNATURE; + p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT; + p_mbr->partition_record[0].start_sect = 1; + p_mbr->partition_record[0].nr_sects = (u32) lldiv(mtd->size, + MTD_LBA_SIZE) - 1; +} + + +static int write_gpt_table_mtd(struct mtd_info *mtd, + gpt_header *gpt_h, + gpt_entry *gpt_e) +{ + const int pte_blk_cnt = PAD_COUNT((gpt_h->num_partition_entries + * sizeof(gpt_entry)), MTD_LBA_SIZE); + uint64_t offset; + void *buf; + u32 gpt_e_size = PAD_SIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry), + MTD_LBA_SIZE); + u32 buf_size, p_size, s_size; + + p_size = gpt_e_size + 2 * MTD_LBA_SIZE; + s_size = roundup(gpt_e_size + MTD_LBA_SIZE, mtd->writesize); + buf_size = max(p_size, s_size); + buf = malloc(buf_size); + memset(buf, 0x0, p_size); + + prepare_mbr_gpt_header_mtd(buf, mtd, gpt_h, gpt_e); + + /* GPT Header (1 block) */ + memcpy(buf + (GPT_PRIMARY_PARTITION_TABLE_LBA * MTD_LBA_SIZE), + gpt_h, sizeof(*gpt_h)); + memcpy(buf + ((GPT_PRIMARY_PARTITION_TABLE_LBA + 1) * MTD_LBA_SIZE), + gpt_e, sizeof(gpt_entry) * pte_blk_cnt); + + offset = ALIGN(le64_to_cpu(gpt_h->my_lba - + GPT_PRIMARY_PARTITION_TABLE_LBA) + * MTD_LBA_SIZE, + mtd->erasesize); + + debug("primary offset = 0x%llx\n", offset); + + if (mtd_erase_write_block(mtd, offset, buf, p_size)) + goto err; + + prepare_backup_gpt_header(gpt_h); + + memset(buf, 0x0, s_size); + + offset = (le64_to_cpu(gpt_h->my_lba) + 1) * MTD_LBA_SIZE - s_size; + memcpy(buf + s_size - MTD_LBA_SIZE, gpt_h, sizeof(*gpt_h)); + memcpy(buf + s_size - MTD_LBA_SIZE - gpt_e_size, + gpt_e, sizeof(gpt_entry) * pte_blk_cnt); + + + debug("backup offset = 0x%llx\n", offset); + + if (mtd_erase_write_block(mtd, offset, buf, s_size)) + goto err; + + free(buf); + debug("GPT successfully written to MTD device!\n"); + return 0; + + err: + free(buf); + printf("** Can't write to MTD device %s **\n", mtd->name); + return -1; +} + +/* + * Public Functions (include/part.h) + */ + +int gpt_restore_mtd(struct mtd_info *mtd, char *str_disk_guid, + disk_partition_t *partitions, int parts_count) +{ + int ret; + gpt_header *gpt_h = calloc(1, PAD_SIZE(sizeof(gpt_header), + MTD_LBA_SIZE)); + gpt_entry *gpt_e; + + if (gpt_h == NULL) { + printf("%s: calloc failed!\n", __func__); + return -1; + } + + gpt_e = calloc(1, PAD_SIZE(GPT_ENTRY_NUMBERS + * sizeof(gpt_entry), + MTD_LBA_SIZE)); + if (gpt_e == NULL) { + printf("%s: calloc failed!\n", __func__); + free(gpt_h); + return -1; + } + + /* Generate Primary GPT header (LBA1) */ + ret = gpt_fill_header_mtd(mtd, gpt_h, str_disk_guid, parts_count); + if (ret) + goto err; + + /* Generate partition entries */ + ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count); + if (ret) + goto err; + + /* Write GPT partition table */ + ret = write_gpt_table_mtd(mtd, gpt_h, gpt_e); + +err: + free(gpt_e); + free(gpt_h); + return ret; +} + +void part_print_efi_mtd(struct mtd_info *mtd) +{ + void *buf; + gpt_header *gpt_head; + gpt_entry *gpt_pte; + + if (!is_gpt_valid_mtd(mtd, &buf, &gpt_head, &gpt_pte)) + return; + + part_print_gpt(gpt_head, gpt_pte); + + /* Remember to free buffer */ + free(buf); + return; +} + +int part_get_info_efi_mtd(struct mtd_info *mtd, int part, + disk_partition_t *info) +{ + void *buf; + gpt_header *gpt_head; + gpt_entry *gpt_pte; + + if (!mtd || !info || part < 1) { + printf("%s: Invalid Argument(s)\n", __func__); + return -1; + } + + if (!is_gpt_valid_mtd(mtd, &buf, &gpt_head, &gpt_pte)) + return -1; + + if (part > le32_to_cpu(gpt_head->num_partition_entries) || + !is_pte_valid(&gpt_pte[part - 1])) { + debug("%s: *** ERROR: Invalid partition number %d ***\n", + __func__, part); + free(buf); + return -1; + } + + part_get_disk_info(part, MTD_LBA_SIZE, gpt_pte, info); + + /* Remember to free buffer */ + free(buf); + return 0; +} +#endif /* CONFIG_EFI_PARTITION_MTD */ diff --git a/doc/README.gpt.mtd b/doc/README.gpt.mtd new file mode 100644 index 0000000..fbc8f82 --- /dev/null +++ b/doc/README.gpt.mtd @@ -0,0 +1,189 @@ +# +# +# SPDX-License-Identifier: GPL-2.0+ + +Glossary: +======== +- GPT (GUID Partition Table) - it is the EFI standard part +- MTD (Memory Technology Device) - abstraction layer for RAW flah device + +Introduction: +============= +This document describes the GPT support on MTD and usage of +the associated command in U-Boot. + +The GPT is normally defined only for block device with built-in controller +which manage flash translation layer (FTL) as MMC, SD, USB or ATA. + +For raw flash device, the MTD partionning are usally defined in U-Boot +environment and provided to kernel (see mtdparts command). + +U-Boot support GPT for MTD device to save the partition informations of +raw flash device directly in this device (usefull for CONFIG_ENV_IS_NOWHERE) +and to use these informations to support MTD devices in DISTRO without +hardcoded MTD partitioning in U-Boot environment + +The GPT support on top of MTD is defined under CONFIG_EFI_PARTITION_MTD. + +PS: DISTRO boot cmd is no yet updated + +GPT on MTD brief explanation: +============================= + +The GPT standard is respected (header and field meaning). + +The GPT header and each partition need to be eraseblock-align to allow +individual udpate for header or partiton. + +The primary and the backup GPT header are located in the first and +the last -not bad- eraseblock. + +We assume that one eraseblock is enought for MBR and GPT header +(size = 17 KB for 128 entry) + +So it not compatible with the feature CONFIG_SPI_FLASH_USE_4K_SECTORS + + Layout: + ------- + + ---------------------------------------------------------- + LBA 0-33 |Protective MBR + Primary GPT | 1rst eraseblock + -------------------------------------------------- + LBA 34 | (not used) | + LBA N-1 | | + ---------------------------------------------------------- + LBA N |Partition 1 | 2nd eraseblock + | | = first usable + ----------------------------------- + |Partition 2 | + | | + ----------------------------------- last-1 eraseblock + LBA M |Partition n | = last usable + ---------------------------------------------------------- + LBA M+1 | (not used) | last eraseblock + LBA -35 | | + -------------------------------------------------- + LBA -1 to -34 |Backup GPT Header | + ---------------------------------------------------------- + + NB: this layout change (LBA0 and LBA-1) if bad block are present + + GPT header: + ----------- + + for details of GPT header, see README.gpt + + "Current LBA" and "Backup LBA" give the location of the primary and + secondary GPT header. + + All the bad block are detected and skipped when the GPT header is build. + + For Primary GPT: + + - Current LBA = 2nd LBA of the first good eraseblock + + - Backup LBA = Last LBA of the last good block + + - First usable LBA = First LBA of the first usable eraseblock + i.e. the block after primary GPT one + Current LBA - 1 + erase block size + + - Last usable LBA = Last LBA of the last usable eraseblock + i.e. the block before backup GPT one + Backup LBA - erase block size + + Bad Block management (NAND): + --------------------------- + As the bad blocks are skipped, Current LBA and Backup LBA give the real + location of primary and backup GPT header + + warning: the first and the last usable LBA are not guarantee + to be in a good block + + + Typically, the last 4 erase blocks for NAND are used for the bad block + table (BBT, see bbt_options and NAND_BBT_USE_FLASH). + They are indicated bad by MTD framework and they are also skipped. + So the layout for NAND with bad : + + NAND layout with bad blocks: + ---------------------------------------------------------- + N * BAD (*) | | skipped bad + ----------------------------------------------------------- + |Protective MBR | 1rst good eraseblock + |Primary GPT Header | + | | + ------------------------------------------- + | | = first usable + | | + | Partitions | + | | + | | = last usable + ------------------------------------------- + | | + |Backup GPT Header | last good eraseblock + ---------------------------------------------------------- + M * BAD (*) | | skipped bad + ---------------------------------------------------------- + BBT => BAD (*) | | skipped 4 blocks + ---------------------------------------------------------- + (*) BBT and block marked bad are skipped + + +Drawbacks: +========== +1. 2 eraseblocks are used in the device just to save the GPT headers + (primary and backup) + +2. for device with back block (NAND), any read request can disturb the device + so the GPT header should be refreshed when one fixable bit-flip ECC error is + detected... + but it is not the case today + +3. for gpt write the eraseblock for the primary or backup GPT header + (expected good) can become bad for the erase request + + And then U-Boot will mark this block bad + + In this case the first / last usable LBA need to change and to skip the new + bad block, so header need to be recomputed + => the requested gpt write command failed to force new request + PS: the next request will work (skip the new bad block) + + And as the first / last usable LBA can change the same partionning after + the block is marked bad + +GPT on MTD commands: +==================== +some command are modified to support GPT on MTD devices under CONFIG_EFI_PARTITION_MTD + + Creating GPT on MTD partitions: + ------------------------------- + + 1. Define partition layout in the environment. + "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...; + name=kernel,size=60MiB,uuid=...;" + + 2. From U-Boot prompt type: + gpt write nand 0 $partitions + gpt write nor 0 $partitions + + List GPT partition on MTD: + --------------------------------- + part list nand 0 + part list nor 0 + + to find bootable partition (used for distro): + + part list nand 0 -bootable nand_boot_part + part list nor 0 -bootable nor_boot_part + + NB: bootable partition can be used with UBIFS + + Generate MTD partitions from GPT: + --------------------------------- + mtdparts gpt nand0 + mtdparts gpt nor0 + + Then to check mtd partition created with: + mtdparts diff --git a/include/part.h b/include/part.h index 0979005..0660c27 100644 --- a/include/part.h +++ b/include/part.h @@ -9,6 +9,7 @@
#include <blk.h> #include <ide.h> +#include <linux/mtd/mtd.h>
struct block_drvr { char *name; @@ -308,7 +309,6 @@ int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h, */ int gpt_restore(struct blk_desc *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 * @@ -363,7 +363,16 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head, int gpt_verify_partitions(struct blk_desc *dev_desc, disk_partition_t *partitions, int parts, gpt_header *gpt_head, gpt_entry **gpt_pte); -#endif + +#ifdef CONFIG_EFI_PARTITION_MTD +#define MTD_LBA_SIZE 512 +int gpt_restore_mtd(struct mtd_info *mtd, char *str_disk_guid, + disk_partition_t *partitions, int parts_count); +void part_print_efi_mtd(struct mtd_info *mtd_info); +int part_get_info_efi_mtd(struct mtd_info *mtd, int part, + disk_partition_t *info); +#endif /* CONFIG_EFI_PARTITION_MTD */ +#endif /* CONFIG_EFI_PARTITION */
#ifdef CONFIG_DOS_PARTITION /**

Hi Patrick,
On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
From: Patrick Delaunay patrick.delaunay@st.com
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2: None
Kconfig | 12 ++ disk/part_efi.c | 445 +++++++++++++++++++++++++++++++++++++++++++++++++++++ doc/README.gpt.mtd | 189 +++++++++++++++++++++++ include/part.h | 13 +- 4 files changed, 657 insertions(+), 2 deletions(-) create mode 100644 doc/README.gpt.mtd
This seems OK to me, but here are some general comments:
- Return -EINVAL or something like that instead of -1 - malloc()/calloc() can fail, so check for NULL and return -ENOMEM - how about putting your changes todisk/part_efi.c in their own file?
Regards, Simon

From: Patrick Delaunay patrick.delaunay@st.com
support gpt write for MTD device
gpt write nand 0 gpt write nor 0
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
cmd/gpt.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 16 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 897596a..9e398e9 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -20,6 +20,10 @@ #include <div64.h> #include <memalign.h>
+#ifdef CONFIG_EFI_PARTITION_MTD +#include <linux/mtd/mtd.h> +#endif + #ifndef CONFIG_PARTITION_UUIDS #error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled #endif @@ -168,7 +172,8 @@ static bool found_key(const char *str, const char *key) * @return - zero on success, otherwise error * */ -static int set_gpt_info(struct blk_desc *dev_desc, +static int set_gpt_info(unsigned int lba, + unsigned int blksz, const char *str_part, char **str_disk_guid, disk_partition_t **partitions, @@ -183,8 +188,7 @@ static int set_gpt_info(struct blk_desc *dev_desc, uint64_t size_ll, start_ll; lbaint_t offset = 0;
- debug("%s: lba num: 0x%x %d\n", __func__, - (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba); + debug("%s: lba num: 0x%x %d\n", __func__, lba, lba);
if (str_part == NULL) return -1; @@ -302,7 +306,7 @@ static int set_gpt_info(struct blk_desc *dev_desc, parts[i].size = 0; } else { size_ll = ustrtoull(p, &p, 0); - parts[i].size = lldiv(size_ll, dev_desc->blksz); + parts[i].size = lldiv(size_ll, blksz); }
free(val); @@ -313,7 +317,7 @@ static int set_gpt_info(struct blk_desc *dev_desc, if (extract_env(val, &p)) p = val; start_ll = ustrtoull(p, &p, 0); - parts[i].start = lldiv(start_ll, dev_desc->blksz); + parts[i].start = lldiv(start_ll, blksz); free(val); }
@@ -337,6 +341,16 @@ err: return errno; }
+static void print_gpt_info_err(int ret) +{ + if (ret == -1) + printf("No partition list provided\n"); + if (ret == -2) + printf("Missing disk guid\n"); + if ((ret == -3) || (ret == -4)) + printf("Partition list incomplete\n"); +} + static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) { int ret; @@ -344,16 +358,13 @@ static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) u8 part_count = 0; disk_partition_t *partitions = NULL;
+ if (!str_part) + return -1; /* fill partitions */ - ret = set_gpt_info(blk_dev_desc, str_part, + ret = set_gpt_info(blk_dev_desc->lba, blk_dev_desc->blksz, str_part, &str_disk_guid, &partitions, &part_count); if (ret) { - if (ret == -1) - printf("No partition list provided\n"); - if (ret == -2) - printf("Missing disk guid\n"); - if ((ret == -3) || (ret == -4)) - printf("Partition list incomplete\n"); + print_gpt_info_err(ret); return -1; }
@@ -376,7 +387,7 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) int ret = 0;
/* fill partitions */ - ret = set_gpt_info(blk_dev_desc, str_part, + ret = set_gpt_info(blk_dev_desc->lba, blk_dev_desc->blksz, str_part, &str_disk_guid, &partitions, &part_count); if (ret) { if (ret == -1) { @@ -402,6 +413,35 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) return ret; }
+#ifdef CONFIG_EFI_PARTITION_MTD +static int gpt_default_mtd(struct mtd_info *mtd_info, const char *str_part) +{ + int ret; + char *str_disk_guid; + u8 part_count = 0; + disk_partition_t *partitions = NULL; + unsigned int lba = lldiv(mtd_info->size, MTD_LBA_SIZE); + + if (!str_part) + return -1; + + /* fill partitions */ + ret = set_gpt_info(lba, MTD_LBA_SIZE, str_part, + &str_disk_guid, &partitions, &part_count); + if (ret) { + print_gpt_info_err(ret); + return -1; + } + + /* save partitions layout to disk */ + ret = gpt_restore_mtd(mtd_info, str_disk_guid, partitions, part_count); + free(str_disk_guid); + free(partitions); + + return ret; +} +#endif + /** * do_gpt(): Perform GPT operations * @@ -418,6 +458,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) int dev = 0; char *ep; struct blk_desc *blk_dev_desc = NULL; +#ifdef CONFIG_EFI_PARTITION_MTD + struct mtd_info *mtd_info = NULL; + char mtd_dev[16]; +#endif
if (argc < 4 || argc > 5) return CMD_RET_USAGE; @@ -428,17 +472,38 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_USAGE; } blk_dev_desc = blk_get_dev(argv[2], dev); +#ifdef CONFIG_EFI_PARTITION_MTD if (!blk_dev_desc) { + sprintf(mtd_dev, "%s%d", argv[2], dev); + mtd_info = get_mtd_device_nm(mtd_dev); + if (IS_ERR(mtd_info)) + ret = CMD_RET_FAILURE; + } +#else + if (!blk_dev_desc) + ret = CMD_RET_FAILURE; +#endif + if (ret) { printf("%s: %s dev %d NOT available\n", __func__, argv[2], dev); - return CMD_RET_FAILURE; + return ret; }
if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { printf("Writing GPT: "); - ret = gpt_default(blk_dev_desc, argv[4]); + if (blk_dev_desc) + ret = gpt_default(blk_dev_desc, argv[4]); +#ifdef CONFIG_EFI_PARTITION_MTD + else if (mtd_info) + ret = gpt_default_mtd(mtd_info, argv[4]); +#endif + else + ret = CMD_RET_FAILURE; } else if ((strcmp(argv[1], "verify") == 0)) { - ret = gpt_verify(blk_dev_desc, argv[4]); + if (blk_dev_desc) + ret = gpt_verify(blk_dev_desc, argv[4]); + else + ret = CMD_RET_FAILURE; printf("Verify GPT: "); } else { return CMD_RET_USAGE; @@ -451,6 +516,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf("success!\n"); return CMD_RET_SUCCESS; + }
U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,

Hi Patrick,
On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
From: Patrick Delaunay patrick.delaunay@st.com
support gpt write for MTD device
gpt write nand 0 gpt write nor 0
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2: None
cmd/gpt.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 82 insertions(+), 16 deletions(-)
Can you please out your refactoring changes into a separate patch? Then have a patch that adds your feature.
diff --git a/cmd/gpt.c b/cmd/gpt.c index 897596a..9e398e9 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -20,6 +20,10 @@ #include <div64.h> #include <memalign.h>
+#ifdef CONFIG_EFI_PARTITION_MTD +#include <linux/mtd/mtd.h> +#endif
I don't think you need the #ifdef, unless including that file is harmful.
#ifndef CONFIG_PARTITION_UUIDS #error CONFIG_PARTITION_UUIDS must be enabled for CONFIG_CMD_GPT to be enabled #endif @@ -168,7 +172,8 @@ static bool found_key(const char *str, const char *key)
- @return - zero on success, otherwise error
*/ -static int set_gpt_info(struct blk_desc *dev_desc, +static int set_gpt_info(unsigned int lba,
unsigned int blksz, const char *str_part, char **str_disk_guid, disk_partition_t **partitions,
@@ -183,8 +188,7 @@ static int set_gpt_info(struct blk_desc *dev_desc, uint64_t size_ll, start_ll; lbaint_t offset = 0;
debug("%s: lba num: 0x%x %d\n", __func__,
(unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
debug("%s: lba num: 0x%x %d\n", __func__, lba, lba); if (str_part == NULL) return -1;
@@ -302,7 +306,7 @@ static int set_gpt_info(struct blk_desc *dev_desc, parts[i].size = 0; } else { size_ll = ustrtoull(p, &p, 0);
parts[i].size = lldiv(size_ll, dev_desc->blksz);
parts[i].size = lldiv(size_ll, blksz); } free(val);
@@ -313,7 +317,7 @@ static int set_gpt_info(struct blk_desc *dev_desc, if (extract_env(val, &p)) p = val; start_ll = ustrtoull(p, &p, 0);
parts[i].start = lldiv(start_ll, dev_desc->blksz);
parts[i].start = lldiv(start_ll, blksz); free(val); }
@@ -337,6 +341,16 @@ err: return errno; }
+static void print_gpt_info_err(int ret) +{
if (ret == -1)
These should really use an enum rather than be open-coded. Or use errno.h values.
printf("No partition list provided\n");
if (ret == -2)
printf("Missing disk guid\n");
if ((ret == -3) || (ret == -4))
printf("Partition list incomplete\n");
+}
static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) { int ret; @@ -344,16 +358,13 @@ static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part) u8 part_count = 0; disk_partition_t *partitions = NULL;
if (!str_part)
return -1; /* fill partitions */
ret = set_gpt_info(blk_dev_desc, str_part,
ret = set_gpt_info(blk_dev_desc->lba, blk_dev_desc->blksz, str_part, &str_disk_guid, &partitions, &part_count); if (ret) {
if (ret == -1)
printf("No partition list provided\n");
if (ret == -2)
printf("Missing disk guid\n");
if ((ret == -3) || (ret == -4))
printf("Partition list incomplete\n");
print_gpt_info_err(ret); return -1; }
@@ -376,7 +387,7 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) int ret = 0;
/* fill partitions */
ret = set_gpt_info(blk_dev_desc, str_part,
ret = set_gpt_info(blk_dev_desc->lba, blk_dev_desc->blksz, str_part, &str_disk_guid, &partitions, &part_count); if (ret) { if (ret == -1) {
@@ -402,6 +413,35 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part) return ret; }
+#ifdef CONFIG_EFI_PARTITION_MTD +static int gpt_default_mtd(struct mtd_info *mtd_info, const char *str_part) +{
int ret;
char *str_disk_guid;
u8 part_count = 0;
disk_partition_t *partitions = NULL;
unsigned int lba = lldiv(mtd_info->size, MTD_LBA_SIZE);
if (!str_part)
return -1;
/* fill partitions */
ret = set_gpt_info(lba, MTD_LBA_SIZE, str_part,
&str_disk_guid, &partitions, &part_count);
if (ret) {
print_gpt_info_err(ret);
return -1;
}
/* save partitions layout to disk */
ret = gpt_restore_mtd(mtd_info, str_disk_guid, partitions, part_count);
free(str_disk_guid);
free(partitions);
return ret;
+} +#endif
/**
- do_gpt(): Perform GPT operations
@@ -418,6 +458,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) int dev = 0; char *ep; struct blk_desc *blk_dev_desc = NULL; +#ifdef CONFIG_EFI_PARTITION_MTD
struct mtd_info *mtd_info = NULL;
char mtd_dev[16];
+#endif
if (argc < 4 || argc > 5) return CMD_RET_USAGE;
@@ -428,17 +472,38 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_USAGE; } blk_dev_desc = blk_get_dev(argv[2], dev); +#ifdef CONFIG_EFI_PARTITION_MTD if (!blk_dev_desc) {
sprintf(mtd_dev, "%s%d", argv[2], dev);
mtd_info = get_mtd_device_nm(mtd_dev);
if (IS_ERR(mtd_info))
ret = CMD_RET_FAILURE;
}
+#else
if (!blk_dev_desc)
ret = CMD_RET_FAILURE;
+#endif
if (ret) { printf("%s: %s dev %d NOT available\n", __func__, argv[2], dev);
return CMD_RET_FAILURE;
return ret; } if ((strcmp(argv[1], "write") == 0) && (argc == 5)) { printf("Writing GPT: ");
ret = gpt_default(blk_dev_desc, argv[4]);
if (blk_dev_desc)
ret = gpt_default(blk_dev_desc, argv[4]);
+#ifdef CONFIG_EFI_PARTITION_MTD
else if (mtd_info)
ret = gpt_default_mtd(mtd_info, argv[4]);
+#endif
else
ret = CMD_RET_FAILURE; } else if ((strcmp(argv[1], "verify") == 0)) {
ret = gpt_verify(blk_dev_desc, argv[4]);
if (blk_dev_desc)
ret = gpt_verify(blk_dev_desc, argv[4]);
else
ret = CMD_RET_FAILURE; printf("Verify GPT: "); } else { return CMD_RET_USAGE;
@@ -451,6 +516,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
printf("success!\n"); return CMD_RET_SUCCESS;
Unrelated change, although you could put a blank line *before* the return.
}
U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
1.9.1
Regards, Simon

From: Patrick Delaunay patrick.delaunay@st.com
support part list for MTD device
part list nand 0 part list nor 0
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
cmd/part.c | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-)
diff --git a/cmd/part.c b/cmd/part.c index 414031e..4ea0fb2 100644 --- a/cmd/part.c +++ b/cmd/part.c @@ -52,11 +52,15 @@ static int do_part_uuid(int argc, char * const argv[]) static int do_part_list(int argc, char * const argv[]) { int ret; - struct blk_desc *desc; + struct blk_desc *desc = NULL; char *var = NULL; bool bootable = false; int i;
+#ifdef CONFIG_EFI_PARTITION_MTD + struct mtd_info *mtd = NULL; + char mtd_dev[16]; +#endif if (argc < 2) return CMD_RET_USAGE;
@@ -81,10 +85,19 @@ static int do_part_list(int argc, char * const argv[]) return CMD_RET_USAGE; }
- ret = blk_get_device_by_str(argv[0], argv[1], &desc); - if (ret < 0) - return 1; - +#ifdef CONFIG_EFI_PARTITION_MTD + if ((strlen(argv[0]) + strlen(argv[1])) < sizeof(mtd_dev)) { + sprintf(mtd_dev, "%s%s", argv[0], argv[1]); + mtd = get_mtd_device_nm(mtd_dev); + } + if (IS_ERR(mtd)) { +#endif + ret = blk_get_device_by_str(argv[0], argv[1], &desc); + if (ret < 0) + return 1; +#ifdef CONFIG_EFI_PARTITION_MTD + } +#endif if (var != NULL) { int p; char str[512] = { '\0', }; @@ -92,10 +105,21 @@ static int do_part_list(int argc, char * const argv[])
for (p = 1; p < 128; p++) { char t[5]; - int r = part_get_info(desc, p, &info); + int r; + if (desc) { + r = part_get_info(desc, p, &info);
- if (r != 0) - continue; + if (r != 0) + continue; + } +#ifdef CONFIG_EFI_PARTITION_MTD + else { + r = part_get_info_efi_mtd(mtd, p, &info); + /* Stop for first non valid partition */ + if (r != 0) + break; + } +#endif
if (bootable && !info.bootable) continue; @@ -107,8 +131,14 @@ static int do_part_list(int argc, char * const argv[]) return 0; }
+#ifndef CONFIG_EFI_PARTITION_MTD part_print(desc); - +#else + if (desc) + part_print(desc); + else + part_print_efi_mtd(mtd); +#endif return 0; }

On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
From: Patrick Delaunay patrick.delaunay@st.com
support part list for MTD device
part list nand 0 part list nor 0
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2: None
cmd/part.c | 48 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 9 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

add new subcommand : mtdparts gpt <mtd-dev> [<GUID>]
extract mtd partition from GPT header present in MTD device
mtdparts gpt nand0 mtdparts gpt nor0
extract mtd partitions only for some GUID
mtdparts gpt nand0 data mtdparts gpt nor0 0FC63DAF-8483-4772-8E79-3D69D8477DE4
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
cmd/mtdparts.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-)
diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c index b9b160d..035a7ec 100644 --- a/cmd/mtdparts.c +++ b/cmd/mtdparts.c @@ -121,6 +121,8 @@ extern void board_mtdparts_default(const char **mtdids, const char **mtdparts); static const char *mtdids_default = MTDIDS_DEFAULT; static const char *mtdparts_default = MTDPARTS_DEFAULT;
+#define PART_ADD_DESC_MAXLEN 64 + /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */ #define MTDIDS_MAXLEN 128 #define MTDPARTS_MAXLEN 512 @@ -1891,6 +1893,90 @@ static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part return NULL; }
+#ifdef CONFIG_EFI_PARTITION_MTD +/** + * extract MTD info from GPT information + * + * @param device string to select GPT device + * @param p_guid_filter guid for filtering add + * + * @return 0 on success, 1 otherwise + */ + +static int mtdparts_gpt(char *device, char *p_guid_filter) +{ + char tmpbuf[PART_ADD_DESC_MAXLEN]; + u8 type, num; + struct mtdids *id; + int part_id; + struct mtd_info *mtd; + struct mtd_device *dev; + struct mtd_device *dev_tmp; + disk_partition_t info; + struct part_info *p; + + if (mtd_id_parse(device, NULL, &type, &num) != 0) { + printf("invalid MTD device %s\n", device); + return 1; + } + + /* this may be the first run, initialize lists if needed + and make sure we are in sync with env variables */ + mtdparts_init(); + /* don't treat error (mtdparts can be empty) */ + + id = id_find(type, num); + if (id == NULL) { + printf("no such device %s defined in mtdids variable\n", + device); + return 1; + } + + if (get_mtd_info(type, num, &mtd) || (mtd == NULL)) { + printf("no such MTD device %s\n", device); + return 1; + } + + for (part_id = 1; part_id <= GPT_ENTRY_NUMBERS; part_id++) { + if (part_get_info_efi_mtd(mtd, part_id, &info)) + break; /* Stop for first non valid partition */ + +#ifdef CONFIG_PARTITION_TYPE_GUID + if (p_guid_filter && + strcmp(p_guid_filter, info.type_guid)) + continue; +#endif + + sprintf(tmpbuf, "%s:0x%llx@0x%llx(%s)", + id->mtd_id, + (u64)(info.size * info.blksz), + (u64)(info.start * info.blksz), + info.name); + debug("add tmpbuf: %s\n", tmpbuf); + + if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev)) + return 1; + + debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(type), num, + id->mtd_id); + + p = list_entry(dev->parts.next, struct part_info, link); + + dev_tmp = device_find(type, num); + + if (dev_tmp == NULL) + device_add(dev); + else if (part_add(dev_tmp, p) != 0) + return 1; + } + if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) { + printf("generated mtdparts too long, resetting to null\n"); + return 1; + } + return 0; +} +#endif + /***************************************************/ /* U-Boot commands */ /***************************************************/ @@ -1966,6 +2052,30 @@ static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, } }
+#ifdef CONFIG_EFI_PARTITION_MTD + /* mtdparts gpt <mtd-dev> [GUID] */ + if ((argc == 3 || argc == 4) && (strncmp(argv[1], "gpt", 3) == 0)) { +#ifdef CONFIG_PARTITION_TYPE_GUID + char guid_str[UUID_STR_LEN + 1]; + char *p_guid_filter = NULL; +#endif + + if (argc == 4) { +#ifdef CONFIG_PARTITION_TYPE_GUID + p_guid_filter = guid_str; + if (uuid_guid_parse_str(argv[3], guid_str)) { + printf("invalid type gui %s\n", argv[3]); + return 1; + } + debug("filtered type gui %s (%s)\n", argv[3], guid_str); +#else + puts("type GUI not support\n"); +#endif + } + + return mtdparts_gpt(argv[2], p_guid_filter); + } +#endif /* make sure we are in sync with env variables */ if (mtdparts_init() != 0) return 1; @@ -1977,7 +2087,6 @@ static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc,
/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */ if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) { -#define PART_ADD_DESC_MAXLEN 64 char tmpbuf[PART_ADD_DESC_MAXLEN]; #if defined(CONFIG_CMD_MTDPARTS_SPREAD) struct mtd_info *mtd; @@ -2083,6 +2192,10 @@ static char mtdparts_help_text[] = "mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" " - add partition, padding size by skipping bad blocks\n" #endif +#ifdef CONFIG_EFI_PARTITION_MTD + "mtdparts gpt <mtd-dev> [<GUID>]\n" + " - add partitions for device from gpt, filtered by GUID type\n" +#endif "mtdparts default\n" " - reset partition table to defaults\n" #if defined(CONFIG_CMD_MTDPARTS_SPREAD) @@ -2112,7 +2225,11 @@ static char mtdparts_help_text[] = "<size> := standard linux memsize OR '-' to denote all remaining space\n" "<offset> := partition start offset within the device\n" "<name> := '(' NAME ')'\n" - "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"; + "<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)" +#ifdef CONFIG_EFI_PARTITION_MTD + "<GUID> := partition guid" +#endif + ; #endif
U_BOOT_CMD(

Hi Patrick,
On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
add new subcommand : mtdparts gpt <mtd-dev> [<GUID>]
extract mtd partition from GPT header present in MTD device
mtdparts gpt nand0 mtdparts gpt nor0
extract mtd partitions only for some GUID
mtdparts gpt nand0 data mtdparts gpt nor0 0FC63DAF-8483-4772-8E79-3D69D8477DE4
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2: None
cmd/mtdparts.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
But please see nits below.
diff --git a/cmd/mtdparts.c b/cmd/mtdparts.c index b9b160d..035a7ec 100644 --- a/cmd/mtdparts.c +++ b/cmd/mtdparts.c @@ -121,6 +121,8 @@ extern void board_mtdparts_default(const char **mtdids, const char **mtdparts); static const char *mtdids_default = MTDIDS_DEFAULT; static const char *mtdparts_default = MTDPARTS_DEFAULT;
+#define PART_ADD_DESC_MAXLEN 64
This change should really be in a new patch, and it would be good to have a comment as to what this is.
/* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */ #define MTDIDS_MAXLEN 128 #define MTDPARTS_MAXLEN 512 @@ -1891,6 +1893,90 @@ static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part return NULL; }
+#ifdef CONFIG_EFI_PARTITION_MTD +/**
- extract MTD info from GPT information
- @param device string to select GPT device
- @param p_guid_filter guid for filtering add
- @return 0 on success, 1 otherwise
I think it would be better to return a useful error number from errno.h and have the caller turn it into CMD_RET_FAILURE.
- */
+static int mtdparts_gpt(char *device, char *p_guid_filter) +{
char tmpbuf[PART_ADD_DESC_MAXLEN];
u8 type, num;
struct mtdids *id;
int part_id;
struct mtd_info *mtd;
struct mtd_device *dev;
struct mtd_device *dev_tmp;
disk_partition_t info;
struct part_info *p;
if (mtd_id_parse(device, NULL, &type, &num) != 0) {
printf("invalid MTD device %s\n", device);
return 1;
}
/* this may be the first run, initialize lists if needed
and make sure we are in sync with env variables */
mtdparts_init();
/* don't treat error (mtdparts can be empty) */
id = id_find(type, num);
if (id == NULL) {
printf("no such device %s defined in mtdids variable\n",
device);
return 1;
}
if (get_mtd_info(type, num, &mtd) || (mtd == NULL)) {
printf("no such MTD device %s\n", device);
return 1;
}
for (part_id = 1; part_id <= GPT_ENTRY_NUMBERS; part_id++) {
if (part_get_info_efi_mtd(mtd, part_id, &info))
break; /* Stop for first non valid partition */
+#ifdef CONFIG_PARTITION_TYPE_GUID
if (p_guid_filter &&
strcmp(p_guid_filter, info.type_guid))
continue;
+#endif
sprintf(tmpbuf, "%s:0x%llx@0x%llx(%s)",
Can you use snprintf() to be safe?
id->mtd_id,
(u64)(info.size * info.blksz),
(u64)(info.start * info.blksz),
info.name);
debug("add tmpbuf: %s\n", tmpbuf);
if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
return 1;
debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(type), num,
id->mtd_id);
p = list_entry(dev->parts.next, struct part_info, link);
dev_tmp = device_find(type, num);
if (dev_tmp == NULL)
device_add(dev);
else if (part_add(dev_tmp, p) != 0)
return 1;
}
if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
printf("generated mtdparts too long, resetting to null\n");
return 1;
}
return 0;
+} +#endif
/***************************************************/ /* U-Boot commands */ /***************************************************/ @@ -1966,6 +2052,30 @@ static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, } }
+#ifdef CONFIG_EFI_PARTITION_MTD
/* mtdparts gpt <mtd-dev> [GUID] */
if ((argc == 3 || argc == 4) && (strncmp(argv[1], "gpt", 3) == 0)) {
+#ifdef CONFIG_PARTITION_TYPE_GUID
char guid_str[UUID_STR_LEN + 1];
char *p_guid_filter = NULL;
+#endif
if (argc == 4) {
+#ifdef CONFIG_PARTITION_TYPE_GUID
p_guid_filter = guid_str;
if (uuid_guid_parse_str(argv[3], guid_str)) {
printf("invalid type gui %s\n", argv[3]);
return 1;
}
debug("filtered type gui %s (%s)\n", argv[3], guid_str);
+#else
puts("type GUI not support\n");
printf()
Should this be GUID?
+#endif
}
return mtdparts_gpt(argv[2], p_guid_filter);
}
+#endif /* make sure we are in sync with env variables */ if (mtdparts_init() != 0) return 1; @@ -1977,7 +2087,6 @@ static int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc,
/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */ if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
-#define PART_ADD_DESC_MAXLEN 64 char tmpbuf[PART_ADD_DESC_MAXLEN]; #if defined(CONFIG_CMD_MTDPARTS_SPREAD) struct mtd_info *mtd; @@ -2083,6 +2192,10 @@ static char mtdparts_help_text[] = "mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n" " - add partition, padding size by skipping bad blocks\n" #endif +#ifdef CONFIG_EFI_PARTITION_MTD
"mtdparts gpt <mtd-dev> [<GUID>]\n"
" - add partitions for device from gpt, filtered by GUID type\n"
+#endif "mtdparts default\n" " - reset partition table to defaults\n" #if defined(CONFIG_CMD_MTDPARTS_SPREAD) @@ -2112,7 +2225,11 @@ static char mtdparts_help_text[] = "<size> := standard linux memsize OR '-' to denote all remaining space\n" "<offset> := partition start offset within the device\n" "<name> := '(' NAME ')'\n"
"<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)";
"<ro-flag> := when set to 'ro' makes partition read-only (not used, passed to kernel)"
+#ifdef CONFIG_EFI_PARTITION_MTD
"<GUID> := partition guid"
+#endif
;
#endif
U_BOOT_CMD(
1.9.1
Regards, Simon

From: Patrick Delaunay patrick.delaunay@st.com
io.h is only used for CONFIG_RANDOM_UUID - for clrsetbits_be16 - for clrsetbits_8 available only for some target (but not for SANDBOX)
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
lib/uuid.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/lib/uuid.c b/lib/uuid.c index eb8d8eb..47646e3 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -8,7 +8,6 @@ #include <linux/ctype.h> #include <errno.h> #include <common.h> -#include <asm/io.h> #include <part_efi.h> #include <malloc.h>
@@ -276,13 +275,13 @@ void gen_rand_uuid(unsigned char *uuid_bin) for (i = 0; i < sizeof(struct uuid) / sizeof(*ptr); i++) *(ptr + i) = cpu_to_be32(rand());
- clrsetbits_be16(&uuid.time_hi_and_version, - UUID_VERSION_MASK, - UUID_VERSION << UUID_VERSION_SHIFT); + /* UUID is big endian */ + uuid.time_hi_and_version |= ~cpu_to_be16(UUID_VERSION_MASK); + uuid.time_hi_and_version &= + cpu_to_be16(UUID_VERSION << UUID_VERSION_SHIFT);
- clrsetbits_8(&uuid.clock_seq_hi_and_reserved, - UUID_VARIANT_MASK, - UUID_VARIANT << UUID_VARIANT_SHIFT); + uuid.clock_seq_hi_and_reserved |= ~UUID_VARIANT_MASK; + uuid.clock_seq_hi_and_reserved &= UUID_VARIANT << UUID_VARIANT_SHIFT;
memcpy(uuid_bin, &uuid, sizeof(struct uuid)); }

From: Patrick Delaunay patrick.delaunay@st.com
activate needed feature in sandbox to allow test GPT over MTD - EFI_PARTITION_MTD - SPI_FLASH_MTD - CMD_MTDPARTS - MTD_PARTITIONS - MTD_DEVICE
activate 2 features useful for test - RANDOM_UUID - PARTITION_TYPE_GUID
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com ---
Changes in v2: None
configs/sandbox_defconfig | 2 ++ include/configs/sandbox.h | 7 +++++++ 2 files changed, 9 insertions(+)
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 380d4fe..1ba8d2a 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -5,6 +5,7 @@ CONFIG_FIT=y CONFIG_FIT_VERBOSE=y CONFIG_FIT_SIGNATURE=y CONFIG_SPL_LOAD_FIT=y +CONFIG_EFI_PARTITION_MTD=y CONFIG_BOOTSTAGE=y CONFIG_BOOTSTAGE_REPORT=y CONFIG_BOOTSTAGE_USER_COUNT=0x20 @@ -110,6 +111,7 @@ CONFIG_SPI_FLASH_SPANSION=y CONFIG_SPI_FLASH_STMICRO=y CONFIG_SPI_FLASH_SST=y CONFIG_SPI_FLASH_WINBOND=y +CONFIG_SPI_FLASH_MTD=y CONFIG_DM_ETH=y CONFIG_PCI=y CONFIG_DM_PCI=y diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 2daf02d..66707e3 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -49,13 +49,20 @@ #define CONFIG_CMD_MD5SUM
#define CONFIG_CMD_GPT +#define CONFIG_RANDOM_UUID #define CONFIG_PARTITION_UUIDS +#define CONFIG_PARTITION_TYPE_GUID #define CONFIG_AMIGA_PARTITION #define CONFIG_DOS_PARTITION #define CONFIG_EFI_PARTITION #define CONFIG_ISO_PARTITION #define CONFIG_MAC_PARTITION
+/* Dynamic MTD partition support */ +#define CONFIG_CMD_MTDPARTS +#define CONFIG_MTD_PARTITIONS +#define CONFIG_MTD_DEVICE + /* * Size of malloc() pool, before and after relocation */

On 30 November 2016 at 04:01, Patrick Delaunay patrick.delaunay73@gmail.com wrote:
From: Patrick Delaunay patrick.delaunay@st.com
activate needed feature in sandbox to allow test GPT over MTD
- EFI_PARTITION_MTD
- SPI_FLASH_MTD
- CMD_MTDPARTS
- MTD_PARTITIONS
- MTD_DEVICE
activate 2 features useful for test
- RANDOM_UUID
- PARTITION_TYPE_GUID
Signed-off-by: Patrick Delaunay patrick.delaunay@st.com Signed-off-by: Patrick Delaunay patrick.delaunay73@gmail.com
Changes in v2: None
configs/sandbox_defconfig | 2 ++ include/configs/sandbox.h | 7 +++++++ 2 files changed, 9 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
participants (2)
-
Patrick Delaunay
-
Simon Glass