[PATCH 0/6] cmd: gpt: GPT manipulation improvements

Adds several improvements and additions to the gpt command processing, specifically (although not exclusively) for the purpose of supporting "ping-pong" booting when doing A/B boot partitions with u-boot itself.
In this mechanism, u-boot must boot up, and then check if the correct boot partition is active, and if not switch the GPT partition table to the other boot partition and reboot to activate the other u-boot.
In order to facilitate this, the gpt command needs to be better at preserving entry attributes when manipulating the partition table. It also learns two new commands, one which can swap the order of partitions in the table, and another that lets it change which partitions have the bootable flag.
Joshua Watt (6): cmd: gpt: Remove confusing help text cmd: gpt: Add command to set bootable flags cmd: gpt: Add gpt_partition_bootable variable cmd: gpt: Preserve type GUID if enabled cmd: gpt: Preserve bootable flag cmd: gpt: Add command to swap partition order
cmd/gpt.c | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 154 insertions(+), 6 deletions(-)

This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 007a68eaa7..e6f7b0319a 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -1060,8 +1060,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt_partition_name, gpt_partition_entry\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" - " read <interface> <dev>\n" - " - read GPT into a data structure for manipulation\n" " gpt guid <interface> <dev>\n" " - print disk GUID\n" " gpt guid <interface> <dev> <varname>\n"

On Tue, Aug 15, 2023 at 10:26:55AM -0600, Joshua Watt wrote:
This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
Reviewed-by: Tom Rini trini@konsulko.com

On Tue, 15 Aug 2023 at 10:28, Joshua Watt jpewhacker@gmail.com wrote:
This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index e6f7b0319a..a4b8b2b286 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -970,6 +970,80 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, } #endif
+/** + * gpt_set_bootable() - Set bootable flags for partitions + * + * Sets the bootable flag for any partition names in the comma separated list of + * partition names. Any partitions not in the list have their bootable flag + * cleared + * + * @desc: block device descriptor + * @name: Comma separated list of partition names + * + * @Return: '0' on success and -ve error on failure + */ +static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) +{ + char *name; + char disk_guid[UUID_STR_LEN + 1]; + struct list_head *pos; + struct disk_part *curr; + struct disk_partition *partitions = NULL; + int part_count = 0; + + int ret = get_disk_guid(blk_dev_desc, disk_guid); + if (ret < 0) + return ret; + + ret = get_gpt_info(blk_dev_desc); + if (ret <= 0) + goto out; + + part_count = ret; + partitions = malloc(sizeof(*partitions) * part_count); + if (!partitions) { + ret = -ENOMEM; + goto out; + } + + /* Copy partitions and clear bootable flag */ + part_count = 0; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + partitions[part_count] = curr->gpt_part_info; + partitions[part_count].bootable &= ~PART_BOOTABLE; + part_count++; + } + + name = strtok(part_list, ","); + while (name) { + bool found = false; + for (int i = 0; i < part_count; i++) { + if (strcmp((char *)partitions[i].name, name) == 0) { + partitions[i].bootable |= PART_BOOTABLE; + found = true; + } + } + + if (!found) { + printf("Warning: No partition matching '%s' found\n", + name); + } + + name = strtok(NULL, ","); + } + + ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count); + +out: + del_gpt_info(); + + if (partitions) + free(partitions); + + return ret; +} + /** * do_gpt(): Perform GPT operations * @@ -1028,6 +1102,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); #endif + } else if ((strcmp(argv[1], "set-bootable") == 0)) { + ret = gpt_set_bootable(blk_dev_desc, argv[4]); } else { return CMD_RET_USAGE; } @@ -1081,4 +1157,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" #endif + " gpt set-bootable <interface> <dev> <list>\n" + " - make partition names in list bootable\n" + " Example usage:\n" + " gpt set-bootable mmc 0 boot_a,boot_b\n" );

Hi Joshua,
On Tue, 15 Aug 2023 at 10:28, Joshua Watt jpewhacker@gmail.com wrote:
Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+)
Can you add doc/usage/gpt.rst and a test?
Regards, Simon

Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index a4b8b2b286..bc08799512 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -723,7 +723,7 @@ static int gpt_enumerate(struct blk_desc *desc) * gpt_setenv_part_variables() - setup partition environmental variables * * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr - * and gpt_partition_size environment variables. + * and gpt_partition_size, gpt_partition_bootable environment variables. * * @pinfo: pointer to disk partition * @i: partition entry @@ -750,6 +750,10 @@ static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) if (ret) goto fail;
+ ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE)); + if (ret) + goto fail; + return 0;
fail: @@ -1133,7 +1137,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt setenv mmc 0 $name\n" " - setup environment variables for partition $name:\n" " gpt_partition_addr, gpt_partition_size,\n" - " gpt_partition_name, gpt_partition_entry\n" + " gpt_partition_name, gpt_partition_entry,\n" + " gpt_partition_bootable\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" " gpt guid <interface> <dev>\n"

If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index bc08799512..c6fbd94ba2 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID + partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); +#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID + strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid, + UUID_STR_LEN); + newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0'; +#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID + printf("Type GUID %s\n", curr->gpt_part_info.type_guid); +#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID + strcat(partitions_list, ",type="); + strncat(partitions_list, curr->gpt_part_info.type_guid, + UUID_STR_LEN + 1); +#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1);

Sets the bootable flag when constructing the partition string from the current partition configuration. This ensures that when the partitions are written back (for example, when renaming a partition), the flag is preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index c6fbd94ba2..58564436d3 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -176,6 +176,7 @@ static int calc_parts_list_len(int numparts) #ifdef CONFIG_PARTITION_TYPE_GUID partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); #endif + partlistlen += numparts * strlen("bootable,"); partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -318,6 +319,8 @@ static int create_gpt_partitions_list(int numparts, const char *guid, strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); + if (curr->gpt_part_info.bootable & PART_BOOTABLE) + strcat(partitions_list, ",bootable"); strcat(partitions_list, ";"); } return 0;

Adds a command called "gpt swap-postition" which will swap the order two partitions are listed in the GPT partition table (but leaves them pointing to the same locations on disk).
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 58564436d3..c8a2b5ae7b 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -859,7 +859,7 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || - (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) + (strcmp(subcomm, "swap") && strcmp(subcomm, "rename") && strcmp(subcomm, "swap-position"))) return -EINVAL;
ret = get_disk_guid(dev_desc, disk_guid); @@ -920,6 +920,48 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; } + } else if(!strcmp(subcomm, "swap-position")) { + int idx1, idx2; + struct disk_partition first, second; + idx1 = simple_strtoul(name1, NULL, 10); + if (idx1 <= 0 || idx1 > numparts) { + printf("Illegal partition number %s\n", name1); + ret = -EINVAL; + goto out; + } + idx2 = simple_strtoul(name2, NULL, 10); + if (idx2 <= 0 || idx2 > numparts) { + printf("Illegal partition number %s\n", name2); + ret = -EINVAL; + goto out; + } + if (idx1 == idx2) { + printf("Cannot swap partition with itself\n"); + ret = -EINVAL; + goto out; + } + + i = 1; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (i == idx1) { + first = curr->gpt_part_info; + } else if (i == idx2) { + second = curr->gpt_part_info; + } + i++; + } + + i = 1; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (i == idx1) { + curr->gpt_part_info = second; + } else if (i == idx2) { + curr->gpt_part_info = first; + } + i++; + } } else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); @@ -1122,7 +1164,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) || - (strcmp(argv[1], "rename") == 0)) { + (strcmp(argv[1], "rename") == 0) || + (strcmp(argv[1], "swap-position") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); #endif } else if ((strcmp(argv[1], "set-bootable") == 0)) { @@ -1175,11 +1218,14 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n" + " gpt swap-position <interface> <dev> <part1> <part2>\n" + " - Swap the order of name1 with name2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" + " gpt swap-partitions mmc 0 1 2\n" #endif " gpt set-bootable <interface> <dev> <list>\n" " - make partition names in list bootable\n"

Hi Joshua,
On Tue, 15 Aug 2023 at 10:28, Joshua Watt jpewhacker@gmail.com wrote:
Adds a command called "gpt swap-postition" which will swap the order two partitions are listed in the GPT partition table (but leaves them pointing to the same locations on disk).
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 58564436d3..c8a2b5ae7b 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -859,7 +859,7 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
(strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
(strcmp(subcomm, "swap") && strcmp(subcomm, "rename") && strcmp(subcomm, "swap-position")))
While you are here you could tidy this code:
if (!subcomm || !name1 || !name2 || ...
return -EINVAL; ret = get_disk_guid(dev_desc, disk_guid);
@@ -920,6 +920,48 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; }
} else if(!strcmp(subcomm, "swap-position")) {
int idx1, idx2;
struct disk_partition first, second;
blank line
idx1 = simple_strtoul(name1, NULL, 10);
if (idx1 <= 0 || idx1 > numparts) {
printf("Illegal partition number %s\n", name1);
ret = -EINVAL;
goto out;
}
idx2 = simple_strtoul(name2, NULL, 10);
if (idx2 <= 0 || idx2 > numparts) {
printf("Illegal partition number %s\n", name2);
ret = -EINVAL;
goto out;
}
if (idx1 == idx2) {
printf("Cannot swap partition with itself\n");
ret = -EINVAL;
goto out;
}
i = 1;
list_for_each(pos, &disk_partitions) {
curr = list_entry(pos, struct disk_part, list);
if (i == idx1) {
first = curr->gpt_part_info;
} else if (i == idx2) {
second = curr->gpt_part_info;
}
Can you please either use patman or manually checkpatch on your patches? This should not have {}
i++;
}
i = 1;
list_for_each(pos, &disk_partitions) {
curr = list_entry(pos, struct disk_part, list);
if (i == idx1) {
curr->gpt_part_info = second;
} else if (i == idx2) {
curr->gpt_part_info = first;
}
i++;
} } else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
@@ -1122,7 +1164,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) ||
(strcmp(argv[1], "rename") == 0)) {
(strcmp(argv[1], "rename") == 0) ||
(strcmp(argv[1], "swap-position") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
#endif } else if ((strcmp(argv[1], "set-bootable") == 0)) { @@ -1175,11 +1218,14 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n"
" gpt swap-position <interface> <dev> <part1> <part2>\n"
" - Swap the order of name1 with name2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n"
" gpt swap-partitions mmc 0 1 2\n"
#endif " gpt set-bootable <interface> <dev> <list>\n" " - make partition names in list bootable\n" -- 2.33.0
Regards, Simon

Adds several improvements and additions to the gpt command processing, specifically (although not exclusively) for the purpose of supporting "ping-pong" booting when doing A/B boot partitions with u-boot itself.
In this mechanism, u-boot must boot up, and then check if the correct boot partition is active, and if not switch the GPT partition table to the other boot partition and reboot to activate the other u-boot.
In order to facilitate this, the gpt command needs to be better at preserving entry attributes when manipulating the partition table. It also learns two new commands, one which can swap the order of partitions in the table, and another that lets it change which partitions have the bootable flag.
V2: Add documentation and tests
Joshua Watt (8): cmd: gpt: Remove confusing help text doc: Add gpt command documentation tests: gpt: Remove test order dependency cmd: gpt: Add gpt_partition_bootable variable cmd: gpt: Add command to set bootable flags cmd: gpt: Preserve type GUID if enabled cmd: gpt: Preserve bootable flag cmd: gpt: Add command to swap partition order
cmd/gpt.c | 159 ++++++++++++++++++++++++++++++++-- doc/usage/cmd/gpt.rst | 174 ++++++++++++++++++++++++++++++++++++++ test/py/tests/test_gpt.py | 151 ++++++++++++++++++++++++++++++--- 3 files changed, 466 insertions(+), 18 deletions(-) create mode 100644 doc/usage/cmd/gpt.rst

This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 007a68eaa7..e6f7b0319a 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -1060,8 +1060,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt_partition_name, gpt_partition_entry\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" - " read <interface> <dev>\n" - " - read GPT into a data structure for manipulation\n" " gpt guid <interface> <dev>\n" " - print disk GUID\n" " gpt guid <interface> <dev> <varname>\n"

On Wed, Aug 23, 2023 at 10:47:37AM -0600, Joshua Watt wrote:
This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
Reviewed-by: Tom Rini trini@konsulko.com

Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- doc/usage/cmd/gpt.rst | 139 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..ea2cf73a60 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,139 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +gpt command +=========== + +Synopsis +-------- + +:: + + gpt repair <interface> <device no> + gpt write <interface> <device no> <partition string> + gpt verify <interface> <device no> <partition string> + gpt setenv <interface> <device no> <partition name> + gpt enumerate <interface> <device no> + gpt guid <interface> <device no> [<varname>] + gpt read <interface> <device no> [<varname>] + gpt swap <interface> <dev> <name1> <name2> + gpt rename <interface> <dev> <part> <name> + +Description +----------- + +The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout. + +The syntax of the text description of the partition list is similar to +the one used by the 'mbr' command. + +The partition list may start with a set of parameters for the whole disk: + +* uuid_disk (the UUID of the disk) + +Following the disk parameters, partitions are specified separated by a ';'. +Supported partition parameters are: + +* name (required) +* start (required, partition start offset in bytes) +* size (in bytes or '-' to expand it to the whole free area) +* bootable (boolean flag) +* uuid (partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled) +* type (partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y) + +Here is an example how to create a 6 partitions, some of the predefined sizes: + +:: + + => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7; + name=boot,start=4M,size=128M,bootable,type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7, + name=rootfs,size=3072M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4; + name=system-data,size=512M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4; + name=[ext],size=-,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4; + name=user,size=-,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4; + name=modules,size=100M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4; + name=ramdisk,size=8M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4 + => gpt write mmc 0 $gpt_parts + + +If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition + +The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command: + +:: + + => gpt verify mmc 0 $gpt_parts + +The verify sub-command is especially useful in the system update scripts: + +:: + + => if gpt verify mmc 0 $gpt_parts; then + echo GPT layout needs to be updated + ... + fi + +The 'gpt write' command returns 0 on success write or 1 on failure. + +The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are: + +* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks) +* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.) + +To get the information about the partition named 'rootfs', issue the following +command: + +:: + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_addr} + 2000 + => echo ${gpt_partition_size} + 14a000 + => echo ${gpt_partition_name} + rootfs + => echo ${gpt_partition_entry} + 2 + +The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example: + +:: + => gpt enumerate + => echo gpt_partition_list + boot rootfs system-data [ext] user modules ramdisk + +The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example: + +:: + => gpt guid mmc 0 + bec9fc2a-86c1-483d-8a0e-0109732277d7 + => gpt guid mmc gpt_disk_uuid + => echo ${gpt_disk_uuid} + bec9fc2a-86c1-483d-8a0e-0109732277d7 + +The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required. + +The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required. + +The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required. + +Configuration +------------- + +To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y.

On Wed, Aug 23, 2023 at 10:47:38AM -0600, Joshua Watt wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 139 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
You need to update the index too so it's included (and doesn't trigger an error about orphan files). Please do a 'make htmldocs' to make sure everything else is clean, thanks.

Hi Joshua,
On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 139 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..ea2cf73a60 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,139 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt repair <interface> <device no>
- gpt write <interface> <device no> <partition string>
- gpt verify <interface> <device no> <partition string>
- gpt setenv <interface> <device no> <partition name>
- gpt enumerate <interface> <device no>
- gpt guid <interface> <device no> [<varname>]
- gpt read <interface> <device no> [<varname>]
- gpt swap <interface> <dev> <name1> <name2>
- gpt rename <interface> <dev> <part> <name>
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+The syntax of the text description of the partition list is similar to
By 'text description' do you mean '<partition string>' ?
+the one used by the 'mbr' command.
OK, but I think you need to show the string as a list of semicolon-separated components (or whatever) and then describe them. As written, this is quite confusing.
+The partition list may start with a set of parameters for the whole disk:
+* uuid_disk (the UUID of the disk)
+Following the disk parameters, partitions are specified separated by a ';'. +Supported partition parameters are:
+* name (required) +* start (required, partition start offset in bytes) +* size (in bytes or '-' to expand it to the whole free area) +* bootable (boolean flag) +* uuid (partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled) +* type (partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y)
+Here is an example how to create a 6 partitions, some of the predefined sizes:
+::
- => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=EBD0A0A2-B9E5-4433-87C0-68B6B72699C7,
name=rootfs,size=3072M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;
name=system-data,size=512M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;
name=[ext],size=-,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;
name=user,size=-,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;
name=modules,size=100M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;
name=ramdisk,size=8M,type=0FC63DAF-8483-4772-8E79-3D69D8477DE4
- => gpt write mmc 0 $gpt_parts
Please use lower-case hex
+If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition
+The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command:
+::
- => gpt verify mmc 0 $gpt_parts
+The verify sub-command is especially useful in the system update scripts:
+::
- => if gpt verify mmc 0 $gpt_parts; then
echo GPT layout needs to be updated
...
fi
+The 'gpt write' command returns 0 on success write or 1 on failure.
+The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are:
+* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks) +* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.)
+To get the information about the partition named 'rootfs', issue the following +command:
+::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example:
+::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
+The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example:
+::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
+The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+Configuration +-------------
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt
+read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y.
2.33.0
Great docs thank you!
- Simon

Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- test/py/tests/test_gpt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 73bfbf77a2..339468bc12 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -61,18 +61,14 @@ class GptTestDiskImage(object): cmd = ('cp', persistent, self.path) u_boot_utils.run_and_log(u_boot_console, cmd)
-gtdi = None @pytest.fixture(scope='function') def state_disk_image(u_boot_console): """pytest fixture to provide a GptTestDiskImage object to tests. This is function-scoped because it uses u_boot_console, which is also - function-scoped. However, we don't need to actually do any function-scope - work, so this simply returns the same object over and over each time.""" + function-scoped. A new disk is returned each time to prevent tests from + interfering with each other."""
- global gtdi - if not gtdi: - gtdi = GptTestDiskImage(u_boot_console) - return gtdi + return GptTestDiskImage(u_boot_console)
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @@ -186,12 +182,12 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console):
u_boot_console.run_command('host bind 0 ' + state_disk_image.path) output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "first"' in output - assert '0x00001000 0x00001bff "second"' in output - u_boot_console.run_command('gpt swap host 0 first second') + assert '0x00000800 0x00000fff "part1"' in output + assert '0x00001000 0x00001bff "part2"' in output + u_boot_console.run_command('gpt swap host 0 part1 part2') output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "second"' in output - assert '0x00001000 0x00001bff "first"' in output + assert '0x00000800 0x00000fff "part2"' in output + assert '0x00001000 0x00001bff "part1"' in output
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt')

Hi Joshua,
On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
test/py/tests/test_gpt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
I suppose this is OK, but is it expensive in terms of time?
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

On Wed, Aug 23, 2023 at 5:59 PM Simon Glass sjg@chromium.org wrote:
Hi Joshua,
On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
test/py/tests/test_gpt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
I suppose this is OK, but is it expensive in terms of time?
There wasn't a noticeable slowdown in test execution time on my (admittedly powerful) workstation.
Reviewed-by: Simon Glass sjg@chromium.org
Regards, Simon

Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 9 +++++++-- doc/usage/cmd/gpt.rst | 3 +++ test/py/tests/test_gpt.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index e6f7b0319a..7a8990e400 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -723,7 +723,7 @@ static int gpt_enumerate(struct blk_desc *desc) * gpt_setenv_part_variables() - setup partition environmental variables * * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr - * and gpt_partition_size environment variables. + * and gpt_partition_size, gpt_partition_bootable environment variables. * * @pinfo: pointer to disk partition * @i: partition entry @@ -750,6 +750,10 @@ static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) if (ret) goto fail;
+ ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE)); + if (ret) + goto fail; + return 0;
fail: @@ -1057,7 +1061,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt setenv mmc 0 $name\n" " - setup environment variables for partition $name:\n" " gpt_partition_addr, gpt_partition_size,\n" - " gpt_partition_name, gpt_partition_entry\n" + " gpt_partition_name, gpt_partition_entry,\n" + " gpt_partition_bootable\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" " gpt guid <interface> <dev>\n" diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index ea2cf73a60..c9d15b2cba 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -85,6 +85,7 @@ information about a particular partition. The variables are: * gpt_partition_size (the size of the partition, in hexadecimal blocks) * gpt_partition_name (the name of the partition) * gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.) +* gpt_partition_bootable (1 if the partition is marked as bootable, 0 if not)
To get the information about the partition named 'rootfs', issue the following command: @@ -99,6 +100,8 @@ command: rootfs => echo ${gpt_partition_entry} 2 + => echo ${gpt_partition_bootable} + 0
The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the list of partition names on the device. For example: diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 339468bc12..1537ceb8c8 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -49,6 +49,7 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) @@ -117,6 +118,38 @@ def test_gpt_guid(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_setenv(state_disk_image, u_boot_console): + """Test the gpt setenv command.""" + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt setenv host 0 part1') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part1' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == "1" + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == "1" + + output = u_boot_console.run_command('gpt setenv host 0 part2') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '1000' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == 'c00' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part2' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == "2" + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == "0" + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')

Hi Joshue,
On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 9 +++++++-- doc/usage/cmd/gpt.rst | 3 +++ test/py/tests/test_gpt.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index e6f7b0319a..7a8990e400 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -723,7 +723,7 @@ static int gpt_enumerate(struct blk_desc *desc)
- gpt_setenv_part_variables() - setup partition environmental variables
- Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr
- and gpt_partition_size environment variables.
- and gpt_partition_size, gpt_partition_bootable environment variables.
- @pinfo: pointer to disk partition
- @i: partition entry
@@ -750,6 +750,10 @@ static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) if (ret) goto fail;
ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE));
if (ret)
goto fail;
return 0;
fail: @@ -1057,7 +1061,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt setenv mmc 0 $name\n" " - setup environment variables for partition $name:\n" " gpt_partition_addr, gpt_partition_size,\n"
" gpt_partition_name, gpt_partition_entry\n"
" gpt_partition_name, gpt_partition_entry,\n"
" gpt_partition_bootable\n"
Please use single quotes except for the """ for function headers.
" gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" " gpt guid <interface> <dev>\n"
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index ea2cf73a60..c9d15b2cba 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -85,6 +85,7 @@ information about a particular partition. The variables are:
- gpt_partition_size (the size of the partition, in hexadecimal blocks)
- gpt_partition_name (the name of the partition)
- gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.)
+* gpt_partition_bootable (1 if the partition is marked as bootable, 0 if not)
To get the information about the partition named 'rootfs', issue the following command: @@ -99,6 +100,8 @@ command: rootfs => echo ${gpt_partition_entry} 2
- => echo ${gpt_partition_bootable}
- 0
The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the list of partition names on the device. For example: diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 339468bc12..1537ceb8c8 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -49,6 +49,7 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1',
'-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd)
@@ -117,6 +118,38 @@ def test_gpt_guid(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_setenv(state_disk_image, u_boot_console):
- """Test the gpt setenv command."""
- u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
- output = u_boot_console.run_command('gpt setenv host 0 part1')
- assert 'success!' in output
- output = u_boot_console.run_command('echo ${gpt_partition_addr}')
- assert output.rstrip() == '800'
- output = u_boot_console.run_command('echo ${gpt_partition_size}')
- assert output.rstrip() == '800'
- output = u_boot_console.run_command('echo ${gpt_partition_name}')
- assert output.rstrip() == 'part1'
- output = u_boot_console.run_command('echo ${gpt_partition_entry}')
- assert output.rstrip() == "1"
- output = u_boot_console.run_command('echo ${gpt_partition_bootable}')
- assert output.rstrip() == "1"
- output = u_boot_console.run_command('gpt setenv host 0 part2')
- assert 'success!' in output
- output = u_boot_console.run_command('echo ${gpt_partition_addr}')
- assert output.rstrip() == '1000'
- output = u_boot_console.run_command('echo ${gpt_partition_size}')
- assert output.rstrip() == 'c00'
- output = u_boot_console.run_command('echo ${gpt_partition_name}')
- assert output.rstrip() == 'part2'
- output = u_boot_console.run_command('echo ${gpt_partition_entry}')
- assert output.rstrip() == "2"
- output = u_boot_console.run_command('echo ${gpt_partition_bootable}')
- assert output.rstrip() == "0"
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk') -- 2.33.0
Regards, Simon

Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 79 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 9 +++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 110 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 7a8990e400..70a01f7da1 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -972,6 +972,80 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, free(partitions_list); return ret; } + +/** + * gpt_set_bootable() - Set bootable flags for partitions + * + * Sets the bootable flag for any partition names in the comma separated list of + * partition names. Any partitions not in the list have their bootable flag + * cleared + * + * @desc: block device descriptor + * @name: Comma separated list of partition names + * + * @Return: '0' on success and -ve error on failure + */ +static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) +{ + char *name; + char disk_guid[UUID_STR_LEN + 1]; + struct list_head *pos; + struct disk_part *curr; + struct disk_partition *partitions = NULL; + int part_count = 0; + + int ret = get_disk_guid(blk_dev_desc, disk_guid); + if (ret < 0) + return ret; + + ret = get_gpt_info(blk_dev_desc); + if (ret <= 0) + goto out; + + part_count = ret; + partitions = malloc(sizeof(*partitions) * part_count); + if (!partitions) { + ret = -ENOMEM; + goto out; + } + + /* Copy partitions and clear bootable flag */ + part_count = 0; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + partitions[part_count] = curr->gpt_part_info; + partitions[part_count].bootable &= ~PART_BOOTABLE; + part_count++; + } + + name = strtok(part_list, ","); + while (name) { + bool found = false; + for (int i = 0; i < part_count; i++) { + if (strcmp((char *)partitions[i].name, name) == 0) { + partitions[i].bootable |= PART_BOOTABLE; + found = true; + } + } + + if (!found) { + printf("Warning: No partition matching '%s' found\n", + name); + } + + name = strtok(NULL, ","); + } + + ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count); + +out: + del_gpt_info(); + + if (partitions) + free(partitions); + + return ret; +} #endif
/** @@ -1031,6 +1105,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if ((strcmp(argv[1], "swap") == 0) || (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); + } else if ((strcmp(argv[1], "set-bootable") == 0)) { + ret = gpt_set_bootable(blk_dev_desc, argv[4]); #endif } else { return CMD_RET_USAGE; @@ -1082,8 +1158,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " and vice-versa\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" + " gpt set-bootable <interface> <dev> <list>\n" + " - make partition names in list bootable\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" + " gpt set-bootable mmc 0 boot_a,boot_b\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index c9d15b2cba..c7a56ad825 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -17,6 +17,7 @@ Synopsis gpt read <interface> <device no> [<varname>] gpt swap <interface> <dev> <name1> <name2> gpt rename <interface> <dev> <part> <name> + gpt set-bootable <interface> <dev> <partition list>
Description ----------- @@ -135,6 +136,14 @@ CONFIG_CMD_GPT_RENAME=y is required. The 'gpt rename' command renames all partitions named 'part' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt set-bootable' command sets the bootable flag for all partitions in the +table. If the partition name is in 'partition list' (separated by ','), the +bootable flag is set, otherwise it is cleared. CONFIG_CMD_GPT_RENAME=y is +required. For example, to mark only the 'boot' partition as bootable: + +:: + => gpt set-bootable mmc 0 boot + Configuration -------------
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 1537ceb8c8..8203515e05 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -222,6 +222,28 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part2"' in output assert '0x00001000 0x00001bff "part1"' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_set_bootable(state_disk_image, u_boot_console): + """Test the gpt set-bootable command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + parts = ('part2', 'part1') + for bootable in parts: + output = u_boot_console.run_command(f'gpt set-bootable host 0 {bootable}') + assert 'success!' in output + + for p in parts: + output = u_boot_console.run_command(f'gpt setenv host 0 {p}') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + if p == bootable: + assert output.rstrip() == '1' + else: + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.buildconfigspec('cmd_part')

On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 79 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 9 +++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 110 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 16 +++++++++++ test/py/tests/test_gpt.py | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 70a01f7da1..fdd9c429f6 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID + partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); +#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID + strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid, + UUID_STR_LEN); + newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0'; +#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID + printf("Type GUID %s\n", curr->gpt_part_info.type_guid); +#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID + strcat(partitions_list, ",type="); + strncat(partitions_list, curr->gpt_part_info.type_guid, + UUID_STR_LEN + 1); +#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 8203515e05..f9351f0274 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -16,6 +16,26 @@ the test. # Mark all tests here as slow pytestmark = pytest.mark.slow
+def parse_gpt_parts(s): + """Part a partition string into a list of partitions""" + parts = [] + for part_str in s.split(';'): + part = {} + for option in part_str.split(","): + if not option: + continue + + if "=" in option: + k, v = option.split("=") + part[k] = v + else: + part[option] = True + + if part: + parts.append(part) + + return parts + class GptTestDiskImage(object): """Disk Image used by the GPT tests."""
@@ -49,11 +69,13 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2', + '--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', persistent) u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--load-backup=' + persistent) @@ -88,6 +110,40 @@ def test_gpt_read(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part1"' in output assert '0x00001000 0x00001bff "part2"' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('partition_type_guid') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_read_var(state_disk_image, u_boot_console): + """Test the gpt read command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt read host 0 gpt_parts') + assert 'success!' in output + + output = u_boot_console.run_command('echo ${gpt_parts}') + parts = parse_gpt_parts(output.rstrip()) + + assert parts == [ + { + "uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe", + }, + { + "name": "part1", + "start": "0x100000", + "size": "0x100000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + }, + { + "name": "part2", + "start": "0x200000", + "size": "0x180000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb", + }, + ] + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk') @@ -263,3 +319,4 @@ def test_gpt_write(state_disk_image, u_boot_console): assert '0x00001000 0x00001bff "second"' in output output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output +

Hi Joshua,
On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 16 +++++++++++ test/py/tests/test_gpt.py | 57 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 70a01f7da1..fdd9c429f6 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID
partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1);
+#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID
strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid,
UUID_STR_LEN);
newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0';
+#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID
printf("Type GUID %s\n", curr->gpt_part_info.type_guid);
+#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID
strcat(partitions_list, ",type=");
strncat(partitions_list, curr->gpt_part_info.type_guid,
UUID_STR_LEN + 1);
+#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 8203515e05..f9351f0274 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -16,6 +16,26 @@ the test. # Mark all tests here as slow pytestmark = pytest.mark.slow
+def parse_gpt_parts(s):
- """Part a partition string into a list of partitions"""
Please remember to fully comment functions, including arg and return value.
Also 's' can be used in loops but not as a var or param. I think we need to use 3 chars or more.
- parts = []
- for part_str in s.split(';'):
part = {}
for option in part_str.split(","):
if not option:
continue
if "=" in option:
k, v = option.split("=")
part[k] = v
else:
part[option] = True
if part:
parts.append(part)
- return parts
class GptTestDiskImage(object): """Disk Image used by the GPT tests."""
@@ -49,11 +69,13 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1',
'--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2',
'--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', persistent) u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--load-backup=' + persistent)
@@ -88,6 +110,40 @@ def test_gpt_read(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part1"' in output assert '0x00001000 0x00001bff "part2"' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('partition_type_guid') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_read_var(state_disk_image, u_boot_console):
- """Test the gpt read command."""
- u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
- output = u_boot_console.run_command('gpt read host 0 gpt_parts')
- assert 'success!' in output
- output = u_boot_console.run_command('echo ${gpt_parts}')
- parts = parse_gpt_parts(output.rstrip())
- assert parts == [
{
"uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe",
},
{
"name": "part1",
single quotes
"start": "0x100000",
"size": "0x100000",
"type": "0fc63daf-8483-4772-8e79-3d69d8477de4",
"uuid": "33194895-67f6-4561-8457-6fdeed4f50a3",
},
{
"name": "part2",
"start": "0x200000",
"size": "0x180000",
"type": "0fc63daf-8483-4772-8e79-3d69d8477de4",
"uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb",
},
- ]
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk') @@ -263,3 +319,4 @@ def test_gpt_write(state_disk_image, u_boot_console): assert '0x00001000 0x00001bff "second"' in output output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
-- 2.33.0
Regards, Simon

Sets the bootable flag when constructing the partition string from the current partition configuration. This ensures that when the partitions are written back (for example, when renaming a partition), the flag is preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 3 +++ test/py/tests/test_gpt.py | 1 + 2 files changed, 4 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index fdd9c429f6..90a60fce8b 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -176,6 +176,7 @@ static int calc_parts_list_len(int numparts) #ifdef CONFIG_PARTITION_TYPE_GUID partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); #endif + partlistlen += numparts * strlen("bootable,"); partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -318,6 +319,8 @@ static int create_gpt_partitions_list(int numparts, const char *guid, strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); + if (curr->gpt_part_info.bootable & PART_BOOTABLE) + strcat(partitions_list, ",bootable"); strcat(partitions_list, ";"); } return 0; diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index f9351f0274..6d79d07b09 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -134,6 +134,7 @@ def test_gpt_read_var(state_disk_image, u_boot_console): "size": "0x100000", "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + "bootable": True, }, { "name": "part2",

On Wed, 23 Aug 2023 at 10:48, Joshua Watt jpewhacker@gmail.com wrote:
Sets the bootable flag when constructing the partition string from the current partition configuration. This ensures that when the partitions are written back (for example, when renaming a partition), the flag is preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 3 +++ test/py/tests/test_gpt.py | 1 + 2 files changed, 4 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

Adds a command called "gpt swap-postition" which will swap the order two partitions are listed in the GPT partition table (but leaves them pointing to the same locations on disk).
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 50 +++++++++++++++++++++++++++++++++++++-- doc/usage/cmd/gpt.rst | 23 ++++++++++++++++++ test/py/tests/test_gpt.py | 18 ++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 90a60fce8b..2448889573 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -859,7 +859,7 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || - (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) + (strcmp(subcomm, "swap") && strcmp(subcomm, "rename") && strcmp(subcomm, "swap-position"))) return -EINVAL;
ret = get_disk_guid(dev_desc, disk_guid); @@ -920,6 +920,48 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; } + } else if(!strcmp(subcomm, "swap-position")) { + int idx1, idx2; + struct disk_partition first, second; + idx1 = simple_strtoul(name1, NULL, 10); + if (idx1 <= 0 || idx1 > numparts) { + printf("Illegal partition number %s\n", name1); + ret = -EINVAL; + goto out; + } + idx2 = simple_strtoul(name2, NULL, 10); + if (idx2 <= 0 || idx2 > numparts) { + printf("Illegal partition number %s\n", name2); + ret = -EINVAL; + goto out; + } + if (idx1 == idx2) { + printf("Cannot swap partition with itself\n"); + ret = -EINVAL; + goto out; + } + + i = 1; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (i == idx1) { + first = curr->gpt_part_info; + } else if (i == idx2) { + second = curr->gpt_part_info; + } + i++; + } + + i = 1; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (i == idx1) { + curr->gpt_part_info = second; + } else if (i == idx2) { + curr->gpt_part_info = first; + } + i++; + } } else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); @@ -1122,7 +1164,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) || - (strcmp(argv[1], "rename") == 0)) { + (strcmp(argv[1], "rename") == 0) || + (strcmp(argv[1], "swap-position") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); } else if ((strcmp(argv[1], "set-bootable") == 0)) { ret = gpt_set_bootable(blk_dev_desc, argv[4]); @@ -1175,6 +1218,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n" + " gpt swap-position <interface> <dev> <part1> <part2>\n" + " - Swap the order of name1 with name2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " gpt set-bootable <interface> <dev> <list>\n" @@ -1183,5 +1228,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" " gpt set-bootable mmc 0 boot_a,boot_b\n" + " gpt swap-position mmc 0 1 2\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index c7a56ad825..f3f778d383 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -17,6 +17,7 @@ Synopsis gpt read <interface> <device no> [<varname>] gpt swap <interface> <dev> <name1> <name2> gpt rename <interface> <dev> <part> <name> + gpt swap-position <interface> <dev> <part1> <part2> gpt set-bootable <interface> <dev> <partition list>
Description @@ -136,6 +137,28 @@ CONFIG_CMD_GPT_RENAME=y is required. The 'gpt rename' command renames all partitions named 'part' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap-position' command swaps the order of two partition index in the +partition table, but otherwise leaves the actual partition data untouched. For +example, to swap the order of the 'boot' and 'rootfs' partitions in the disk +described above, you would do: + +:: + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 2 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 1 + + => gpt swap-position mmc 0 1 2 + + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 1 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 2 + The 'gpt set-bootable' command sets the bootable flag for all partitions in the table. If the partition name is in 'partition list' (separated by ','), the bootable flag is set, otherwise it is cleared. CONFIG_CMD_GPT_RENAME=y is diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 6d79d07b09..af25bcd998 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -321,3 +321,21 @@ def test_gpt_write(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_swap_position(state_disk_image, u_boot_console): + """Test the gpt swap-position command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('part list host 0') + assert '1\t0x00000800\t0x00000fff\t"part1"' in output + assert '2\t0x00001000\t0x00001bff\t"part2"' in output + + output = u_boot_console.run_command('gpt swap-position host 0 1 2') + assert 'success!' in output + + output = u_boot_console.run_command('part list host 0') + assert '2\t0x00000800\t0x00000fff\t"part1"' in output + assert '1\t0x00001000\t0x00001bff\t"part2"' in output

Adds several improvements and additions to the gpt command processing, specifically (although not exclusively) for the purpose of supporting "ping-pong" booting when doing A/B boot partitions with u-boot itself.
In this mechanism, u-boot must boot up, and then check if the correct boot partition is active, and if not switch the GPT partition table to the other boot partition and reboot to activate the other u-boot.
In order to facilitate this, the gpt command needs to be better at preserving entry attributes when manipulating the partition table. It also learns two new commands, one which can swap the order of partitions in the table, and another that lets it change which partitions have the bootable flag.
V2: Add documentation and tests V3: Review Feedback
Joshua Watt (8): cmd: gpt: Remove confusing help text doc: Add gpt command documentation tests: gpt: Remove test order dependency cmd: gpt: Add gpt_partition_bootable variable cmd: gpt: Add command to set bootable flags cmd: gpt: Preserve type GUID if enabled cmd: gpt: Preserve bootable flag cmd: gpt: Add command to swap partition order
cmd/gpt.c | 162 +++++++++++++++++++++++++++++++++-- doc/usage/cmd/gpt.rst | 176 ++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/py/tests/test_gpt.py | 160 +++++++++++++++++++++++++++++++--- 4 files changed, 480 insertions(+), 19 deletions(-) create mode 100644 doc/usage/cmd/gpt.rst

This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 007a68eaa7..e6f7b0319a 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -1060,8 +1060,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt_partition_name, gpt_partition_entry\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" - " read <interface> <dev>\n" - " - read GPT into a data structure for manipulation\n" " gpt guid <interface> <dev>\n" " - print disk GUID\n" " gpt guid <interface> <dev> <varname>\n"

Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..f6e082fb94 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +gpt command +=========== + +Synopsis +-------- + +:: + + gpt repair <interface> <device no> + gpt write <interface> <device no> <partition string> + gpt verify <interface> <device no> <partition string> + gpt setenv <interface> <device no> <partition name> + gpt enumerate <interface> <device no> + gpt guid <interface> <device no> [<varname>] + gpt read <interface> <device no> [<varname>] + gpt swap <interface> <dev> <name1> <name2> + gpt rename <interface> <dev> <part> <name> + +Description +----------- + +The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout. + +The syntax of the text description of the partition list is similar to +the one used by the 'mbr' command. The string contains one or more partition +descriptors, each separated by a ";". Each descriptor contains one or more +fields, with each field separated by a ",". Fields are either of the form +"key=value" to set a specific value, or simple "flag" to set a boolean flag + +The first descriptor can optionally be used to describe parameters for the +whole disk with the following fields: + +* uuid_disk=UUID - Set the UUID for the disk + +Partition descriptors can have the following fields: +* name=NAME - The partition name, required +* start=BYTES - The partition start offset in bytes, required +* size=BYTES - The partition size, in bytes or "-" to expand it to the whole free area +* bootable - Set the legacy bootable flag +* uuid=UUID - Set the partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled +* type=UUID - Set the partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y + +Here is an example how to create a 6 partitions, some of the predefined sizes: + +:: + + => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7; + name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7, + name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4 + => gpt write mmc 0 $gpt_parts + + +If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition + +The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command: + +:: + + => gpt verify mmc 0 $gpt_parts + +The verify sub-command is especially useful in the system update scripts: + +:: + + => if gpt verify mmc 0 $gpt_parts; then + echo GPT layout needs to be updated + ... + fi + +The 'gpt write' command returns 0 on success write or 1 on failure. + +The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are: + +* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks) +* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.) + +To get the information about the partition named 'rootfs', issue the following +command: + +:: + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_addr} + 2000 + => echo ${gpt_partition_size} + 14a000 + => echo ${gpt_partition_name} + rootfs + => echo ${gpt_partition_entry} + 2 + +The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example: + +:: + => gpt enumerate + => echo gpt_partition_list + boot rootfs system-data [ext] user modules ramdisk + +The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example: + +:: + => gpt guid mmc 0 + bec9fc2a-86c1-483d-8a0e-0109732277d7 + => gpt guid mmc gpt_disk_uuid + => echo ${gpt_disk_uuid} + bec9fc2a-86c1-483d-8a0e-0109732277d7 + +The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required. + +The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required. + +The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required. + +Configuration +------------- + +To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 3326ec82ff..4bfaabbd16 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -65,6 +65,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio + cmd/gpt cmd/host cmd/imxtract cmd/load

Hi Joshua,
On Fri, 25 Aug 2023 at 13:38, Joshua Watt jpewhacker@gmail.com wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
I don't see a change log?
Reviewed-by: Simon Glass sjg@chromium.org

On Fri, Aug 25, 2023 at 5:53 PM Simon Glass sjg@chromium.org wrote:
Hi Joshua,
On Fri, 25 Aug 2023 at 13:38, Joshua Watt jpewhacker@gmail.com wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
I don't see a change log?
Sorry, I didn't realize patman was a thing until I just looked now; I've just been using git send-email, and I'm not really sure how to switch over to patman now; I'll start with it next time though.
Reviewed-by: Simon Glass sjg@chromium.org

On 8/25/23 21:38, Joshua Watt wrote:
Adds initial documentation for the gpt command
Thanks a lot for filling the gap.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..f6e082fb94 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt repair <interface> <device no>
- gpt write <interface> <device no> <partition string>
- gpt verify <interface> <device no> <partition string>
<partition string> is not required. Please, add brackets [].
- gpt setenv <interface> <device no> <partition name>
gpt setenv can be called without partition name which leads to a crash.
If that parameter is meant to be optional, this should be indicated here. Otherwise an argc check is missing.
- gpt enumerate <interface> <device no>
- gpt guid <interface> <device no> [<varname>]
- gpt read <interface> <device no> [<varname>]
- gpt swap <interface> <dev> <name1> <name2>
- gpt rename <interface> <dev> <part> <name>
Thanks a lot for providing a man-page for this command.
If <device no> and <dev> both relate to the same object type, we should use the same text. <dev> would be fine.
The sequence looks random. Please, sort the sub-commands either logically or alphabetically.
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+The syntax of the text description of the partition list is similar to +the one used by the 'mbr' command. The string contains one or more partition
Please, link the mbr page:
by the :doc:`mbr command <mbr>`.
+descriptors, each separated by a ";". Each descriptor contains one or more +fields, with each field separated by a ",". Fields are either of the form +"key=value" to set a specific value, or simple "flag" to set a boolean flag
At this point it remains unclear to the reader what this ;-separated string format relates to. Is it an output format? Is it a format used in variables? Is it used for the parameter 'partition string'?
Maybe describe it after the parameters and relate it to the 'partition string' parameter.
Please, describe all parameters (in this indented format):
interface interface for accessing the block device (mmc, sata, scsi, usb, ....)
device no device number
...
+The first descriptor can optionally be used to describe parameters for the +whole disk with the following fields:
+* uuid_disk=UUID - Set the UUID for the disk
+Partition descriptors can have the following fields: +* name=NAME - The partition name, required
Maybe better
name=<NAME>
This is not rendered as an unordered list but everything is in one line. Please, add the missing blank lines.
Please, generate the HTML documentation as described in https://u-boot.readthedocs.io/en/latest/build/documentation.html and check the output before resubmitting.
+* start=BYTES - The partition start offset in bytes, required +* size=BYTES - The partition size, in bytes or "-" to expand it to the whole free area +* bootable - Set the legacy bootable flag +* uuid=UUID - Set the partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled +* type=UUID - Set the partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y
The following should be in a separate 'Examples' section to match the other man-pages.
+Here is an example how to create a 6 partitions, some of the predefined sizes:
+::
- => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4
- => gpt write mmc 0 $gpt_parts
+If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition
+The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command:
The command can be used with and without partition parameter. This should be described here.
I would prefer:
sets the return value $? to 0 (true) if the layout or 1 (false) if not
+::
- => gpt verify mmc 0 $gpt_parts
+The verify sub-command is especially useful in the system update scripts:
+::
- => if gpt verify mmc 0 $gpt_parts; then
echo GPT layout needs to be updated
...
fi
+The 'gpt write' command returns 0 on success write or 1 on failure.
+The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are:
+* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks)
The blocks that are not hexadecimal, the numbers are.
gpt_partition_addr (first block of the partition as hexadecimal number) gpt_partition_size (number of blocks as hexadecimal number)
+* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.)
This value is currently decimal but this seems to be a bug. We need a hexadecimal number to use this variable in a command like
load host 0:$gpt_partition_entry $loadaddr filename
Another bug is that this command assumes that partitions are continuously numbered.
+To get the information about the partition named 'rootfs', issue the following +command:
+::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example:
+::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
As we cannot see from the output if there is a partition 'user' and a partition 'modules' or only a single partition 'user modules' this sub-command seems to need some rework.
Best regards
Heinrich
+The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example:
+::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
+The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+Configuration +-------------
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 3326ec82ff..4bfaabbd16 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -65,6 +65,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio
- cmd/gpt cmd/host cmd/imxtract cmd/load

On Fri, Aug 25, 2023 at 7:57 PM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/25/23 21:38, Joshua Watt wrote:
Adds initial documentation for the gpt command
Thanks a lot for filling the gap.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..f6e082fb94 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt repair <interface> <device no>
- gpt write <interface> <device no> <partition string>
- gpt verify <interface> <device no> <partition string>
<partition string> is not required. Please, add brackets [].
It's not optional; there is no standardized string for the list of GPT partitions like there is for MBR
- gpt setenv <interface> <device no> <partition name>
gpt setenv can be called without partition name which leads to a crash.
If that parameter is meant to be optional, this should be indicated here. Otherwise an argc check is missing.
I don't believe the argument is optional, but either way it can be fixed in a subsequent patch series. I'd rather not hold up the documentation to fix bugs
- gpt enumerate <interface> <device no>
- gpt guid <interface> <device no> [<varname>]
- gpt read <interface> <device no> [<varname>]
- gpt swap <interface> <dev> <name1> <name2>
- gpt rename <interface> <dev> <part> <name>
Thanks a lot for providing a man-page for this command.
If <device no> and <dev> both relate to the same object type, we should use the same text. <dev> would be fine.
The sequence looks random. Please, sort the sub-commands either logically or alphabetically.
They are sorted to match the gpt command help text. Reordering of both can be done later if desired.
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+The syntax of the text description of the partition list is similar to +the one used by the 'mbr' command. The string contains one or more partition
Please, link the mbr page:
by the :doc:`mbr command <mbr>`.
+descriptors, each separated by a ";". Each descriptor contains one or more +fields, with each field separated by a ",". Fields are either of the form +"key=value" to set a specific value, or simple "flag" to set a boolean flag
At this point it remains unclear to the reader what this ;-separated string format relates to. Is it an output format? Is it a format used in variables? Is it used for the parameter 'partition string'?
Maybe describe it after the parameters and relate it to the 'partition string' parameter.
Please, describe all parameters (in this indented format):
interface interface for accessing the block device (mmc, sata, scsi, usb, ....)
device no device number
...
+The first descriptor can optionally be used to describe parameters for the +whole disk with the following fields:
+* uuid_disk=UUID - Set the UUID for the disk
+Partition descriptors can have the following fields: +* name=NAME - The partition name, required
Maybe better
name=<NAME>
This is not rendered as an unordered list but everything is in one line. Please, add the missing blank lines.
Please, generate the HTML documentation as described in https://u-boot.readthedocs.io/en/latest/build/documentation.html and check the output before resubmitting.
+* start=BYTES - The partition start offset in bytes, required +* size=BYTES - The partition size, in bytes or "-" to expand it to the whole free area +* bootable - Set the legacy bootable flag +* uuid=UUID - Set the partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled +* type=UUID - Set the partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y
The following should be in a separate 'Examples' section to match the other man-pages.
+Here is an example how to create a 6 partitions, some of the predefined sizes:
+::
- => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4
- => gpt write mmc 0 $gpt_parts
+If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition
+The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command:
The command can be used with and without partition parameter. This should be described here.
I would prefer:
sets the return value $? to 0 (true) if the layout or 1 (false) if not
+::
- => gpt verify mmc 0 $gpt_parts
+The verify sub-command is especially useful in the system update scripts:
+::
- => if gpt verify mmc 0 $gpt_parts; then
echo GPT layout needs to be updated
...
fi
+The 'gpt write' command returns 0 on success write or 1 on failure.
+The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are:
+* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks)
The blocks that are not hexadecimal, the numbers are.
gpt_partition_addr (first block of the partition as hexadecimal number) gpt_partition_size (number of blocks as hexadecimal number)
+* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.)
This value is currently decimal but this seems to be a bug. We need a hexadecimal number to use this variable in a command like
load host 0:$gpt_partition_entry $loadaddr filename
Another bug is that this command assumes that partitions are continuously numbered.
+To get the information about the partition named 'rootfs', issue the following +command:
+::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example:
+::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
As we cannot see from the output if there is a partition 'user' and a partition 'modules' or only a single partition 'user modules' this sub-command seems to need some rework.
Can be fixed later.
Best regards
Heinrich
+The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example:
+::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
+The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+Configuration +-------------
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 3326ec82ff..4bfaabbd16 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -65,6 +65,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio
- cmd/gpt cmd/host cmd/imxtract cmd/load

On 8/28/23 21:29, Joshua Watt wrote:
On Fri, Aug 25, 2023 at 7:57 PM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/25/23 21:38, Joshua Watt wrote:
Adds initial documentation for the gpt command
Thanks a lot for filling the gap.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..f6e082fb94 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt repair <interface> <device no>
- gpt write <interface> <device no> <partition string>
- gpt verify <interface> <device no> <partition string>
<partition string> is not required. Please, add brackets [].
It's not optional; there is no standardized string for the list of GPT partitions like there is for MBR
You can use the command without partition string. It will tell you if the device is partitioned or not.
- gpt setenv <interface> <device no> <partition name>
gpt setenv can be called without partition name which leads to a crash.
If that parameter is meant to be optional, this should be indicated here. Otherwise an argc check is missing.
I don't believe the argument is optional, but either way it can be fixed in a subsequent patch series. I'd rather not hold up the documentation to fix bugs
- gpt enumerate <interface> <device no>
- gpt guid <interface> <device no> [<varname>]
- gpt read <interface> <device no> [<varname>]
- gpt swap <interface> <dev> <name1> <name2>
- gpt rename <interface> <dev> <part> <name>
Thanks a lot for providing a man-page for this command.
If <device no> and <dev> both relate to the same object type, we should use the same text. <dev> would be fine.
The sequence looks random. Please, sort the sub-commands either logically or alphabetically.
They are sorted to match the gpt command help text. Reordering of both can be done later if desired.
There is no requirement to follow the gpt help =sequence here.
We should not reproduce what is not helpful.
Best regards
Heinrich
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+The syntax of the text description of the partition list is similar to +the one used by the 'mbr' command. The string contains one or more partition
Please, link the mbr page:
by the :doc:`mbr command <mbr>`.
+descriptors, each separated by a ";". Each descriptor contains one or more +fields, with each field separated by a ",". Fields are either of the form +"key=value" to set a specific value, or simple "flag" to set a boolean flag
At this point it remains unclear to the reader what this ;-separated string format relates to. Is it an output format? Is it a format used in variables? Is it used for the parameter 'partition string'?
Maybe describe it after the parameters and relate it to the 'partition string' parameter.
Please, describe all parameters (in this indented format):
interface interface for accessing the block device (mmc, sata, scsi, usb, ....)
device no device number
...
+The first descriptor can optionally be used to describe parameters for the +whole disk with the following fields:
+* uuid_disk=UUID - Set the UUID for the disk
+Partition descriptors can have the following fields: +* name=NAME - The partition name, required
Maybe better
name=<NAME>
This is not rendered as an unordered list but everything is in one line. Please, add the missing blank lines.
Please, generate the HTML documentation as described in https://u-boot.readthedocs.io/en/latest/build/documentation.html and check the output before resubmitting.
+* start=BYTES - The partition start offset in bytes, required +* size=BYTES - The partition size, in bytes or "-" to expand it to the whole free area +* bootable - Set the legacy bootable flag +* uuid=UUID - Set the partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled +* type=UUID - Set the partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y
The following should be in a separate 'Examples' section to match the other man-pages.
+Here is an example how to create a 6 partitions, some of the predefined sizes:
+::
- => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4
- => gpt write mmc 0 $gpt_parts
+If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition
+The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command:
The command can be used with and without partition parameter. This should be described here.
I would prefer:
sets the return value $? to 0 (true) if the layout or 1 (false) if not
+::
- => gpt verify mmc 0 $gpt_parts
+The verify sub-command is especially useful in the system update scripts:
+::
- => if gpt verify mmc 0 $gpt_parts; then
echo GPT layout needs to be updated
...
fi
+The 'gpt write' command returns 0 on success write or 1 on failure.
+The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are:
+* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks)
The blocks that are not hexadecimal, the numbers are.
gpt_partition_addr (first block of the partition as hexadecimal number) gpt_partition_size (number of blocks as hexadecimal number)
+* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.)
This value is currently decimal but this seems to be a bug. We need a hexadecimal number to use this variable in a command like
load host 0:$gpt_partition_entry $loadaddr filename
Another bug is that this command assumes that partitions are continuously numbered.
+To get the information about the partition named 'rootfs', issue the following +command:
+::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example:
+::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
As we cannot see from the output if there is a partition 'user' and a partition 'modules' or only a single partition 'user modules' this sub-command seems to need some rework.
Can be fixed later.
Best regards
Heinrich
+The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example:
+::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
+The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+Configuration +-------------
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 3326ec82ff..4bfaabbd16 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -65,6 +65,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio
- cmd/gpt cmd/host cmd/imxtract cmd/load

On Mon, Aug 28, 2023 at 2:00 PM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/28/23 21:29, Joshua Watt wrote:
On Fri, Aug 25, 2023 at 7:57 PM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/25/23 21:38, Joshua Watt wrote:
Adds initial documentation for the gpt command
Thanks a lot for filling the gap.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 141 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 142 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..f6e082fb94 --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,141 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt repair <interface> <device no>
- gpt write <interface> <device no> <partition string>
- gpt verify <interface> <device no> <partition string>
<partition string> is not required. Please, add brackets [].
It's not optional; there is no standardized string for the list of GPT partitions like there is for MBR
You can use the command without partition string. It will tell you if the device is partitioned or not.
Ah, right. I missed that
- gpt setenv <interface> <device no> <partition name>
gpt setenv can be called without partition name which leads to a crash.
If that parameter is meant to be optional, this should be indicated here. Otherwise an argc check is missing.
I don't believe the argument is optional, but either way it can be fixed in a subsequent patch series. I'd rather not hold up the documentation to fix bugs
- gpt enumerate <interface> <device no>
- gpt guid <interface> <device no> [<varname>]
- gpt read <interface> <device no> [<varname>]
- gpt swap <interface> <dev> <name1> <name2>
- gpt rename <interface> <dev> <part> <name>
Thanks a lot for providing a man-page for this command.
If <device no> and <dev> both relate to the same object type, we should use the same text. <dev> would be fine.
The sequence looks random. Please, sort the sub-commands either logically or alphabetically.
They are sorted to match the gpt command help text. Reordering of both can be done later if desired.
There is no requirement to follow the gpt help =sequence here.
We should not reproduce what is not helpful.
Best regards
Heinrich
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+The syntax of the text description of the partition list is similar to +the one used by the 'mbr' command. The string contains one or more partition
Please, link the mbr page:
by the :doc:`mbr command <mbr>`.
+descriptors, each separated by a ";". Each descriptor contains one or more +fields, with each field separated by a ",". Fields are either of the form +"key=value" to set a specific value, or simple "flag" to set a boolean flag
At this point it remains unclear to the reader what this ;-separated string format relates to. Is it an output format? Is it a format used in variables? Is it used for the parameter 'partition string'?
Maybe describe it after the parameters and relate it to the 'partition string' parameter.
Please, describe all parameters (in this indented format):
interface interface for accessing the block device (mmc, sata, scsi, usb, ....)
device no device number
...
+The first descriptor can optionally be used to describe parameters for the +whole disk with the following fields:
+* uuid_disk=UUID - Set the UUID for the disk
+Partition descriptors can have the following fields: +* name=NAME - The partition name, required
Maybe better
name=<NAME>
This is not rendered as an unordered list but everything is in one line. Please, add the missing blank lines.
Please, generate the HTML documentation as described in https://u-boot.readthedocs.io/en/latest/build/documentation.html and check the output before resubmitting.
+* start=BYTES - The partition start offset in bytes, required +* size=BYTES - The partition size, in bytes or "-" to expand it to the whole free area +* bootable - Set the legacy bootable flag +* uuid=UUID - Set the partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled +* type=UUID - Set the partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y
The following should be in a separate 'Examples' section to match the other man-pages.
+Here is an example how to create a 6 partitions, some of the predefined sizes:
+::
- => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4
- => gpt write mmc 0 $gpt_parts
+If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID +will be generated for the partition
+The 'gpt verify' command returns 0 if the layout matches the one on the storage +device or 1 if not. To check if the layout on the MMC #0 storage device +matches the provided text description one has to issue following command:
The command can be used with and without partition parameter. This should be described here.
I would prefer:
sets the return value $? to 0 (true) if the layout or 1 (false) if not
+::
- => gpt verify mmc 0 $gpt_parts
+The verify sub-command is especially useful in the system update scripts:
+::
- => if gpt verify mmc 0 $gpt_parts; then
echo GPT layout needs to be updated
...
fi
+The 'gpt write' command returns 0 on success write or 1 on failure.
+The 'gpt setenv' command will set a series of environment variables with +information about a particular partition. The variables are:
+* gpt_partition_addr (the starting offset of the partition, in hexadecimal blocks) +* gpt_partition_size (the size of the partition, in hexadecimal blocks)
The blocks that are not hexadecimal, the numbers are.
gpt_partition_addr (first block of the partition as hexadecimal number) gpt_partition_size (number of blocks as hexadecimal number)
+* gpt_partition_name (the name of the partition) +* gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.)
This value is currently decimal but this seems to be a bug. We need a hexadecimal number to use this variable in a command like
load host 0:$gpt_partition_entry $loadaddr filename
Another bug is that this command assumes that partitions are continuously numbered.
+To get the information about the partition named 'rootfs', issue the following +command:
+::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the +list of partition names on the device. For example:
+::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
As we cannot see from the output if there is a partition 'user' and a partition 'modules' or only a single partition 'user modules' this sub-command seems to need some rework.
Can be fixed later.
Best regards
Heinrich
+The 'gpt guid' command will report the GUID of a disk. If 'varname' is +specified, the command will set the variable to the GUID, otherwise it will be +printed out. For example:
+::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
+The 'gpt read' command will print out the current state of the GPT partition +table. If 'varname' is specified, the variable will be filled with a partition +string as described above that is suitable for passing to other 'gpt' commands. +If omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap' command changes the names of all partitions that are named +'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt rename' command renames all partitions named 'part' to be 'name1'. +CONFIG_CMD_GPT_RENAME=y is required.
+Configuration +-------------
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 3326ec82ff..4bfaabbd16 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -65,6 +65,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio
- cmd/gpt cmd/host cmd/imxtract cmd/load

Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- test/py/tests/test_gpt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 73bfbf77a2..339468bc12 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -61,18 +61,14 @@ class GptTestDiskImage(object): cmd = ('cp', persistent, self.path) u_boot_utils.run_and_log(u_boot_console, cmd)
-gtdi = None @pytest.fixture(scope='function') def state_disk_image(u_boot_console): """pytest fixture to provide a GptTestDiskImage object to tests. This is function-scoped because it uses u_boot_console, which is also - function-scoped. However, we don't need to actually do any function-scope - work, so this simply returns the same object over and over each time.""" + function-scoped. A new disk is returned each time to prevent tests from + interfering with each other."""
- global gtdi - if not gtdi: - gtdi = GptTestDiskImage(u_boot_console) - return gtdi + return GptTestDiskImage(u_boot_console)
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @@ -186,12 +182,12 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console):
u_boot_console.run_command('host bind 0 ' + state_disk_image.path) output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "first"' in output - assert '0x00001000 0x00001bff "second"' in output - u_boot_console.run_command('gpt swap host 0 first second') + assert '0x00000800 0x00000fff "part1"' in output + assert '0x00001000 0x00001bff "part2"' in output + u_boot_console.run_command('gpt swap host 0 part1 part2') output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "second"' in output - assert '0x00001000 0x00001bff "first"' in output + assert '0x00000800 0x00000fff "part2"' in output + assert '0x00001000 0x00001bff "part1"' in output
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt')

Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 9 +++++++-- doc/usage/cmd/gpt.rst | 3 +++ test/py/tests/test_gpt.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index e6f7b0319a..7a8990e400 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -723,7 +723,7 @@ static int gpt_enumerate(struct blk_desc *desc) * gpt_setenv_part_variables() - setup partition environmental variables * * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr - * and gpt_partition_size environment variables. + * and gpt_partition_size, gpt_partition_bootable environment variables. * * @pinfo: pointer to disk partition * @i: partition entry @@ -750,6 +750,10 @@ static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) if (ret) goto fail;
+ ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE)); + if (ret) + goto fail; + return 0;
fail: @@ -1057,7 +1061,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt setenv mmc 0 $name\n" " - setup environment variables for partition $name:\n" " gpt_partition_addr, gpt_partition_size,\n" - " gpt_partition_name, gpt_partition_entry\n" + " gpt_partition_name, gpt_partition_entry,\n" + " gpt_partition_bootable\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" " gpt guid <interface> <dev>\n" diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index f6e082fb94..88839b8e1b 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -87,6 +87,7 @@ information about a particular partition. The variables are: * gpt_partition_size (the size of the partition, in hexadecimal blocks) * gpt_partition_name (the name of the partition) * gpt_partition_entry (the partition number in the table, e.g. 1, 2, 3, etc.) +* gpt_partition_bootable (1 if the partition is marked as bootable, 0 if not)
To get the information about the partition named 'rootfs', issue the following command: @@ -101,6 +102,8 @@ command: rootfs => echo ${gpt_partition_entry} 2 + => echo ${gpt_partition_bootable} + 0
The 'gpt enumerate' command will set the variable 'gpt_partition_list' with the list of partition names on the device. For example: diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 339468bc12..946858800d 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -49,6 +49,7 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) @@ -117,6 +118,38 @@ def test_gpt_guid(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_setenv(state_disk_image, u_boot_console): + """Test the gpt setenv command.""" + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt setenv host 0 part1') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part1' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == '1' + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == '1' + + output = u_boot_console.run_command('gpt setenv host 0 part2') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '1000' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == 'c00' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part2' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == '2' + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')

On Fri, 25 Aug 2023 at 13:38, Joshua Watt jpewhacker@gmail.com wrote:
Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 9 +++++++-- doc/usage/cmd/gpt.rst | 3 +++ test/py/tests/test_gpt.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 9 +++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 111 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 7a8990e400..1fe7f1a7db 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -972,6 +972,81 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, free(partitions_list); return ret; } + +/** + * gpt_set_bootable() - Set bootable flags for partitions + * + * Sets the bootable flag for any partition names in the comma separated list of + * partition names. Any partitions not in the list have their bootable flag + * cleared + * + * @desc: block device descriptor + * @name: Comma separated list of partition names + * + * @Return: '0' on success and -ve error on failure + */ +static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) +{ + char *name; + char disk_guid[UUID_STR_LEN + 1]; + struct list_head *pos; + struct disk_part *curr; + struct disk_partition *partitions = NULL; + int part_count = 0; + int ret = get_disk_guid(blk_dev_desc, disk_guid); + + if (ret < 0) + return ret; + + ret = get_gpt_info(blk_dev_desc); + if (ret <= 0) + goto out; + + part_count = ret; + partitions = malloc(sizeof(*partitions) * part_count); + if (!partitions) { + ret = -ENOMEM; + goto out; + } + + /* Copy partitions and clear bootable flag */ + part_count = 0; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + partitions[part_count] = curr->gpt_part_info; + partitions[part_count].bootable &= ~PART_BOOTABLE; + part_count++; + } + + name = strtok(part_list, ","); + while (name) { + bool found = false; + + for (int i = 0; i < part_count; i++) { + if (strcmp((char *)partitions[i].name, name) == 0) { + partitions[i].bootable |= PART_BOOTABLE; + found = true; + } + } + + if (!found) { + printf("Warning: No partition matching '%s' found\n", + name); + } + + name = strtok(NULL, ","); + } + + ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count); + +out: + del_gpt_info(); + + if (partitions) + free(partitions); + + return ret; +} #endif
/** @@ -1031,6 +1106,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if ((strcmp(argv[1], "swap") == 0) || (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); + } else if ((strcmp(argv[1], "set-bootable") == 0)) { + ret = gpt_set_bootable(blk_dev_desc, argv[4]); #endif } else { return CMD_RET_USAGE; @@ -1082,8 +1159,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " and vice-versa\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" + " gpt set-bootable <interface> <dev> <list>\n" + " - make partition names in list bootable\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" + " gpt set-bootable mmc 0 boot_a,boot_b\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 88839b8e1b..353dfb05cf 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -17,6 +17,7 @@ Synopsis gpt read <interface> <device no> [<varname>] gpt swap <interface> <dev> <name1> <name2> gpt rename <interface> <dev> <part> <name> + gpt set-bootable <interface> <dev> <partition list>
Description ----------- @@ -137,6 +138,14 @@ CONFIG_CMD_GPT_RENAME=y is required. The 'gpt rename' command renames all partitions named 'part' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt set-bootable' command sets the bootable flag for all partitions in the +table. If the partition name is in 'partition list' (separated by ','), the +bootable flag is set, otherwise it is cleared. CONFIG_CMD_GPT_RENAME=y is +required. For example, to mark only the 'boot' partition as bootable: + +:: + => gpt set-bootable mmc 0 boot + Configuration -------------
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 946858800d..5d23f9b292 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -222,6 +222,28 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part2"' in output assert '0x00001000 0x00001bff "part1"' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_set_bootable(state_disk_image, u_boot_console): + """Test the gpt set-bootable command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + parts = ('part2', 'part1') + for bootable in parts: + output = u_boot_console.run_command(f'gpt set-bootable host 0 {bootable}') + assert 'success!' in output + + for p in parts: + output = u_boot_console.run_command(f'gpt setenv host 0 {p}') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + if p == bootable: + assert output.rstrip() == '1' + else: + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.buildconfigspec('cmd_part')

If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 16 ++++++++++ test/py/tests/test_gpt.py | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 1fe7f1a7db..b7d861aa1e 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID + partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); +#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID + strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid, + UUID_STR_LEN); + newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0'; +#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID + printf("Type GUID %s\n", curr->gpt_part_info.type_guid); +#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID + strcat(partitions_list, ",type="); + strncat(partitions_list, curr->gpt_part_info.type_guid, + UUID_STR_LEN + 1); +#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 5d23f9b292..09a90f026f 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -16,6 +16,35 @@ the test. # Mark all tests here as slow pytestmark = pytest.mark.slow
+def parse_gpt_parts(disk_str): + """Parser a partition string into a list of partitions. + + Args: + disk_str: The disk description string, as returned by `gpt read` + + Returns: + A list of parsed partitions. Each partition is a dictionary with the + string value from each specified key in the partition description, or a + key with with the value True for a boolean flag + """ + parts = [] + for part_str in disk_str.split(';'): + part = {} + for option in part_str.split(","): + if not option: + continue + + if "=" in option: + k, v = option.split("=") + part[k] = v + else: + part[option] = True + + if part: + parts.append(part) + + return parts + class GptTestDiskImage(object): """Disk Image used by the GPT tests."""
@@ -49,11 +78,13 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2', + '--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', persistent) u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--load-backup=' + persistent) @@ -88,6 +119,40 @@ def test_gpt_read(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part1"' in output assert '0x00001000 0x00001bff "part2"' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('partition_type_guid') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_read_var(state_disk_image, u_boot_console): + """Test the gpt read command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt read host 0 gpt_parts') + assert 'success!' in output + + output = u_boot_console.run_command('echo ${gpt_parts}') + parts = parse_gpt_parts(output.rstrip()) + + assert parts == [ + { + "uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe", + }, + { + "name": "part1", + "start": "0x100000", + "size": "0x100000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + }, + { + "name": "part2", + "start": "0x200000", + "size": "0x180000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb", + }, + ] + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk') @@ -263,3 +328,4 @@ def test_gpt_write(state_disk_image, u_boot_console): assert '0x00001000 0x00001bff "second"' in output output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output +

On Fri, 25 Aug 2023 at 13:39, Joshua Watt jpewhacker@gmail.com wrote:
If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 16 ++++++++++ test/py/tests/test_gpt.py | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

On 8/25/23 21:38, Joshua Watt wrote:
If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com Reviewed-by: Simon Glass sjg@chromium.org
cmd/gpt.c | 16 ++++++++++ test/py/tests/test_gpt.py | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 1fe7f1a7db..b7d861aa1e 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID
- partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1);
+#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID
- strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid,
UUID_STR_LEN);
- newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0';
+#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID
printf("Type GUID %s\n", curr->gpt_part_info.type_guid);
+#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID
strcat(partitions_list, ",type=");
strncat(partitions_list, curr->gpt_part_info.type_guid,
UUID_STR_LEN + 1);
+#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 5d23f9b292..09a90f026f 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -16,6 +16,35 @@ the test. # Mark all tests here as slow pytestmark = pytest.mark.slow
+def parse_gpt_parts(disk_str):
- """Parser a partition string into a list of partitions.
- Args:
disk_str: The disk description string, as returned by `gpt read`
- Returns:
A list of parsed partitions. Each partition is a dictionary with the
string value from each specified key in the partition description, or a
key with with the value True for a boolean flag
- """
- parts = []
- for part_str in disk_str.split(';'):
part = {}
for option in part_str.split(","):
if not option:
continue
if "=" in option:
k, v = option.split("=")
This results in a pylint warning:
C0103: Variable name "v" doesn't conform to snake_case naming style (invalid-name)
How about key, value?
part[k] = v
else:
part[option] = True
if part:
parts.append(part)
- return parts
- class GptTestDiskImage(object): """Disk Image used by the GPT tests."""
@@ -49,11 +78,13 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1',
'--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2',
'--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', persistent) u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--load-backup=' + persistent)
@@ -88,6 +119,40 @@ def test_gpt_read(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part1"' in output assert '0x00001000 0x00001bff "part2"' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('partition_type_guid') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_read_var(state_disk_image, u_boot_console):
- """Test the gpt read command."""
- u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
- output = u_boot_console.run_command('gpt read host 0 gpt_parts')
- assert 'success!' in output
- output = u_boot_console.run_command('echo ${gpt_parts}')
- parts = parse_gpt_parts(output.rstrip())
- assert parts == [
{
"uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe",
},
{
"name": "part1",
"start": "0x100000",
"size": "0x100000",
"type": "0fc63daf-8483-4772-8e79-3d69d8477de4",
"uuid": "33194895-67f6-4561-8457-6fdeed4f50a3",
},
{
"name": "part2",
"start": "0x200000",
"size": "0x180000",
"type": "0fc63daf-8483-4772-8e79-3d69d8477de4",
"uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb",
},
- ]
- @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')
@@ -263,3 +328,4 @@ def test_gpt_write(state_disk_image, u_boot_console): assert '0x00001000 0x00001bff "second"' in output output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
Please, remove this white space line.
Best regards
Heinrich

Sets the bootable flag when constructing the partition string from the current partition configuration. This ensures that when the partitions are written back (for example, when renaming a partition), the flag is preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 3 +++ test/py/tests/test_gpt.py | 1 + 2 files changed, 4 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index b7d861aa1e..0479b3a6a4 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -176,6 +176,7 @@ static int calc_parts_list_len(int numparts) #ifdef CONFIG_PARTITION_TYPE_GUID partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); #endif + partlistlen += numparts * strlen("bootable,"); partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -318,6 +319,8 @@ static int create_gpt_partitions_list(int numparts, const char *guid, strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); + if (curr->gpt_part_info.bootable & PART_BOOTABLE) + strcat(partitions_list, ",bootable"); strcat(partitions_list, ";"); } return 0; diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 09a90f026f..666d387ac8 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -143,6 +143,7 @@ def test_gpt_read_var(state_disk_image, u_boot_console): "size": "0x100000", "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + "bootable": True, }, { "name": "part2",

Adds a command called "gpt swap-postition" which will swap the order two partitions are listed in the GPT partition table (but leaves them pointing to the same locations on disk).
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 52 ++++++++++++++++++++++++++++++++++++--- doc/usage/cmd/gpt.rst | 23 +++++++++++++++++ test/py/tests/test_gpt.py | 18 ++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 0479b3a6a4..3c39446258 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -858,8 +858,9 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, u8 part_count = 0; int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
- if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || - (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) + if (!subcomm || !name1 || !name2 || + (strcmp(subcomm, "swap") && strcmp(subcomm, "rename") && + strcmp(subcomm, "swap-position"))) return -EINVAL;
ret = get_disk_guid(dev_desc, disk_guid); @@ -920,6 +921,47 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; } + } else if (!strcmp(subcomm, "swap-position")) { + int idx1, idx2; + struct disk_partition first, second; + + idx1 = simple_strtoul(name1, NULL, 10); + if (idx1 <= 0 || idx1 > numparts) { + printf("Illegal partition number %s\n", name1); + ret = -EINVAL; + goto out; + } + idx2 = simple_strtoul(name2, NULL, 10); + if (idx2 <= 0 || idx2 > numparts) { + printf("Illegal partition number %s\n", name2); + ret = -EINVAL; + goto out; + } + if (idx1 == idx2) { + printf("Cannot swap partition with itself\n"); + ret = -EINVAL; + goto out; + } + + i = 1; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (i == idx1) + first = curr->gpt_part_info; + else if (i == idx2) + second = curr->gpt_part_info; + i++; + } + + i = 1; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (i == idx1) + curr->gpt_part_info = second; + else if (i == idx2) + curr->gpt_part_info = first; + i++; + } } else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); @@ -1123,7 +1165,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) || - (strcmp(argv[1], "rename") == 0)) { + (strcmp(argv[1], "rename") == 0) || + (strcmp(argv[1], "swap-position") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); } else if ((strcmp(argv[1], "set-bootable") == 0)) { ret = gpt_set_bootable(blk_dev_desc, argv[4]); @@ -1176,6 +1219,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n" + " gpt swap-position <interface> <dev> <part1> <part2>\n" + " - Swap the order of name1 with name2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " gpt set-bootable <interface> <dev> <list>\n" @@ -1184,5 +1229,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" " gpt set-bootable mmc 0 boot_a,boot_b\n" + " gpt swap-position mmc 0 1 2\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 353dfb05cf..bc14bda6e5 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -17,6 +17,7 @@ Synopsis gpt read <interface> <device no> [<varname>] gpt swap <interface> <dev> <name1> <name2> gpt rename <interface> <dev> <part> <name> + gpt swap-position <interface> <dev> <part1> <part2> gpt set-bootable <interface> <dev> <partition list>
Description @@ -138,6 +139,28 @@ CONFIG_CMD_GPT_RENAME=y is required. The 'gpt rename' command renames all partitions named 'part' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap-position' command swaps the order of two partition index in the +partition table, but otherwise leaves the actual partition data untouched. For +example, to swap the order of the 'boot' and 'rootfs' partitions in the disk +described above, you would do: + +:: + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 2 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 1 + + => gpt swap-position mmc 0 1 2 + + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 1 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 2 + The 'gpt set-bootable' command sets the bootable flag for all partitions in the table. If the partition name is in 'partition list' (separated by ','), the bootable flag is set, otherwise it is cleared. CONFIG_CMD_GPT_RENAME=y is diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 666d387ac8..3d23b98cea 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -330,3 +330,21 @@ def test_gpt_write(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_swap_position(state_disk_image, u_boot_console): + """Test the gpt swap-position command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('part list host 0') + assert '1\t0x00000800\t0x00000fff\t"part1"' in output + assert '2\t0x00001000\t0x00001bff\t"part2"' in output + + output = u_boot_console.run_command('gpt swap-position host 0 1 2') + assert 'success!' in output + + output = u_boot_console.run_command('part list host 0') + assert '2\t0x00000800\t0x00000fff\t"part1"' in output + assert '1\t0x00001000\t0x00001bff\t"part2"' in output

On Fri, 25 Aug 2023 at 13:39, Joshua Watt jpewhacker@gmail.com wrote:
Adds a command called "gpt swap-postition" which will swap the order two partitions are listed in the GPT partition table (but leaves them pointing to the same locations on disk).
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 52 ++++++++++++++++++++++++++++++++++++--- doc/usage/cmd/gpt.rst | 23 +++++++++++++++++ test/py/tests/test_gpt.py | 18 ++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

On 8/25/23 21:38, Joshua Watt wrote:
Adds a command called "gpt swap-postition" which will swap the order two partitions are listed in the GPT partition table (but leaves them pointing to the same locations on disk).
Why is this functionality needed in a boot firmware?
Signed-off-by: Joshua Watt JPEWhacker@gmail.com Reviewed-by: Simon Glass <sjg@chromium.org > --- cmd/gpt.c | 52 ++++++++++++++++++++++++++++++++++++--- doc/usage/cmd/gpt.rst | 23 +++++++++++++++++ test/py/tests/test_gpt.py | 18 ++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 0479b3a6a4..3c39446258 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -858,8 +858,9 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, u8 part_count = 0; int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
- if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
(strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
if (!subcomm || !name1 || !name2 ||
(strcmp(subcomm, "swap") && strcmp(subcomm, "rename") &&
strcmp(subcomm, "swap-position")))
return -EINVAL;
ret = get_disk_guid(dev_desc, disk_guid);
@@ -920,6 +921,47 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; }
- } else if (!strcmp(subcomm, "swap-position")) {
int idx1, idx2;
struct disk_partition first, second;
idx1 = simple_strtoul(name1, NULL, 10);
if (idx1 <= 0 || idx1 > numparts) {
The number of partitions is irrelevant here.
Take a partition table with two partitions 37 and 63. numparts is 2. But of course you can swap the two. You have to check that idx1 relates to an existing partition here.
I would have preferred to see the numerous bugs in the gpt command to be fixed before adding new functionality.
printf("Illegal partition number %s\n", name1);
ret = -EINVAL;
goto out;
}
idx2 = simple_strtoul(name2, NULL, 10);
if (idx2 <= 0 || idx2 > numparts) {
printf("Illegal partition number %s\n", name2);
ret = -EINVAL;
goto out;
}
if (idx1 == idx2) {
printf("Cannot swap partition with itself\n");
ret = -EINVAL;
goto out;
}
i = 1;
list_for_each(pos, &disk_partitions) {
curr = list_entry(pos, struct disk_part, list);
if (i == idx1)
first = curr->gpt_part_info;
else if (i == idx2)
second = curr->gpt_part_info;
i++;
}
i = 1;
list_for_each(pos, &disk_partitions) {
curr = list_entry(pos, struct disk_part, list);
if (i == idx1)
curr->gpt_part_info = second;
else if (i == idx2)
curr->gpt_part_info = first;
i++;
} else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);}
@@ -1123,7 +1165,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) ||
(strcmp(argv[1], "rename") == 0)) {
(strcmp(argv[1], "rename") == 0) ||
ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); } else if ((strcmp(argv[1], "set-bootable") == 0)) { ret = gpt_set_bootable(blk_dev_desc, argv[4]);(strcmp(argv[1], "swap-position") == 0)) {
@@ -1176,6 +1219,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n"
- " gpt swap-position <interface> <dev> <part1> <part2>\n"
- " - Swap the order of name1 with name2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " gpt set-bootable <interface> <dev> <list>\n"
@@ -1184,5 +1229,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" " gpt set-bootable mmc 0 boot_a,boot_b\n"
- " gpt swap-position mmc 0 1 2\n" #endif );
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 353dfb05cf..bc14bda6e5 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -17,6 +17,7 @@ Synopsis gpt read <interface> <device no> [<varname>] gpt swap <interface> <dev> <name1> <name2> gpt rename <interface> <dev> <part> <name>
gpt swap-position <interface> <dev> <part1> <part2> gpt set-bootable <interface> <dev> <partition list>
Description
@@ -138,6 +139,28 @@ CONFIG_CMD_GPT_RENAME=y is required. The 'gpt rename' command renames all partitions named 'part' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+The 'gpt swap-position' command swaps the order of two partition index in the
Two requires a plural form.
You don't swap indices, you swap the partition table entries indexed by part1 and part2.
+partition table, but otherwise leaves the actual partition data untouched. For +example, to swap the order of the 'boot' and 'rootfs' partitions in the disk
You don't swap the order in the disks. You swap the entries in the partition table.
Best regards
Heinrich
+described above, you would do:
+::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_entry}
- 2
- => gpt setenv mmc 0 boot
- => echo ${gpt_partition_entry}
- 1
- => gpt swap-position mmc 0 1 2
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_entry}
- 1
- => gpt setenv mmc 0 boot
- => echo ${gpt_partition_entry}
- 2
- The 'gpt set-bootable' command sets the bootable flag for all partitions in the table. If the partition name is in 'partition list' (separated by ','), the bootable flag is set, otherwise it is cleared. CONFIG_CMD_GPT_RENAME=y is
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 666d387ac8..3d23b98cea 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -330,3 +330,21 @@ def test_gpt_write(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_swap_position(state_disk_image, u_boot_console):
- """Test the gpt swap-position command."""
- u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
- output = u_boot_console.run_command('part list host 0')
- assert '1\t0x00000800\t0x00000fff\t"part1"' in output
- assert '2\t0x00001000\t0x00001bff\t"part2"' in output
- output = u_boot_console.run_command('gpt swap-position host 0 1 2')
- assert 'success!' in output
- output = u_boot_console.run_command('part list host 0')
- assert '2\t0x00000800\t0x00000fff\t"part1"' in output
- assert '1\t0x00001000\t0x00001bff\t"part2"' in output

Adds several improvements and additions to the gpt command processing, specifically (although not exclusively) for the purpose of supporting "ping-pong" booting when doing A/B boot partitions with u-boot itself.
In this mechanism, u-boot must boot up, and then check if the correct boot partition is active, and if not switch the GPT partition table to the other boot partition and reboot to activate the other u-boot.
In order to facilitate this, the gpt command needs to be better at preserving entry attributes when manipulating the partition table. It also learns two new commands, one which can swap the order of partitions in the table, and another that lets it change which partitions have the bootable flag.
V2: Add documentation and tests V3: Review Feedback V4: More review feedback. Fixed 'gpt swap-partition' to work with missing partition indexes.
Joshua Watt (8): cmd: gpt: Remove confusing help text doc: Add gpt command documentation tests: gpt: Remove test order dependency cmd: gpt: Add gpt_partition_bootable variable cmd: gpt: Add command to set bootable flags cmd: gpt: Preserve type GUID if enabled cmd: gpt: Preserve bootable flag cmd: gpt: Add command to swap partition order
cmd/gpt.c | 156 ++++++++++++++++++++++++-- doc/usage/cmd/gpt.rst | 226 ++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/py/tests/test_gpt.py | 160 +++++++++++++++++++++++++-- 4 files changed, 524 insertions(+), 19 deletions(-) create mode 100644 doc/usage/cmd/gpt.rst

This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 964056bd28..fe9e06681c 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -1060,8 +1060,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt_partition_name, gpt_partition_entry\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" - " read <interface> <dev>\n" - " - read GPT into a data structure for manipulation\n" " gpt guid <interface> <dev>\n" " - print disk GUID\n" " gpt guid <interface> <dev> <varname>\n"

On 8/28/23 23:56, Joshua Watt wrote:
This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 964056bd28..fe9e06681c 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -1060,8 +1060,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt_partition_name, gpt_partition_entry\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n"
- " read <interface> <dev>\n"
- " - read GPT into a data structure for manipulation\n" " gpt guid <interface> <dev>\n" " - print disk GUID\n" " gpt guid <interface> <dev> <varname>\n"

Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- doc/usage/cmd/gpt.rst | 184 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 185 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..6387c8116f --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,184 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +gpt command +=========== + +Synopsis +-------- + +:: + + gpt enumerate <interface> <dev> + gpt guid <interface> <dev> [<varname>] + gpt read <interface> <dev> [<varname>] + gpt rename <interface> <dev> <part> <name> + gpt repair <interface> <dev> + gpt setenv <interface> <dev> <partition name> + gpt swap <interface> <dev> <name1> <name2> + gpt verify <interface> <dev> [<partition string>] + gpt write <interface> <dev> <partition string> + +Description +----------- + +The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout. + +Common arguments: + +interface + interface for accessing the block device (mmc, sata, scsi, usb, ....) + +dev + device number + +partition string + Describes the GPT partition layout for a disk. The syntax is similar to + the one used by the :doc:`mbr command <mbr>` command. The string contains + one or more partition descriptors, each separated by a ";". Each descriptor + contains one or more fields, with each field separated by a ",". Fields are + either of the form "key=value" to set a specific value, or simple "flag" to + set a boolean flag + + The first descriptor can optionally be used to describe parameters for the + whole disk with the following fields: + + * uuid_disk=UUID - Set the UUID for the disk + + Partition descriptors can have the following fields: + + * name=<NAME> - The partition name, required + * start=<BYTES> - The partition start offset in bytes, required + * size=<BYTES> - The partition size in bytes or "-" to expand it to the whole free area + * bootable - Set the legacy bootable flag + * uuid=<UUID> - The partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled + * type=<UUID> - The partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y + + + If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID + will be generated for the partition + +gpt enumerate +~~~~~~~~~~~~~ + +Sets the variable 'gpt_partition_list' to be a list of all the partition names +on the device. + +gpt guid +~~~~~~~~ + +Report the GUID of a disk. If 'varname' is specified, the command will set the +variable to the GUID, otherwise it will be printed out. + +gpt read +~~~~~~~~ + +Prints the current state of the GPT partition table. If 'varname' is specified, +the variable will be filled with a partition string in the same format as a +'<partition string>', suitable for passing to other 'gpt' commands. If the +argument is omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required. + +gpt rename +~~~~~~~~~~ + +Renames all partitions named 'part' to be 'name'. CONFIG_CMD_GPT_RENAME=y is +required. + +gpt repair +~~~~~~~~~~ + +Repairs the GPT partition tables if it they become corrupted. + +gpt setenv +~~~~~~~~~~ + +The 'gpt setenv' command will set a series of environment variables with +information about the partition named '<partition name>'. The variables are: + +gpt_partition_addr + the starting offset of the partition in blocks as a hexadecimal number + +gpt_partition_size + the size of the partition in blocks as a hexadecimal number + +gpt_partition_name + the name of the partition + +gpt_partition_entry + the partition number in the table, e.g. 1, 2, 3, etc. + +gpt swap +~~~~~~~~ + +Changes the names of all partitions that are named 'name1' to be 'name2', and +all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is +required. + +gpt verify +~~~~~~~~~~ + +Sets return value $? to 0 (true) if the partition layout on the +specified disk matches the one in the provided partition string, and 1 (false) +if it does not match. If no partition string is specified, the command will +check if the disk is partitioned or not. + +gpt write +~~~~~~~~~ + +(Re)writes the partition table on the disk to match the provided +partition string. It returns 0 on success or 1 on failure. + +Configuration +------------- + +To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. + +Examples +~~~~~~~~ +Create 6 partitions on a disk:: + + => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7; + name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7, + name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4 + => gpt write mmc 0 $gpt_parts + + +Verify that the device matches the partition layout described in the variable +$gpt_parts:: + + => gpt verify mmc 0 $gpt_parts + + +Get the information about the partition named 'rootfs':: + + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_addr} + 2000 + => echo ${gpt_partition_size} + 14a000 + => echo ${gpt_partition_name} + rootfs + => echo ${gpt_partition_entry} + 2 + +Get the list of partition names on the disk:: + + => gpt enumerate + => echo gpt_partition_list + boot rootfs system-data [ext] user modules ramdisk + + +Get the GUID for a disk:: + + => gpt guid mmc 0 + bec9fc2a-86c1-483d-8a0e-0109732277d7 + => gpt guid mmc gpt_disk_uuid + => echo ${gpt_disk_uuid} + bec9fc2a-86c1-483d-8a0e-0109732277d7 diff --git a/doc/usage/index.rst b/doc/usage/index.rst index f45a7f5502..fa702920fa 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -66,6 +66,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio + cmd/gpt cmd/host cmd/imxtract cmd/load

/On 8/28/23 23:56, Joshua Watt wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 184 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 185 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..6387c8116f --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,184 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt enumerate <interface> <dev>
- gpt guid <interface> <dev> [<varname>]
- gpt read <interface> <dev> [<varname>]
- gpt rename <interface> <dev> <part> <name>
- gpt repair <interface> <dev>
- gpt setenv <interface> <dev> <partition name>
- gpt swap <interface> <dev> <name1> <name2>
- gpt verify <interface> <dev> [<partition string>]
- gpt write <interface> <dev> <partition string>
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+Common arguments:
+interface
- interface for accessing the block device (mmc, sata, scsi, usb, ....)
+dev
- device number
+partition string
- Describes the GPT partition layout for a disk. The syntax is similar to
- the one used by the :doc:`mbr command <mbr>` command. The string contains
- one or more partition descriptors, each separated by a ";". Each descriptor
- contains one or more fields, with each field separated by a ",". Fields are
- either of the form "key=value" to set a specific value, or simple "flag" to
- set a boolean flag
- The first descriptor can optionally be used to describe parameters for the
- whole disk with the following fields:
- uuid_disk=UUID - Set the UUID for the disk
- Partition descriptors can have the following fields:
- name=<NAME> - The partition name, required
- start=<BYTES> - The partition start offset in bytes, required
The code has this comment: "start address is optional".
- size=<BYTES> - The partition size in bytes or "-" to expand it to the whole free area
This filed is mandatory.
- bootable - Set the legacy bootable flag
This field is optional
- uuid=<UUID> - The partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled
- type=<UUID> - The partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y
This field is optional
Thanks for all the updates. Looks much neater now.
The sequence expected in set_gpt_info() is:
uuid (optional if CONFIG_RANDOM_UUID=y), type (optional, only usable for CONFIG_PARTITION_TYPE_GUID=y), name (mandatory), size (mandatory), start (optional), bootable (optional).
From the description above it is not clear that:
* semicolons are used to separate partitions * the exact sequence of fields must be kept * commas are used to separate fields * no extra white-space is allowed.
- If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID
- will be generated for the partition
+gpt enumerate +~~~~~~~~~~~~~
+Sets the variable 'gpt_partition_list' to be a list of all the partition names +on the device.
+gpt guid +~~~~~~~~
+Report the GUID of a disk. If 'varname' is specified, the command will set the +variable to the GUID, otherwise it will be printed out.
+gpt read +~~~~~~~~
+Prints the current state of the GPT partition table. If 'varname' is specified, +the variable will be filled with a partition string in the same format as a +'<partition string>', suitable for passing to other 'gpt' commands. If the +argument is omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+gpt rename +~~~~~~~~~~
+Renames all partitions named 'part' to be 'name'. CONFIG_CMD_GPT_RENAME=y is +required.
+gpt repair +~~~~~~~~~~
+Repairs the GPT partition tables if it they become corrupted.
+gpt setenv +~~~~~~~~~~
+The 'gpt setenv' command will set a series of environment variables with +information about the partition named '<partition name>'. The variables are:
+gpt_partition_addr
- the starting offset of the partition in blocks as a hexadecimal number
+gpt_partition_size
- the size of the partition in blocks as a hexadecimal number
+gpt_partition_name
- the name of the partition
+gpt_partition_entry
- the partition number in the table, e.g. 1, 2, 3, etc.
Since eeef58401520 ("cmd: let gpt_partition_entry be hexadecimal") this is a hexadecimal number. As partitions are not required to be numbered start at 1:
%s/, e.g. 1, 2, 3, etc./as a hexadecimal number/
+gpt swap +~~~~~~~~
+Changes the names of all partitions that are named 'name1' to be 'name2', and +all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is +required.
+gpt verify +~~~~~~~~~~
+Sets return value $? to 0 (true) if the partition layout on the +specified disk matches the one in the provided partition string, and 1 (false) +if it does not match. If no partition string is specified, the command will +check if the disk is partitioned or not.
+gpt write +~~~~~~~~~
+(Re)writes the partition table on the disk to match the provided +partition string. It returns 0 on success or 1 on failure.
+Configuration +-------------
All other man-pages have Configuration after Examples.
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y.
+Examples +~~~~~~~~
An example for gpt read would be nice.
+Create 6 partitions on a disk:: > +
- => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4
- => gpt write mmc 0 $gpt_parts
There is a starting single quotation mark, but I don't see an ending single quotation mark.
White-space is not allowed before 'name='. As ugly as it is, please, put the whole setenv command into a single line.
You cannot use a comma before name=. It must be a semicolon.
Looking at the code the sequence in the partition descriptors seems to be wrong. It should be
uuid (optional if CONFIG_RANDOM_UUID=y), type (optional, only usable for CONFIG_PARTITION_TYPE_GUID=y), name (mandatory), size (mandatory), start (optional), bootable (optional). . Please, use a command that you have actually tested and copy it verbatim. sandbox_defconfig has a host bind command to attach a file as drive. That makes testing easy.
+Verify that the device matches the partition layout described in the variable +$gpt_parts::
- => gpt verify mmc 0 $gpt_parts
How about adding output here:
=> gpt verify mmc 0 $gpt_parts; echo $? 0
Best regards
Heinrich
+Get the information about the partition named 'rootfs'::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+Get the list of partition names on the disk::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
+Get the GUID for a disk::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
diff --git a/doc/usage/index.rst b/doc/usage/index.rst index f45a7f5502..fa702920fa 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -66,6 +66,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio
- cmd/gpt cmd/host cmd/imxtract cmd/load

On 8/29/23 00:45, Heinrich Schuchardt wrote:
/On 8/28/23 23:56, Joshua Watt wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 184 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 185 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..6387c8116f --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,184 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
+ gpt enumerate <interface> <dev> + gpt guid <interface> <dev> [<varname>] + gpt read <interface> <dev> [<varname>] + gpt rename <interface> <dev> <part> <name> + gpt repair <interface> <dev> + gpt setenv <interface> <dev> <partition name> + gpt swap <interface> <dev> <name1> <name2> + gpt verify <interface> <dev> [<partition string>] + gpt write <interface> <dev> <partition string>
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout.
+Common arguments:
+interface + interface for accessing the block device (mmc, sata, scsi, usb, ....)
+dev + device number
+partition string + Describes the GPT partition layout for a disk. The syntax is similar to + the one used by the :doc:`mbr command <mbr>` command. The string contains + one or more partition descriptors, each separated by a ";". Each descriptor + contains one or more fields, with each field separated by a ",". Fields are + either of the form "key=value" to set a specific value, or simple "flag" to + set a boolean flag
+ The first descriptor can optionally be used to describe parameters for the + whole disk with the following fields:
+ * uuid_disk=UUID - Set the UUID for the disk
+ Partition descriptors can have the following fields:
+ * name=<NAME> - The partition name, required + * start=<BYTES> - The partition start offset in bytes, required
The code has this comment: "start address is optional".
+ * size=<BYTES> - The partition size in bytes or "-" to expand it to the whole free area
This filed is mandatory.
+ * bootable - Set the legacy bootable flag
This field is optional
+ * uuid=<UUID> - The partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled + * type=<UUID> - The partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y
This field is optional
Thanks for all the updates. Looks much neater now.
The sequence expected in set_gpt_info() is:
uuid (optional if CONFIG_RANDOM_UUID=y), type (optional, only usable for CONFIG_PARTITION_TYPE_GUID=y), name (mandatory), size (mandatory), start (optional), bootable (optional).
A gross bug in the gpt command is that 'gpt read' creates a different sequence than 'gpt write' needs.
Furthermore 'gpt read' does not write all fields needed by 'gpt write' to recreate the partition table: bootable and type are missing.
Best regards
Heinrich
From the description above it is not clear that:
- semicolons are used to separate partitions
- the exact sequence of fields must be kept
- commas are used to separate fields
- no extra white-space is allowed.
+ If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID + will be generated for the partition
+gpt enumerate +~~~~~~~~~~~~~
+Sets the variable 'gpt_partition_list' to be a list of all the partition names +on the device.
+gpt guid +~~~~~~~~
+Report the GUID of a disk. If 'varname' is specified, the command will set the +variable to the GUID, otherwise it will be printed out.
+gpt read +~~~~~~~~
+Prints the current state of the GPT partition table. If 'varname' is specified, +the variable will be filled with a partition string in the same format as a +'<partition string>', suitable for passing to other 'gpt' commands. If the +argument is omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+gpt rename +~~~~~~~~~~
+Renames all partitions named 'part' to be 'name'. CONFIG_CMD_GPT_RENAME=y is +required.
+gpt repair +~~~~~~~~~~
+Repairs the GPT partition tables if it they become corrupted.
+gpt setenv +~~~~~~~~~~
+The 'gpt setenv' command will set a series of environment variables with +information about the partition named '<partition name>'. The variables are:
+gpt_partition_addr + the starting offset of the partition in blocks as a hexadecimal number
+gpt_partition_size + the size of the partition in blocks as a hexadecimal number
+gpt_partition_name + the name of the partition
+gpt_partition_entry + the partition number in the table, e.g. 1, 2, 3, etc.
Since eeef58401520 ("cmd: let gpt_partition_entry be hexadecimal") this is a hexadecimal number. As partitions are not required to be numbered start at 1:
%s/, e.g. 1, 2, 3, etc./as a hexadecimal number/
+gpt swap +~~~~~~~~
+Changes the names of all partitions that are named 'name1' to be 'name2', and +all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is +required.
+gpt verify +~~~~~~~~~~
+Sets return value $? to 0 (true) if the partition layout on the +specified disk matches the one in the provided partition string, and 1 (false) +if it does not match. If no partition string is specified, the command will +check if the disk is partitioned or not.
+gpt write +~~~~~~~~~
+(Re)writes the partition table on the disk to match the provided +partition string. It returns 0 on success or 1 on failure.
+Configuration +-------------
All other man-pages have Configuration after Examples.
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y.
+Examples +~~~~~~~~
An example for gpt read would be nice.
+Create 6 partitions on a disk:: > + + => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4 + => gpt write mmc 0 $gpt_parts
There is a starting single quotation mark, but I don't see an ending single quotation mark.
White-space is not allowed before 'name='. As ugly as it is, please, put the whole setenv command into a single line.
You cannot use a comma before name=. It must be a semicolon.
Looking at the code the sequence in the partition descriptors seems to be wrong. It should be
uuid (optional if CONFIG_RANDOM_UUID=y), type (optional, only usable for CONFIG_PARTITION_TYPE_GUID=y), name (mandatory), size (mandatory), start (optional), bootable (optional). . Please, use a command that you have actually tested and copy it verbatim. sandbox_defconfig has a host bind command to attach a file as drive. That makes testing easy.
+Verify that the device matches the partition layout described in the variable +$gpt_parts::
+ => gpt verify mmc 0 $gpt_parts
How about adding output here:
=> gpt verify mmc 0 $gpt_parts; echo $? 0
Best regards
Heinrich
+Get the information about the partition named 'rootfs'::
+ => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_addr} + 2000 + => echo ${gpt_partition_size} + 14a000 + => echo ${gpt_partition_name} + rootfs + => echo ${gpt_partition_entry} + 2
+Get the list of partition names on the disk::
+ => gpt enumerate + => echo gpt_partition_list + boot rootfs system-data [ext] user modules ramdisk
+Get the GUID for a disk::
+ => gpt guid mmc 0 + bec9fc2a-86c1-483d-8a0e-0109732277d7 + => gpt guid mmc gpt_disk_uuid + => echo ${gpt_disk_uuid} + bec9fc2a-86c1-483d-8a0e-0109732277d7 diff --git a/doc/usage/index.rst b/doc/usage/index.rst index f45a7f5502..fa702920fa 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -66,6 +66,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio + cmd/gpt cmd/host cmd/imxtract cmd/load

On Mon, Aug 28, 2023, 4:58 PM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/29/23 00:45, Heinrich Schuchardt wrote:
/On 8/28/23 23:56, Joshua Watt wrote:
Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
doc/usage/cmd/gpt.rst | 184 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 185 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..6387c8116f --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,184 @@ +.. SPDX-License-Identifier: GPL-2.0+
+gpt command +===========
+Synopsis +--------
+::
- gpt enumerate <interface> <dev>
- gpt guid <interface> <dev> [<varname>]
- gpt read <interface> <dev> [<varname>]
- gpt rename <interface> <dev> <part> <name>
- gpt repair <interface> <dev>
- gpt setenv <interface> <dev> <partition name>
- gpt swap <interface> <dev> <name1> <name2>
- gpt verify <interface> <dev> [<partition string>]
- gpt write <interface> <dev> <partition string>
+Description +-----------
+The gpt command lets users read, create, modify, or verify the GPT
(GUID
+Partition Table) partition layout.
+Common arguments:
+interface
- interface for accessing the block device (mmc, sata, scsi, usb,
....)
+dev
- device number
+partition string
- Describes the GPT partition layout for a disk. The syntax is
similar to
- the one used by the :doc:`mbr command <mbr>` command. The string
contains
- one or more partition descriptors, each separated by a ";". Each
descriptor
- contains one or more fields, with each field separated by a ",".
Fields are
- either of the form "key=value" to set a specific value, or simple
"flag" to
- set a boolean flag
- The first descriptor can optionally be used to describe
parameters for the
- whole disk with the following fields:
- uuid_disk=UUID - Set the UUID for the disk
- Partition descriptors can have the following fields:
- name=<NAME> - The partition name, required
- start=<BYTES> - The partition start offset in bytes, required
The code has this comment: "start address is optional".
- size=<BYTES> - The partition size in bytes or "-" to expand it
to the whole free area
This filed is mandatory.
- bootable - Set the legacy bootable flag
This field is optional
- uuid=<UUID> - The partition UUID, optional if
CONFIG_RANDOM_UUID=y is enabled
- type=<UUID> - The partition type GUID, requires
CONFIG_PARTITION_TYPE_GUID=y
This field is optional
Thanks for all the updates. Looks much neater now.
The sequence expected in set_gpt_info() is:
uuid (optional if CONFIG_RANDOM_UUID=y), type (optional, only usable for CONFIG_PARTITION_TYPE_GUID=y), name (mandatory), size (mandatory), start (optional), bootable (optional).
A gross bug in the gpt command is that 'gpt read' creates a different sequence than 'gpt write' needs.
Furthermore 'gpt read' does not write all fields needed by 'gpt write' to recreate the partition table: bootable and type are missing.
This is fixed in later patches in this series
Best regards
Heinrich
From the description above it is not clear that:
- semicolons are used to separate partitions
- the exact sequence of fields must be kept
- commas are used to separate fields
- no extra white-space is allowed.
- If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a
random UUID
- will be generated for the partition
+gpt enumerate +~~~~~~~~~~~~~
+Sets the variable 'gpt_partition_list' to be a list of all the partition names +on the device.
+gpt guid +~~~~~~~~
+Report the GUID of a disk. If 'varname' is specified, the command will set the +variable to the GUID, otherwise it will be printed out.
+gpt read +~~~~~~~~
+Prints the current state of the GPT partition table. If 'varname' is specified, +the variable will be filled with a partition string in the same format as a +'<partition string>', suitable for passing to other 'gpt' commands. If the +argument is omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required.
+gpt rename +~~~~~~~~~~
+Renames all partitions named 'part' to be 'name'. CONFIG_CMD_GPT_RENAME=y is +required.
+gpt repair +~~~~~~~~~~
+Repairs the GPT partition tables if it they become corrupted.
+gpt setenv +~~~~~~~~~~
+The 'gpt setenv' command will set a series of environment variables
with
+information about the partition named '<partition name>'. The variables are:
+gpt_partition_addr
- the starting offset of the partition in blocks as a hexadecimal
number
+gpt_partition_size
- the size of the partition in blocks as a hexadecimal number
+gpt_partition_name
- the name of the partition
+gpt_partition_entry
- the partition number in the table, e.g. 1, 2, 3, etc.
Since eeef58401520 ("cmd: let gpt_partition_entry be hexadecimal") this is a hexadecimal number. As partitions are not required to be numbered start at 1:
%s/, e.g. 1, 2, 3, etc./as a hexadecimal number/
+gpt swap +~~~~~~~~
+Changes the names of all partitions that are named 'name1' to be 'name2', and +all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is +required.
+gpt verify +~~~~~~~~~~
+Sets return value $? to 0 (true) if the partition layout on the +specified disk matches the one in the provided partition string, and 1 (false) +if it does not match. If no partition string is specified, the command will +check if the disk is partitioned or not.
+gpt write +~~~~~~~~~
+(Re)writes the partition table on the disk to match the provided +partition string. It returns 0 on success or 1 on failure.
+Configuration +-------------
All other man-pages have Configuration after Examples.
+To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y.
+Examples +~~~~~~~~
An example for gpt read would be nice.
+Create 6 partitions on a disk:: > +
- => setenv gpt_parts
'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7;
name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7,
name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4;
name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4
- => gpt write mmc 0 $gpt_parts
There is a starting single quotation mark, but I don't see an ending single quotation mark.
White-space is not allowed before 'name='. As ugly as it is, please, put the whole setenv command into a single line.
You cannot use a comma before name=. It must be a semicolon.
Looking at the code the sequence in the partition descriptors seems to be wrong. It should be
uuid (optional if CONFIG_RANDOM_UUID=y), type (optional, only usable for CONFIG_PARTITION_TYPE_GUID=y), name (mandatory), size (mandatory), start (optional), bootable (optional). . Please, use a command that you have actually tested and copy it verbatim. sandbox_defconfig has a host bind command to attach a file as drive. That makes testing easy.
+Verify that the device matches the partition layout described in the variable +$gpt_parts::
- => gpt verify mmc 0 $gpt_parts
How about adding output here:
=> gpt verify mmc 0 $gpt_parts; echo $? 0
Best regards
Heinrich
+Get the information about the partition named 'rootfs'::
- => gpt setenv mmc 0 rootfs
- => echo ${gpt_partition_addr}
- 2000
- => echo ${gpt_partition_size}
- 14a000
- => echo ${gpt_partition_name}
- rootfs
- => echo ${gpt_partition_entry}
- 2
+Get the list of partition names on the disk::
- => gpt enumerate
- => echo gpt_partition_list
- boot rootfs system-data [ext] user modules ramdisk
+Get the GUID for a disk::
- => gpt guid mmc 0
- bec9fc2a-86c1-483d-8a0e-0109732277d7
- => gpt guid mmc gpt_disk_uuid
- => echo ${gpt_disk_uuid}
- bec9fc2a-86c1-483d-8a0e-0109732277d7
diff --git a/doc/usage/index.rst b/doc/usage/index.rst index f45a7f5502..fa702920fa 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -66,6 +66,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio
- cmd/gpt cmd/host cmd/imxtract cmd/load

Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- test/py/tests/test_gpt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 73bfbf77a2..339468bc12 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -61,18 +61,14 @@ class GptTestDiskImage(object): cmd = ('cp', persistent, self.path) u_boot_utils.run_and_log(u_boot_console, cmd)
-gtdi = None @pytest.fixture(scope='function') def state_disk_image(u_boot_console): """pytest fixture to provide a GptTestDiskImage object to tests. This is function-scoped because it uses u_boot_console, which is also - function-scoped. However, we don't need to actually do any function-scope - work, so this simply returns the same object over and over each time.""" + function-scoped. A new disk is returned each time to prevent tests from + interfering with each other."""
- global gtdi - if not gtdi: - gtdi = GptTestDiskImage(u_boot_console) - return gtdi + return GptTestDiskImage(u_boot_console)
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @@ -186,12 +182,12 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console):
u_boot_console.run_command('host bind 0 ' + state_disk_image.path) output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "first"' in output - assert '0x00001000 0x00001bff "second"' in output - u_boot_console.run_command('gpt swap host 0 first second') + assert '0x00000800 0x00000fff "part1"' in output + assert '0x00001000 0x00001bff "part2"' in output + u_boot_console.run_command('gpt swap host 0 part1 part2') output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "second"' in output - assert '0x00001000 0x00001bff "first"' in output + assert '0x00000800 0x00000fff "part2"' in output + assert '0x00001000 0x00001bff "part1"' in output
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt')

Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 9 +++++++-- doc/usage/cmd/gpt.rst | 5 +++++ test/py/tests/test_gpt.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index fe9e06681c..c6c8282ac9 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -725,7 +725,7 @@ static int gpt_enumerate(struct blk_desc *desc) * gpt_setenv_part_variables() - setup partition environmental variables * * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr - * and gpt_partition_size environment variables. + * and gpt_partition_size, gpt_partition_bootable environment variables. * * @pinfo: pointer to disk partition * @i: partition entry @@ -752,6 +752,10 @@ static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) if (ret) goto fail;
+ ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE)); + if (ret) + goto fail; + return 0;
fail: @@ -1057,7 +1061,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt setenv mmc 0 $name\n" " - setup environment variables for partition $name:\n" " gpt_partition_addr, gpt_partition_size,\n" - " gpt_partition_name, gpt_partition_entry\n" + " gpt_partition_name, gpt_partition_entry,\n" + " gpt_partition_bootable\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" " gpt guid <interface> <dev>\n" diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 6387c8116f..b505b159d0 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -108,6 +108,9 @@ gpt_partition_name gpt_partition_entry the partition number in the table, e.g. 1, 2, 3, etc.
+gpt_partition_bootable + 1 if the partition is marked as bootable, 0 if not + gpt swap ~~~~~~~~
@@ -167,6 +170,8 @@ Get the information about the partition named 'rootfs':: rootfs => echo ${gpt_partition_entry} 2 + => echo ${gpt_partition_bootable} + 0
Get the list of partition names on the disk::
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 339468bc12..946858800d 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -49,6 +49,7 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) @@ -117,6 +118,38 @@ def test_gpt_guid(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_setenv(state_disk_image, u_boot_console): + """Test the gpt setenv command.""" + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt setenv host 0 part1') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part1' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == '1' + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == '1' + + output = u_boot_console.run_command('gpt setenv host 0 part2') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '1000' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == 'c00' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part2' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == '2' + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')

Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 12 ++++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 114 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index c6c8282ac9..45fbe07404 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -972,6 +972,81 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, free(partitions_list); return ret; } + +/** + * gpt_set_bootable() - Set bootable flags for partitions + * + * Sets the bootable flag for any partition names in the comma separated list of + * partition names. Any partitions not in the list have their bootable flag + * cleared + * + * @desc: block device descriptor + * @name: Comma separated list of partition names + * + * @Return: '0' on success and -ve error on failure + */ +static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) +{ + char *name; + char disk_guid[UUID_STR_LEN + 1]; + struct list_head *pos; + struct disk_part *curr; + struct disk_partition *partitions = NULL; + int part_count = 0; + int ret = get_disk_guid(blk_dev_desc, disk_guid); + + if (ret < 0) + return ret; + + ret = get_gpt_info(blk_dev_desc); + if (ret <= 0) + goto out; + + part_count = ret; + partitions = malloc(sizeof(*partitions) * part_count); + if (!partitions) { + ret = -ENOMEM; + goto out; + } + + /* Copy partitions and clear bootable flag */ + part_count = 0; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + partitions[part_count] = curr->gpt_part_info; + partitions[part_count].bootable &= ~PART_BOOTABLE; + part_count++; + } + + name = strtok(part_list, ","); + while (name) { + bool found = false; + + for (int i = 0; i < part_count; i++) { + if (strcmp((char *)partitions[i].name, name) == 0) { + partitions[i].bootable |= PART_BOOTABLE; + found = true; + } + } + + if (!found) { + printf("Warning: No partition matching '%s' found\n", + name); + } + + name = strtok(NULL, ","); + } + + ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count); + +out: + del_gpt_info(); + + if (partitions) + free(partitions); + + return ret; +} #endif
/** @@ -1031,6 +1106,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if ((strcmp(argv[1], "swap") == 0) || (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); + } else if ((strcmp(argv[1], "set-bootable") == 0)) { + ret = gpt_set_bootable(blk_dev_desc, argv[4]); #endif } else { return CMD_RET_USAGE; @@ -1082,8 +1159,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " and vice-versa\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" + " gpt set-bootable <interface> <dev> <list>\n" + " - make partition names in list bootable\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" + " gpt set-bootable mmc 0 boot_a,boot_b\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index b505b159d0..288dd365c0 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -13,6 +13,7 @@ Synopsis gpt read <interface> <dev> [<varname>] gpt rename <interface> <dev> <part> <name> gpt repair <interface> <dev> + gpt set-bootable <interface> <dev> <partition list> gpt setenv <interface> <dev> <partition name> gpt swap <interface> <dev> <name1> <name2> gpt verify <interface> <dev> [<partition string>] @@ -90,6 +91,13 @@ gpt repair
Repairs the GPT partition tables if it they become corrupted.
+gpt set-bootable +~~~~~~~~~~~~~~~~ + +Sets the bootable flag for all partitions in the table. If the partition name +is in 'partition list' (separated by ','), the bootable flag is set, otherwise +it is cleared. CONFIG_CMD_GPT_RENAME=y is required. + gpt setenv ~~~~~~~~~~
@@ -187,3 +195,7 @@ Get the GUID for a disk:: => gpt guid mmc gpt_disk_uuid => echo ${gpt_disk_uuid} bec9fc2a-86c1-483d-8a0e-0109732277d7 + +Set the bootable flag for the 'boot' partition and clear it for all others:: + + => gpt set-bootable mmc 0 boot diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 946858800d..5d23f9b292 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -222,6 +222,28 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part2"' in output assert '0x00001000 0x00001bff "part1"' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_set_bootable(state_disk_image, u_boot_console): + """Test the gpt set-bootable command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + parts = ('part2', 'part1') + for bootable in parts: + output = u_boot_console.run_command(f'gpt set-bootable host 0 {bootable}') + assert 'success!' in output + + for p in parts: + output = u_boot_console.run_command(f'gpt setenv host 0 {p}') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + if p == bootable: + assert output.rstrip() == '1' + else: + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.buildconfigspec('cmd_part')

On 8/28/23 23:56, Joshua Watt wrote:
Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 12 ++++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 114 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index c6c8282ac9..45fbe07404 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -972,6 +972,81 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, free(partitions_list); return ret; }
+/**
- gpt_set_bootable() - Set bootable flags for partitions
- Sets the bootable flag for any partition names in the comma separated list of
- partition names. Any partitions not in the list have their bootable flag
- cleared
- @desc: block device descriptor
- @name: Comma separated list of partition names
- @Return: '0' on success and -ve error on failure
- */
+static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) +{
- char *name;
- char disk_guid[UUID_STR_LEN + 1];
- struct list_head *pos;
- struct disk_part *curr;
- struct disk_partition *partitions = NULL;
- int part_count = 0;
- int ret = get_disk_guid(blk_dev_desc, disk_guid);
- if (ret < 0)
return ret;
- ret = get_gpt_info(blk_dev_desc);
- if (ret <= 0)
goto out;
- part_count = ret;
- partitions = malloc(sizeof(*partitions) * part_count);
- if (!partitions) {
ret = -ENOMEM;
goto out;
- }
- /* Copy partitions and clear bootable flag */
- part_count = 0;
- list_for_each(pos, &disk_partitions) {
curr = list_entry(pos, struct disk_part, list);
partitions[part_count] = curr->gpt_part_info;
partitions[part_count].bootable &= ~PART_BOOTABLE;
part_count++;
- }
- name = strtok(part_list, ",");
- while (name) {
bool found = false;
for (int i = 0; i < part_count; i++) {
if (strcmp((char *)partitions[i].name, name) == 0) {
partitions[i].bootable |= PART_BOOTABLE;
found = true;
}
}
if (!found) {
printf("Warning: No partition matching '%s' found\n",
name);
}
name = strtok(NULL, ",");
- }
- ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count);
+out:
- del_gpt_info();
- if (partitions)
free(partitions);
- return ret;
+} #endif
/** @@ -1031,6 +1106,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if ((strcmp(argv[1], "swap") == 0) || (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
- } else if ((strcmp(argv[1], "set-bootable") == 0)) {
#endif } else { return CMD_RET_USAGE;ret = gpt_set_bootable(blk_dev_desc, argv[4]);
@@ -1082,8 +1159,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " and vice-versa\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n"
- " gpt set-bootable <interface> <dev> <list>\n"
- " - make partition names in list bootable\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n"
- " gpt set-bootable mmc 0 boot_a,boot_b\n" #endif );
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index b505b159d0..288dd365c0 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -13,6 +13,7 @@ Synopsis gpt read <interface> <dev> [<varname>] gpt rename <interface> <dev> <part> <name> gpt repair <interface> <dev>
- gpt set-bootable <interface> <dev> <partition list> gpt setenv <interface> <dev> <partition name> gpt swap <interface> <dev> <name1> <name2> gpt verify <interface> <dev> [<partition string>]
@@ -90,6 +91,13 @@ gpt repair
Repairs the GPT partition tables if it they become corrupted.
+gpt set-bootable +~~~~~~~~~~~~~~~~
+Sets the bootable flag for all partitions in the table. If the partition name +is in 'partition list' (separated by ','), the bootable flag is set, otherwise +it is cleared. CONFIG_CMD_GPT_RENAME=y is required.
Why should this feature be related to CONFIG_CMD_GPT_RENAME?
Why do we need this sub-command? You can use gpt read and gpt write for this rarely needed manipulation.
Best regards
Heinrich
- gpt setenv
@@ -187,3 +195,7 @@ Get the GUID for a disk:: => gpt guid mmc gpt_disk_uuid => echo ${gpt_disk_uuid} bec9fc2a-86c1-483d-8a0e-0109732277d7
+Set the bootable flag for the 'boot' partition and clear it for all others::
- => gpt set-bootable mmc 0 boot
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 946858800d..5d23f9b292 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -222,6 +222,28 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part2"' in output assert '0x00001000 0x00001bff "part1"' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_set_bootable(state_disk_image, u_boot_console):
- """Test the gpt set-bootable command."""
- u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
- parts = ('part2', 'part1')
- for bootable in parts:
output = u_boot_console.run_command(f'gpt set-bootable host 0 {bootable}')
assert 'success!' in output
for p in parts:
output = u_boot_console.run_command(f'gpt setenv host 0 {p}')
assert 'success!' in output
output = u_boot_console.run_command('echo ${gpt_partition_bootable}')
if p == bootable:
assert output.rstrip() == '1'
else:
assert output.rstrip() == '0'
- @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.buildconfigspec('cmd_part')

On Mon, Aug 28, 2023, 4:53 PM Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 8/28/23 23:56, Joshua Watt wrote:
Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 12 ++++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 114 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index c6c8282ac9..45fbe07404 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -972,6 +972,81 @@ static int do_rename_gpt_parts(struct blk_desc
*dev_desc, char *subcomm,
free(partitions_list); return ret;
}
+/**
- gpt_set_bootable() - Set bootable flags for partitions
- Sets the bootable flag for any partition names in the comma
separated list of
- partition names. Any partitions not in the list have their bootable
flag
- cleared
- @desc: block device descriptor
- @name: Comma separated list of partition names
- @Return: '0' on success and -ve error on failure
- */
+static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const
part_list)
+{
char *name;
char disk_guid[UUID_STR_LEN + 1];
struct list_head *pos;
struct disk_part *curr;
struct disk_partition *partitions = NULL;
int part_count = 0;
int ret = get_disk_guid(blk_dev_desc, disk_guid);
if (ret < 0)
return ret;
ret = get_gpt_info(blk_dev_desc);
if (ret <= 0)
goto out;
part_count = ret;
partitions = malloc(sizeof(*partitions) * part_count);
if (!partitions) {
ret = -ENOMEM;
goto out;
}
/* Copy partitions and clear bootable flag */
part_count = 0;
list_for_each(pos, &disk_partitions) {
curr = list_entry(pos, struct disk_part, list);
partitions[part_count] = curr->gpt_part_info;
partitions[part_count].bootable &= ~PART_BOOTABLE;
part_count++;
}
name = strtok(part_list, ",");
while (name) {
bool found = false;
for (int i = 0; i < part_count; i++) {
if (strcmp((char *)partitions[i].name, name) == 0)
{
partitions[i].bootable |= PART_BOOTABLE;
found = true;
}
}
if (!found) {
printf("Warning: No partition matching '%s'
found\n",
name);
}
name = strtok(NULL, ",");
}
ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count);
+out:
del_gpt_info();
if (partitions)
free(partitions);
return ret;
+} #endif
/** @@ -1031,6 +1106,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag,
int argc, char *const argv[])
} else if ((strcmp(argv[1], "swap") == 0) || (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4],
argv[5]);
} else if ((strcmp(argv[1], "set-bootable") == 0)) {
#endif } else { return CMD_RET_USAGE;ret = gpt_set_bootable(blk_dev_desc, argv[4]);
@@ -1082,8 +1159,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " and vice-versa\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n"
" gpt set-bootable <interface> <dev> <list>\n"
" - make partition names in list bootable\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n"
#endif );" gpt set-bootable mmc 0 boot_a,boot_b\n"
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index b505b159d0..288dd365c0 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -13,6 +13,7 @@ Synopsis gpt read <interface> <dev> [<varname>] gpt rename <interface> <dev> <part> <name> gpt repair <interface> <dev>
- gpt set-bootable <interface> <dev> <partition list> gpt setenv <interface> <dev> <partition name> gpt swap <interface> <dev> <name1> <name2> gpt verify <interface> <dev> [<partition string>]
@@ -90,6 +91,13 @@ gpt repair
Repairs the GPT partition tables if it they become corrupted.
+gpt set-bootable +~~~~~~~~~~~~~~~~
+Sets the bootable flag for all partitions in the table. If the
partition name
+is in 'partition list' (separated by ','), the bootable flag is set,
otherwise
+it is cleared. CONFIG_CMD_GPT_RENAME=y is required.
Why should this feature be related to CONFIG_CMD_GPT_RENAME?
Commands that write to the partition table seem to need this (probably poorly named) config.
Why do we need this sub-command? You can use gpt read and gpt write for this rarely needed manipulation.
Dealing with the string parsing in a script is cantankerous and annoying, unless I'm missing something that magically makes it easy
Best regards
Heinrich
- gpt setenv
@@ -187,3 +195,7 @@ Get the GUID for a disk:: => gpt guid mmc gpt_disk_uuid => echo ${gpt_disk_uuid} bec9fc2a-86c1-483d-8a0e-0109732277d7
+Set the bootable flag for the 'boot' partition and clear it for all
others::
- => gpt set-bootable mmc 0 boot
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 946858800d..5d23f9b292 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -222,6 +222,28 @@ def test_gpt_swap_partitions(state_disk_image,
u_boot_console):
assert '0x00000800 0x00000fff "part2"' in output assert '0x00001000 0x00001bff "part1"' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_set_bootable(state_disk_image, u_boot_console):
- """Test the gpt set-bootable command."""
- u_boot_console.run_command('host bind 0 ' + state_disk_image.path)
- parts = ('part2', 'part1')
- for bootable in parts:
output = u_boot_console.run_command(f'gpt set-bootable host 0
{bootable}')
assert 'success!' in output
for p in parts:
output = u_boot_console.run_command(f'gpt setenv host 0
{p}')
assert 'success!' in output
output = u_boot_console.run_command('echo
${gpt_partition_bootable}')
if p == bootable:
assert output.rstrip() == '1'
else:
assert output.rstrip() == '0'
- @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.buildconfigspec('cmd_part')

If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 16 ++++++++++ test/py/tests/test_gpt.py | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 45fbe07404..0090e02110 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID + partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); +#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID + strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid, + UUID_STR_LEN); + newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0'; +#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID + printf("Type GUID %s\n", curr->gpt_part_info.type_guid); +#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID + strcat(partitions_list, ",type="); + strncat(partitions_list, curr->gpt_part_info.type_guid, + UUID_STR_LEN + 1); +#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 5d23f9b292..93007dee9a 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -16,6 +16,35 @@ the test. # Mark all tests here as slow pytestmark = pytest.mark.slow
+def parse_gpt_parts(disk_str): + """Parser a partition string into a list of partitions. + + Args: + disk_str: The disk description string, as returned by `gpt read` + + Returns: + A list of parsed partitions. Each partition is a dictionary with the + string value from each specified key in the partition description, or a + key with with the value True for a boolean flag + """ + parts = [] + for part_str in disk_str.split(';'): + part = {} + for option in part_str.split(","): + if not option: + continue + + if "=" in option: + key, value = option.split("=") + part[key] = value + else: + part[option] = True + + if part: + parts.append(part) + + return parts + class GptTestDiskImage(object): """Disk Image used by the GPT tests."""
@@ -49,11 +78,13 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2', + '--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', persistent) u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--load-backup=' + persistent) @@ -88,6 +119,40 @@ def test_gpt_read(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part1"' in output assert '0x00001000 0x00001bff "part2"' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('partition_type_guid') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_read_var(state_disk_image, u_boot_console): + """Test the gpt read command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt read host 0 gpt_parts') + assert 'success!' in output + + output = u_boot_console.run_command('echo ${gpt_parts}') + parts = parse_gpt_parts(output.rstrip()) + + assert parts == [ + { + "uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe", + }, + { + "name": "part1", + "start": "0x100000", + "size": "0x100000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + }, + { + "name": "part2", + "start": "0x200000", + "size": "0x180000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb", + }, + ] + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')

Sets the bootable flag when constructing the partition string from the current partition configuration. This ensures that when the partitions are written back (for example, when renaming a partition), the flag is preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 3 +++ test/py/tests/test_gpt.py | 1 + 2 files changed, 4 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 0090e02110..927b6afa68 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -176,6 +176,7 @@ static int calc_parts_list_len(int numparts) #ifdef CONFIG_PARTITION_TYPE_GUID partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); #endif + partlistlen += numparts * strlen("bootable,"); partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -318,6 +319,8 @@ static int create_gpt_partitions_list(int numparts, const char *guid, strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); + if (curr->gpt_part_info.bootable & PART_BOOTABLE) + strcat(partitions_list, ",bootable"); strcat(partitions_list, ";"); } return 0; diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 93007dee9a..b4c03bc3a2 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -143,6 +143,7 @@ def test_gpt_read_var(state_disk_image, u_boot_console): "size": "0x100000", "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + "bootable": True, }, { "name": "part2",

Adds a command called "gpt swap-postition" which will swap the order two partition table entries in the GPT partition table (but leaves them pointing to the same locations on disk).
This can be useful for swapping bootloaders in systems that use an A/B partitioning scheme where the bootrom is hard coded to look for the bootloader in a specific index in the GPT partition table.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 46 ++++++++++++++++++++++++++++++++++++--- doc/usage/cmd/gpt.rst | 25 +++++++++++++++++++++ test/py/tests/test_gpt.py | 19 ++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 927b6afa68..c7d3f65ff2 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -858,8 +858,9 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, u8 part_count = 0; int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
- if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || - (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) + if (!subcomm || !name1 || !name2 || + (strcmp(subcomm, "swap") && strcmp(subcomm, "rename") && + strcmp(subcomm, "swap-position"))) return -EINVAL;
ret = get_disk_guid(dev_desc, disk_guid); @@ -920,6 +921,41 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; } + } else if (!strcmp(subcomm, "swap-position")) { + int idx1, idx2; + struct disk_partition* first = NULL; + struct disk_partition* second= NULL; + struct disk_partition tmp_part; + + idx1 = simple_strtoul(name1, NULL, 10); + idx2 = simple_strtoul(name2, NULL, 10); + if (idx1 == idx2) { + printf("Cannot swap partition with itself\n"); + ret = -EINVAL; + goto out; + } + + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (curr->partnum == idx1) + first = &curr->gpt_part_info; + else if (curr->partnum == idx2) + second = &curr->gpt_part_info; + } + if (!first) { + printf("Illegal partition number %s\n", name1); + ret = -EINVAL; + goto out; + } + if (!second) { + printf("Illegal partition number %s\n", name2); + ret = -EINVAL; + goto out; + } + + tmp_part = *first; + *first = *second; + *second = tmp_part; } else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); @@ -1123,7 +1159,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) || - (strcmp(argv[1], "rename") == 0)) { + (strcmp(argv[1], "rename") == 0) || + (strcmp(argv[1], "swap-position") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); } else if ((strcmp(argv[1], "set-bootable") == 0)) { ret = gpt_set_bootable(blk_dev_desc, argv[4]); @@ -1176,6 +1213,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n" + " gpt swap-position <interface> <dev> <part1> <part2>\n" + " - Swap the order of the entries for part1 and part2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " gpt set-bootable <interface> <dev> <list>\n" @@ -1184,5 +1223,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" " gpt set-bootable mmc 0 boot_a,boot_b\n" + " gpt swap-position mmc 0 1 2\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 288dd365c0..b2aaf4a701 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -16,6 +16,7 @@ Synopsis gpt set-bootable <interface> <dev> <partition list> gpt setenv <interface> <dev> <partition name> gpt swap <interface> <dev> <name1> <name2> + gpt swap-position <interface> <dev> <part1> <part2> gpt verify <interface> <dev> [<partition string>] gpt write <interface> <dev> <partition string>
@@ -126,6 +127,13 @@ Changes the names of all partitions that are named 'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+gpt swap-position +~~~~~~~~~~~~~~~~~ + +Swaps the order of two partition table entries with indexes 'part1' and 'part2' +in the partition table, but otherwise leaves the actual partition data +untouched. + gpt verify ~~~~~~~~~~
@@ -199,3 +207,20 @@ Get the GUID for a disk:: Set the bootable flag for the 'boot' partition and clear it for all others::
=> gpt set-bootable mmc 0 boot + +Swap the order of the 'boot' and 'rootfs' partition table entries:: + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 2 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 1 + + => gpt swap-position mmc 0 1 2 + + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 1 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 2 diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index b4c03bc3a2..5a106c038c 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -329,3 +329,22 @@ def test_gpt_write(state_disk_image, u_boot_console): assert '0x00001000 0x00001bff "second"' in output output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output + +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_swap_position(state_disk_image, u_boot_console): + """Test the gpt swap-position command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('part list host 0') + assert '1\t0x00000800\t0x00000fff\t"part1"' in output + assert '2\t0x00001000\t0x00001bff\t"part2"' in output + + output = u_boot_console.run_command('gpt swap-position host 0 1 2') + assert 'success!' in output + + output = u_boot_console.run_command('part list host 0') + assert '2\t0x00000800\t0x00000fff\t"part1"' in output + assert '1\t0x00001000\t0x00001bff\t"part2"' in output

Adds several improvements and additions to the gpt command processing, specifically (although not exclusively) for the purpose of supporting "ping-pong" booting when doing A/B boot partitions with u-boot itself.
In this mechanism, u-boot must boot up, and then check if the correct boot partition is active, and if not switch the GPT partition table to the other boot partition and reboot to activate the other u-boot.
In order to facilitate this, the gpt command needs to be better at preserving entry attributes when manipulating the partition table. It also learns two new commands, one which can swap the order of partitions in the table, and another that lets it change which partitions have the bootable flag.
V2: Add documentation and tests V3: Review Feedback V4: More review feedback. Fixed 'gpt swap-position' to work with missing partition indexes. V5: Rename 'gpt swap-position' -> 'gpt transpose', taking inspiration from `sgdisk --transpose`
Joshua Watt (8): cmd: gpt: Remove confusing help text doc: Add gpt command documentation tests: gpt: Remove test order dependency cmd: gpt: Add gpt_partition_bootable variable cmd: gpt: Add command to set bootable flags cmd: gpt: Preserve type GUID if enabled cmd: gpt: Preserve bootable flag cmd: gpt: Add command to swap partition order
cmd/gpt.c | 156 ++++++++++++++++++++++++-- doc/usage/cmd/gpt.rst | 226 ++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + test/py/tests/test_gpt.py | 160 +++++++++++++++++++++++++-- 4 files changed, 524 insertions(+), 19 deletions(-) create mode 100644 doc/usage/cmd/gpt.rst

This help text appears to be a fragment of the text shown when CONFIG_CMD_GPT_RENAME is enabled, but is confusing so remove it.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 2 -- 1 file changed, 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 964056bd28..fe9e06681c 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -1060,8 +1060,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt_partition_name, gpt_partition_entry\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" - " read <interface> <dev>\n" - " - read GPT into a data structure for manipulation\n" " gpt guid <interface> <dev>\n" " - print disk GUID\n" " gpt guid <interface> <dev> <varname>\n"

Adds initial documentation for the gpt command
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- doc/usage/cmd/gpt.rst | 184 ++++++++++++++++++++++++++++++++++++++++++ doc/usage/index.rst | 1 + 2 files changed, 185 insertions(+) create mode 100644 doc/usage/cmd/gpt.rst
diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst new file mode 100644 index 0000000000..6387c8116f --- /dev/null +++ b/doc/usage/cmd/gpt.rst @@ -0,0 +1,184 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +gpt command +=========== + +Synopsis +-------- + +:: + + gpt enumerate <interface> <dev> + gpt guid <interface> <dev> [<varname>] + gpt read <interface> <dev> [<varname>] + gpt rename <interface> <dev> <part> <name> + gpt repair <interface> <dev> + gpt setenv <interface> <dev> <partition name> + gpt swap <interface> <dev> <name1> <name2> + gpt verify <interface> <dev> [<partition string>] + gpt write <interface> <dev> <partition string> + +Description +----------- + +The gpt command lets users read, create, modify, or verify the GPT (GUID +Partition Table) partition layout. + +Common arguments: + +interface + interface for accessing the block device (mmc, sata, scsi, usb, ....) + +dev + device number + +partition string + Describes the GPT partition layout for a disk. The syntax is similar to + the one used by the :doc:`mbr command <mbr>` command. The string contains + one or more partition descriptors, each separated by a ";". Each descriptor + contains one or more fields, with each field separated by a ",". Fields are + either of the form "key=value" to set a specific value, or simple "flag" to + set a boolean flag + + The first descriptor can optionally be used to describe parameters for the + whole disk with the following fields: + + * uuid_disk=UUID - Set the UUID for the disk + + Partition descriptors can have the following fields: + + * name=<NAME> - The partition name, required + * start=<BYTES> - The partition start offset in bytes, required + * size=<BYTES> - The partition size in bytes or "-" to expand it to the whole free area + * bootable - Set the legacy bootable flag + * uuid=<UUID> - The partition UUID, optional if CONFIG_RANDOM_UUID=y is enabled + * type=<UUID> - The partition type GUID, requires CONFIG_PARTITION_TYPE_GUID=y + + + If 'uuid' is not specified, but CONFIG_RANDOM_UUID is enabled, a random UUID + will be generated for the partition + +gpt enumerate +~~~~~~~~~~~~~ + +Sets the variable 'gpt_partition_list' to be a list of all the partition names +on the device. + +gpt guid +~~~~~~~~ + +Report the GUID of a disk. If 'varname' is specified, the command will set the +variable to the GUID, otherwise it will be printed out. + +gpt read +~~~~~~~~ + +Prints the current state of the GPT partition table. If 'varname' is specified, +the variable will be filled with a partition string in the same format as a +'<partition string>', suitable for passing to other 'gpt' commands. If the +argument is omitted, a human readable description is printed out. +CONFIG_CMD_GPT_RENAME=y is required. + +gpt rename +~~~~~~~~~~ + +Renames all partitions named 'part' to be 'name'. CONFIG_CMD_GPT_RENAME=y is +required. + +gpt repair +~~~~~~~~~~ + +Repairs the GPT partition tables if it they become corrupted. + +gpt setenv +~~~~~~~~~~ + +The 'gpt setenv' command will set a series of environment variables with +information about the partition named '<partition name>'. The variables are: + +gpt_partition_addr + the starting offset of the partition in blocks as a hexadecimal number + +gpt_partition_size + the size of the partition in blocks as a hexadecimal number + +gpt_partition_name + the name of the partition + +gpt_partition_entry + the partition number in the table, e.g. 1, 2, 3, etc. + +gpt swap +~~~~~~~~ + +Changes the names of all partitions that are named 'name1' to be 'name2', and +all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is +required. + +gpt verify +~~~~~~~~~~ + +Sets return value $? to 0 (true) if the partition layout on the +specified disk matches the one in the provided partition string, and 1 (false) +if it does not match. If no partition string is specified, the command will +check if the disk is partitioned or not. + +gpt write +~~~~~~~~~ + +(Re)writes the partition table on the disk to match the provided +partition string. It returns 0 on success or 1 on failure. + +Configuration +------------- + +To use the 'gpt' command you must specify CONFIG_CMD_GPT=y. To enable 'gpt +read', 'gpt swap' and 'gpt rename', you must specify CONFIG_CMD_GPT_RENAME=y. + +Examples +~~~~~~~~ +Create 6 partitions on a disk:: + + => setenv gpt_parts 'uuid_disk=bec9fc2a-86c1-483d-8a0e-0109732277d7; + name=boot,start=4M,size=128M,bootable,type=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7, + name=rootfs,size=3072M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=system-data,size=512M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=[ext],size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=user,size=-,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=modules,size=100M,type=0fc63daf-8483-4772-8e79-3d69d8477de4; + name=ramdisk,size=8M,type=0fc63daf-8483-4772-8e79-3d69d8477de4 + => gpt write mmc 0 $gpt_parts + + +Verify that the device matches the partition layout described in the variable +$gpt_parts:: + + => gpt verify mmc 0 $gpt_parts + + +Get the information about the partition named 'rootfs':: + + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_addr} + 2000 + => echo ${gpt_partition_size} + 14a000 + => echo ${gpt_partition_name} + rootfs + => echo ${gpt_partition_entry} + 2 + +Get the list of partition names on the disk:: + + => gpt enumerate + => echo gpt_partition_list + boot rootfs system-data [ext] user modules ramdisk + + +Get the GUID for a disk:: + + => gpt guid mmc 0 + bec9fc2a-86c1-483d-8a0e-0109732277d7 + => gpt guid mmc gpt_disk_uuid + => echo ${gpt_disk_uuid} + bec9fc2a-86c1-483d-8a0e-0109732277d7 diff --git a/doc/usage/index.rst b/doc/usage/index.rst index f45a7f5502..fa702920fa 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -66,6 +66,7 @@ Shell commands cmd/for cmd/fwu_mdata cmd/gpio + cmd/gpt cmd/host cmd/imxtract cmd/load

Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- test/py/tests/test_gpt.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-)
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 73bfbf77a2..339468bc12 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -61,18 +61,14 @@ class GptTestDiskImage(object): cmd = ('cp', persistent, self.path) u_boot_utils.run_and_log(u_boot_console, cmd)
-gtdi = None @pytest.fixture(scope='function') def state_disk_image(u_boot_console): """pytest fixture to provide a GptTestDiskImage object to tests. This is function-scoped because it uses u_boot_console, which is also - function-scoped. However, we don't need to actually do any function-scope - work, so this simply returns the same object over and over each time.""" + function-scoped. A new disk is returned each time to prevent tests from + interfering with each other."""
- global gtdi - if not gtdi: - gtdi = GptTestDiskImage(u_boot_console) - return gtdi + return GptTestDiskImage(u_boot_console)
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @@ -186,12 +182,12 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console):
u_boot_console.run_command('host bind 0 ' + state_disk_image.path) output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "first"' in output - assert '0x00001000 0x00001bff "second"' in output - u_boot_console.run_command('gpt swap host 0 first second') + assert '0x00000800 0x00000fff "part1"' in output + assert '0x00001000 0x00001bff "part2"' in output + u_boot_console.run_command('gpt swap host 0 part1 part2') output = u_boot_console.run_command('part list host 0') - assert '0x00000800 0x00000fff "second"' in output - assert '0x00001000 0x00001bff "first"' in output + assert '0x00000800 0x00000fff "part2"' in output + assert '0x00001000 0x00001bff "part1"' in output
@pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt')

On Thu, Aug 31, 2023 at 10:51:36AM -0600, Joshua Watt wrote:
Re-create a clean disk image for each test to prevent modifications from one test affecting another
Signed-off-by: Joshua Watt JPEWhacker@gmail.com
For the series, applied to u-boot/next, thanks!

Adds an additional variable called gpt_partition_bootable that indicates if the given partition is bootable or not.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 9 +++++++-- doc/usage/cmd/gpt.rst | 5 +++++ test/py/tests/test_gpt.py | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index fe9e06681c..c6c8282ac9 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -725,7 +725,7 @@ static int gpt_enumerate(struct blk_desc *desc) * gpt_setenv_part_variables() - setup partition environmental variables * * Setup the gpt_partition_name, gpt_partition_entry, gpt_partition_addr - * and gpt_partition_size environment variables. + * and gpt_partition_size, gpt_partition_bootable environment variables. * * @pinfo: pointer to disk partition * @i: partition entry @@ -752,6 +752,10 @@ static int gpt_setenv_part_variables(struct disk_partition *pinfo, int i) if (ret) goto fail;
+ ret = env_set_ulong("gpt_partition_bootable", !!(pinfo->bootable & PART_BOOTABLE)); + if (ret) + goto fail; + return 0;
fail: @@ -1057,7 +1061,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt setenv mmc 0 $name\n" " - setup environment variables for partition $name:\n" " gpt_partition_addr, gpt_partition_size,\n" - " gpt_partition_name, gpt_partition_entry\n" + " gpt_partition_name, gpt_partition_entry,\n" + " gpt_partition_bootable\n" " gpt enumerate mmc 0\n" " - store list of partitions to gpt_partition_list environment variable\n" " gpt guid <interface> <dev>\n" diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 6387c8116f..b505b159d0 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -108,6 +108,9 @@ gpt_partition_name gpt_partition_entry the partition number in the table, e.g. 1, 2, 3, etc.
+gpt_partition_bootable + 1 if the partition is marked as bootable, 0 if not + gpt swap ~~~~~~~~
@@ -167,6 +170,8 @@ Get the information about the partition named 'rootfs':: rootfs => echo ${gpt_partition_entry} 2 + => echo ${gpt_partition_bootable} + 0
Get the list of partition names on the disk::
diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 339468bc12..946858800d 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -49,6 +49,7 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) @@ -117,6 +118,38 @@ def test_gpt_guid(state_disk_image, u_boot_console): output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_setenv(state_disk_image, u_boot_console): + """Test the gpt setenv command.""" + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt setenv host 0 part1') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == '800' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part1' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == '1' + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == '1' + + output = u_boot_console.run_command('gpt setenv host 0 part2') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_addr}') + assert output.rstrip() == '1000' + output = u_boot_console.run_command('echo ${gpt_partition_size}') + assert output.rstrip() == 'c00' + output = u_boot_console.run_command('echo ${gpt_partition_name}') + assert output.rstrip() == 'part2' + output = u_boot_console.run_command('echo ${gpt_partition_entry}') + assert output.rstrip() == '2' + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')

Adds a command that can be used to modify the GPT partition table to indicate which partitions should have the bootable flag set
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 80 +++++++++++++++++++++++++++++++++++++++ doc/usage/cmd/gpt.rst | 12 ++++++ test/py/tests/test_gpt.py | 22 +++++++++++ 3 files changed, 114 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index c6c8282ac9..45fbe07404 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -972,6 +972,81 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, free(partitions_list); return ret; } + +/** + * gpt_set_bootable() - Set bootable flags for partitions + * + * Sets the bootable flag for any partition names in the comma separated list of + * partition names. Any partitions not in the list have their bootable flag + * cleared + * + * @desc: block device descriptor + * @name: Comma separated list of partition names + * + * @Return: '0' on success and -ve error on failure + */ +static int gpt_set_bootable(struct blk_desc *blk_dev_desc, char *const part_list) +{ + char *name; + char disk_guid[UUID_STR_LEN + 1]; + struct list_head *pos; + struct disk_part *curr; + struct disk_partition *partitions = NULL; + int part_count = 0; + int ret = get_disk_guid(blk_dev_desc, disk_guid); + + if (ret < 0) + return ret; + + ret = get_gpt_info(blk_dev_desc); + if (ret <= 0) + goto out; + + part_count = ret; + partitions = malloc(sizeof(*partitions) * part_count); + if (!partitions) { + ret = -ENOMEM; + goto out; + } + + /* Copy partitions and clear bootable flag */ + part_count = 0; + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + partitions[part_count] = curr->gpt_part_info; + partitions[part_count].bootable &= ~PART_BOOTABLE; + part_count++; + } + + name = strtok(part_list, ","); + while (name) { + bool found = false; + + for (int i = 0; i < part_count; i++) { + if (strcmp((char *)partitions[i].name, name) == 0) { + partitions[i].bootable |= PART_BOOTABLE; + found = true; + } + } + + if (!found) { + printf("Warning: No partition matching '%s' found\n", + name); + } + + name = strtok(NULL, ","); + } + + ret = gpt_restore(blk_dev_desc, disk_guid, partitions, part_count); + +out: + del_gpt_info(); + + if (partitions) + free(partitions); + + return ret; +} #endif
/** @@ -1031,6 +1106,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if ((strcmp(argv[1], "swap") == 0) || (strcmp(argv[1], "rename") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); + } else if ((strcmp(argv[1], "set-bootable") == 0)) { + ret = gpt_set_bootable(blk_dev_desc, argv[4]); #endif } else { return CMD_RET_USAGE; @@ -1082,8 +1159,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " and vice-versa\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" + " gpt set-bootable <interface> <dev> <list>\n" + " - make partition names in list bootable\n" " Example usage:\n" " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" + " gpt set-bootable mmc 0 boot_a,boot_b\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index b505b159d0..288dd365c0 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -13,6 +13,7 @@ Synopsis gpt read <interface> <dev> [<varname>] gpt rename <interface> <dev> <part> <name> gpt repair <interface> <dev> + gpt set-bootable <interface> <dev> <partition list> gpt setenv <interface> <dev> <partition name> gpt swap <interface> <dev> <name1> <name2> gpt verify <interface> <dev> [<partition string>] @@ -90,6 +91,13 @@ gpt repair
Repairs the GPT partition tables if it they become corrupted.
+gpt set-bootable +~~~~~~~~~~~~~~~~ + +Sets the bootable flag for all partitions in the table. If the partition name +is in 'partition list' (separated by ','), the bootable flag is set, otherwise +it is cleared. CONFIG_CMD_GPT_RENAME=y is required. + gpt setenv ~~~~~~~~~~
@@ -187,3 +195,7 @@ Get the GUID for a disk:: => gpt guid mmc gpt_disk_uuid => echo ${gpt_disk_uuid} bec9fc2a-86c1-483d-8a0e-0109732277d7 + +Set the bootable flag for the 'boot' partition and clear it for all others:: + + => gpt set-bootable mmc 0 boot diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 946858800d..5d23f9b292 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -222,6 +222,28 @@ def test_gpt_swap_partitions(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part2"' in output assert '0x00001000 0x00001bff "part1"' in output
+@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_set_bootable(state_disk_image, u_boot_console): + """Test the gpt set-bootable command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + parts = ('part2', 'part1') + for bootable in parts: + output = u_boot_console.run_command(f'gpt set-bootable host 0 {bootable}') + assert 'success!' in output + + for p in parts: + output = u_boot_console.run_command(f'gpt setenv host 0 {p}') + assert 'success!' in output + output = u_boot_console.run_command('echo ${gpt_partition_bootable}') + if p == bootable: + assert output.rstrip() == '1' + else: + assert output.rstrip() == '0' + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.buildconfigspec('cmd_part')

If CONFIG_PARTITION_TYPE_GUID is enabled, the type GUID will be preserved when writing out the partition string. It was already respected when writing out partitions; this ensures that if you capture the current partition layout and write it back (such as when renaming), the type GUIDs are preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 16 ++++++++++ test/py/tests/test_gpt.py | 65 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 45fbe07404..0090e02110 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -173,6 +173,9 @@ static int calc_parts_list_len(int numparts) /* see part.h for definition of struct disk_partition */ partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1); partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1); +#ifdef CONFIG_PARTITION_TYPE_GUID + partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); +#endif partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -211,6 +214,11 @@ static struct disk_part *allocate_disk_part(struct disk_partition *info, PART_TYPE_LEN); newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0'; newpart->gpt_part_info.bootable = info->bootable; +#ifdef CONFIG_PARTITION_TYPE_GUID + strncpy(newpart->gpt_part_info.type_guid, (const char *)info->type_guid, + UUID_STR_LEN); + newpart->gpt_part_info.type_guid[UUID_STR_LEN] = '\0'; +#endif #ifdef CONFIG_PARTITION_UUIDS strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid, UUID_STR_LEN); @@ -252,6 +260,9 @@ static void print_gpt_info(void) curr->gpt_part_info.name); printf("Type %s, bootable %d\n", curr->gpt_part_info.type, curr->gpt_part_info.bootable & PART_BOOTABLE); +#ifdef CONFIG_PARTITION_TYPE_GUID + printf("Type GUID %s\n", curr->gpt_part_info.type_guid); +#endif #ifdef CONFIG_PARTITION_UUIDS printf("UUID %s\n", curr->gpt_part_info.uuid); #endif @@ -299,6 +310,11 @@ static int create_gpt_partitions_list(int numparts, const char *guid, curr->gpt_part_info.blksz); strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+#ifdef CONFIG_PARTITION_TYPE_GUID + strcat(partitions_list, ",type="); + strncat(partitions_list, curr->gpt_part_info.type_guid, + UUID_STR_LEN + 1); +#endif strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 5d23f9b292..93007dee9a 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -16,6 +16,35 @@ the test. # Mark all tests here as slow pytestmark = pytest.mark.slow
+def parse_gpt_parts(disk_str): + """Parser a partition string into a list of partitions. + + Args: + disk_str: The disk description string, as returned by `gpt read` + + Returns: + A list of parsed partitions. Each partition is a dictionary with the + string value from each specified key in the partition description, or a + key with with the value True for a boolean flag + """ + parts = [] + for part_str in disk_str.split(';'): + part = {} + for option in part_str.split(","): + if not option: + continue + + if "=" in option: + key, value = option.split("=") + part[key] = value + else: + part[option] = True + + if part: + parts.append(part) + + return parts + class GptTestDiskImage(object): """Disk Image used by the GPT tests."""
@@ -49,11 +78,13 @@ class GptTestDiskImage(object): u_boot_utils.run_and_log(u_boot_console, cmd) # part1 offset 1MB size 1MB cmd = ('sgdisk', '--new=1:2048:4095', '--change-name=1:part1', + '--partition-guid=1:33194895-67f6-4561-8457-6fdeed4f50a3', '-A 1:set:2', persistent) # part2 offset 2MB size 1.5MB u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--new=2:4096:7167', '--change-name=2:part2', + '--partition-guid=2:cc9c6e4a-6551-4cb5-87be-3210f96c86fb', persistent) u_boot_utils.run_and_log(u_boot_console, cmd) cmd = ('sgdisk', '--load-backup=' + persistent) @@ -88,6 +119,40 @@ def test_gpt_read(state_disk_image, u_boot_console): assert '0x00000800 0x00000fff "part1"' in output assert '0x00001000 0x00001bff "part2"' in output
+@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('partition_type_guid') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_read_var(state_disk_image, u_boot_console): + """Test the gpt read command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('gpt read host 0 gpt_parts') + assert 'success!' in output + + output = u_boot_console.run_command('echo ${gpt_parts}') + parts = parse_gpt_parts(output.rstrip()) + + assert parts == [ + { + "uuid_disk": "375a56f7-d6c9-4e81-b5f0-09d41ca89efe", + }, + { + "name": "part1", + "start": "0x100000", + "size": "0x100000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + }, + { + "name": "part2", + "start": "0x200000", + "size": "0x180000", + "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", + "uuid": "cc9c6e4a-6551-4cb5-87be-3210f96c86fb", + }, + ] + @pytest.mark.boardspec('sandbox') @pytest.mark.buildconfigspec('cmd_gpt') @pytest.mark.requiredtool('sgdisk')

Sets the bootable flag when constructing the partition string from the current partition configuration. This ensures that when the partitions are written back (for example, when renaming a partition), the flag is preserved.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 3 +++ test/py/tests/test_gpt.py | 1 + 2 files changed, 4 insertions(+)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 0090e02110..927b6afa68 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -176,6 +176,7 @@ static int calc_parts_list_len(int numparts) #ifdef CONFIG_PARTITION_TYPE_GUID partlistlen += numparts * (strlen("type=,") + UUID_STR_LEN + 1); #endif + partlistlen += numparts * strlen("bootable,"); partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1); /* for the terminating null */ partlistlen++; @@ -318,6 +319,8 @@ static int create_gpt_partitions_list(int numparts, const char *guid, strcat(partitions_list, ",uuid="); strncat(partitions_list, curr->gpt_part_info.uuid, UUID_STR_LEN + 1); + if (curr->gpt_part_info.bootable & PART_BOOTABLE) + strcat(partitions_list, ",bootable"); strcat(partitions_list, ";"); } return 0; diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index 93007dee9a..b4c03bc3a2 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -143,6 +143,7 @@ def test_gpt_read_var(state_disk_image, u_boot_console): "size": "0x100000", "type": "0fc63daf-8483-4772-8e79-3d69d8477de4", "uuid": "33194895-67f6-4561-8457-6fdeed4f50a3", + "bootable": True, }, { "name": "part2",

Adds a command called "gpt transpose" which will swap the order two partition table entries in the GPT partition table (but leaves them pointing to the same locations on disk).
This can be useful for swapping bootloaders in systems that use an A/B partitioning scheme where the bootrom is hard coded to look for the bootloader in a specific index in the GPT partition table.
Signed-off-by: Joshua Watt JPEWhacker@gmail.com --- cmd/gpt.c | 46 ++++++++++++++++++++++++++++++++++++--- doc/usage/cmd/gpt.rst | 25 +++++++++++++++++++++ test/py/tests/test_gpt.py | 19 ++++++++++++++++ 3 files changed, 87 insertions(+), 3 deletions(-)
diff --git a/cmd/gpt.c b/cmd/gpt.c index 927b6afa68..58b2c904a1 100644 --- a/cmd/gpt.c +++ b/cmd/gpt.c @@ -858,8 +858,9 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, u8 part_count = 0; int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
- if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) || - (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename")))) + if (!subcomm || !name1 || !name2 || + (strcmp(subcomm, "swap") && strcmp(subcomm, "rename") && + strcmp(subcomm, "transpose"))) return -EINVAL;
ret = get_disk_guid(dev_desc, disk_guid); @@ -920,6 +921,41 @@ static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm, ret = -EINVAL; goto out; } + } else if (!strcmp(subcomm, "transpose")) { + int idx1, idx2; + struct disk_partition* first = NULL; + struct disk_partition* second= NULL; + struct disk_partition tmp_part; + + idx1 = simple_strtoul(name1, NULL, 10); + idx2 = simple_strtoul(name2, NULL, 10); + if (idx1 == idx2) { + printf("Cannot swap partition with itself\n"); + ret = -EINVAL; + goto out; + } + + list_for_each(pos, &disk_partitions) { + curr = list_entry(pos, struct disk_part, list); + if (curr->partnum == idx1) + first = &curr->gpt_part_info; + else if (curr->partnum == idx2) + second = &curr->gpt_part_info; + } + if (!first) { + printf("Illegal partition number %s\n", name1); + ret = -EINVAL; + goto out; + } + if (!second) { + printf("Illegal partition number %s\n", name2); + ret = -EINVAL; + goto out; + } + + tmp_part = *first; + *first = *second; + *second = tmp_part; } else { /* rename */ if (strlen(name2) > PART_NAME_LEN) { printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN); @@ -1123,7 +1159,8 @@ static int do_gpt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) } else if (strcmp(argv[1], "read") == 0) { ret = do_get_gpt_info(blk_dev_desc, (argc == 5) ? argv[4] : NULL); } else if ((strcmp(argv[1], "swap") == 0) || - (strcmp(argv[1], "rename") == 0)) { + (strcmp(argv[1], "rename") == 0) || + (strcmp(argv[1], "transpose") == 0)) { ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]); } else if ((strcmp(argv[1], "set-bootable") == 0)) { ret = gpt_set_bootable(blk_dev_desc, argv[4]); @@ -1176,6 +1213,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap <interface> <dev> <name1> <name2>\n" " - change all partitions named name1 to name2\n" " and vice-versa\n" + " gpt transpose <interface> <dev> <part1> <part2>\n" + " - Swap the order of the entries for part1 and part2 in the partition table\n" " gpt rename <interface> <dev> <part> <name>\n" " - rename the specified partition\n" " gpt set-bootable <interface> <dev> <list>\n" @@ -1184,5 +1223,6 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt, " gpt swap mmc 0 foo bar\n" " gpt rename mmc 0 3 foo\n" " gpt set-bootable mmc 0 boot_a,boot_b\n" + " gpt transpose mmc 0 1 2\n" #endif ); diff --git a/doc/usage/cmd/gpt.rst b/doc/usage/cmd/gpt.rst index 288dd365c0..f6115ecb0e 100644 --- a/doc/usage/cmd/gpt.rst +++ b/doc/usage/cmd/gpt.rst @@ -16,6 +16,7 @@ Synopsis gpt set-bootable <interface> <dev> <partition list> gpt setenv <interface> <dev> <partition name> gpt swap <interface> <dev> <name1> <name2> + gpt transpose <interface> <dev> <part1> <part2> gpt verify <interface> <dev> [<partition string>] gpt write <interface> <dev> <partition string>
@@ -126,6 +127,13 @@ Changes the names of all partitions that are named 'name1' to be 'name2', and all partitions named 'name2' to be 'name1'. CONFIG_CMD_GPT_RENAME=y is required.
+gpt transpose +~~~~~~~~~~~~~ + +Swaps the order of two partition table entries with indexes 'part1' and 'part2' +in the partition table, but otherwise leaves the actual partition data +untouched. + gpt verify ~~~~~~~~~~
@@ -199,3 +207,20 @@ Get the GUID for a disk:: Set the bootable flag for the 'boot' partition and clear it for all others::
=> gpt set-bootable mmc 0 boot + +Swap the order of the 'boot' and 'rootfs' partition table entries:: + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 2 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 1 + + => gpt transpose mmc 0 1 2 + + => gpt setenv mmc 0 rootfs + => echo ${gpt_partition_entry} + 1 + => gpt setenv mmc 0 boot + => echo ${gpt_partition_entry} + 2 diff --git a/test/py/tests/test_gpt.py b/test/py/tests/test_gpt.py index b4c03bc3a2..6e135b663e 100644 --- a/test/py/tests/test_gpt.py +++ b/test/py/tests/test_gpt.py @@ -329,3 +329,22 @@ def test_gpt_write(state_disk_image, u_boot_console): assert '0x00001000 0x00001bff "second"' in output output = u_boot_console.run_command('gpt guid host 0') assert '375a56f7-d6c9-4e81-b5f0-09d41ca89efe' in output + +@pytest.mark.buildconfigspec('cmd_gpt') +@pytest.mark.buildconfigspec('cmd_gpt_rename') +@pytest.mark.buildconfigspec('cmd_part') +@pytest.mark.requiredtool('sgdisk') +def test_gpt_transpose(state_disk_image, u_boot_console): + """Test the gpt transpose command.""" + + u_boot_console.run_command('host bind 0 ' + state_disk_image.path) + output = u_boot_console.run_command('part list host 0') + assert '1\t0x00000800\t0x00000fff\t"part1"' in output + assert '2\t0x00001000\t0x00001bff\t"part2"' in output + + output = u_boot_console.run_command('gpt transpose host 0 1 2') + assert 'success!' in output + + output = u_boot_console.run_command('part list host 0') + assert '2\t0x00000800\t0x00000fff\t"part1"' in output + assert '1\t0x00001000\t0x00001bff\t"part2"' in output
participants (6)
-
Heinrich Schuchardt
-
Heinrich Schuchardt
-
Joshua Watt
-
Simon Glass
-
Simon Glass
-
Tom Rini