All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation
@ 2017-05-21  2:27 alison at peloton-tech.com
  2017-05-21  2:27 ` [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID alison at peloton-tech.com
                   ` (3 more replies)
  0 siblings, 4 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-21  2:27 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

One way for userspace and the bootloader to exchange information about
dynamic image selection is via the storage device partition table, as
described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag.
When no partition on a device is bootable since the kernel and U-Boot
are stored elsewhere, the name field in the GPT partition table offers
another logical place to store information.  These patches allow users
to easily modify GPT partition names via bootscripts that can select
different images based on a boot-failure counter, or when userspace
installs a software update.

These patches have been tested on a TI DRA7xx-based SOM with U-Boot
2015.07.  The storage device is an eMMC.

Alison Chaiken (3):
  GPT: add accessor function for disk GUID
  GPT: read partition table from device into a data structure
  rename GPT partitions to detect boot failure

 cmd/gpt.c       | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 disk/part_efi.c |  31 ++++++
 include/part.h  |  24 ++++
 3 files changed, 392 insertions(+), 2 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID
  2017-05-21  2:27 [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation alison at peloton-tech.com
@ 2017-05-21  2:27 ` alison at peloton-tech.com
  2017-05-26 12:38   ` Tom Rini
  2017-05-21  2:27 ` [U-Boot] [PATCH 2/3] GPT: read partition table from device into a data structure alison at peloton-tech.com
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-21  2:27 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

In order to read the GPT, modify the partition name strings, and then
write out a new GPT, the disk GUID is needed.  While there is an
existing accessor for the partition UUIDs, there is none yet for the
disk GUID.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c       | 29 ++++++++++++++++++++++++++++-
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 include/part.h  | 15 +++++++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 3e98821..814cb11 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return 1;
+
+	if (namestr != NULL)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return 0;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
 	int dev = 0;
-	char *ep;
+	char *ep, *varname = NULL;
 	struct blk_desc *blk_dev_desc = NULL;
 
 	if (argc < 4 || argc > 5)
@@ -436,6 +453,9 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5) strcpy(varname, argv[4]);
+		return do_disk_guid(blk_dev_desc, varname);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +478,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 1b7ba27..de35c9b 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -1;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
diff --git a/include/part.h b/include/part.h
index 83bce05..69143bb 100644
--- a/include/part.h
+++ b/include/part.h
@@ -367,6 +367,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 2/3] GPT: read partition table from device into a data structure
  2017-05-21  2:27 [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-05-21  2:27 ` [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-05-21  2:27 ` alison at peloton-tech.com
  2017-05-26 12:39   ` Tom Rini
  2017-05-21  2:27 ` [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure alison at peloton-tech.com
  2017-05-26 12:38 ` [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation Tom Rini
  3 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-21  2:27 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   9 +++++
 2 files changed, 122 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 814cb11..128c895 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,112 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	/*
+	 * 33 rather than 32, as each string must be null-terminated;
+	 * other extract_val() above will fail.
+	 */
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, 33);
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, 33);
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN + 1);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */
+	int valid_parts = 1, p, ret = 0;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
+			return -1;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -1;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -456,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if (strcmp(argv[1], "guid") == 0) {
 		if (argc == 5) strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -478,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index 69143bb..87a9818 100644
--- a/include/part.h
+++ b/include/part.h
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -46,6 +47,8 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define MAX_SEARCH_PARTITIONS 16
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
 	lbaint_t	size;	/* number of blocks in partition	*/
@@ -64,6 +67,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure
  2017-05-21  2:27 [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-05-21  2:27 ` [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID alison at peloton-tech.com
  2017-05-21  2:27 ` [U-Boot] [PATCH 2/3] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-05-21  2:27 ` alison at peloton-tech.com
  2017-05-26 12:39   ` Tom Rini
  2017-05-29  9:25   ` Lothar Waßmann
  2017-05-26 12:38 ` [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation Tom Rini
  3 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-21  2:27 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via a new 'gpt flip'
command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
   to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
   ‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
   it renames it failed’ and renames the ‘backup’ partition as
   ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
   via u-boot.  Partitions can go to ‘backup’ only from ‘primary’
   and vice-versa, only via Linux.  Partitions go to ‘candidate’
   from ‘primary’ or ‘backup’ only via u-boot.  Only system
   update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 201 insertions(+), 6 deletions(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 128c895..f2c32ae 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -21,6 +21,9 @@
 #include <memalign.h>
 #include <linux/compat.h>
 
+/* ONEMIB is 2**20 */
+#define ONEMIB 1024*1024
+
 static LIST_HEAD(disk_partitions);
 
 /**
@@ -114,7 +117,6 @@ static char *extract_val(const char *str, const char *key)
 			break;
 		}
 	}
-
 	free(strcopy);
 
 	return new;
@@ -158,6 +160,7 @@ static void del_gpt_info(void)
 {
 	struct list_head *pos = &disk_partitions;
 	struct disk_part *curr;
+
 	while (!list_empty(pos)) {
 		curr = list_entry(pos->next, struct disk_part, list);
 		list_del(pos->next);
@@ -165,6 +168,11 @@ static void del_gpt_info(void)
 	}
 }
 
+/*
+ * The number '33' comes from the '32' in the definition of disk_partition_t
+ * in include/part.h.   That file has '37' rather than UUID_STR_LEN + 1, from
+ * include/uuid.h
+ */
 static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 {
 	struct disk_part *newpart;
@@ -191,16 +199,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, ONEMIB);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -212,6 +237,89 @@ static void print_gpt_info(void)
 	}
 }
 
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + 33);
+	/* 17 because partstr below is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen ++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[16];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over 'partitions='.
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		/*
+		 * name is 32 chars long, per definition of disk_partition_t in part.h,
+		 * plus one extra byte for NULL
+		 */
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, 33);
+
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, 17);
+
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, 17);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -223,8 +331,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -241,7 +352,6 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	if (!valid_parts) {
 		printf("** No valid partitions found **\n");
 		del_gpt_info();
-		return -1;
 	}
 	return --valid_parts;
 }
@@ -295,10 +405,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
 	val = extract_val(str, "uuid_disk");
+
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
@@ -312,6 +425,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		if (extract_env(val, &p))
 			p = val;
 		*str_disk_guid = strdup(p);
+
 		free(val);
 		/* Move s to first partition */
 		strsep(&s, ";");
@@ -524,6 +638,83 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return 0;
 }
 
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -567,6 +758,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, varname);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -591,6 +784,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" gpt verify mmc 0 $partitions\n"
 	" read <interface> <dev>\n"
 	"    - read GPT into a data structure for manipulation\n"
+	" flip <interface> <dev>\n"
+	"    - exchange 'primary' and 'backup' partition names in GPT"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation
  2017-05-21  2:27 [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation alison at peloton-tech.com
                   ` (2 preceding siblings ...)
  2017-05-21  2:27 ` [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-05-26 12:38 ` Tom Rini
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
  3 siblings, 1 reply; 116+ messages in thread
From: Tom Rini @ 2017-05-26 12:38 UTC (permalink / raw)
  To: u-boot

On Sat, May 20, 2017 at 07:27:52PM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> One way for userspace and the bootloader to exchange information about
> dynamic image selection is via the storage device partition table, as
> described at
> 
> https://source.android.com/devices/tech/ota/ab_updates
> 
> The scheme described there relies on setting partitions' "boot" flag.
> When no partition on a device is bootable since the kernel and U-Boot
> are stored elsewhere, the name field in the GPT partition table offers
> another logical place to store information.  These patches allow users
> to easily modify GPT partition names via bootscripts that can select
> different images based on a boot-failure counter, or when userspace
> installs a software update.
> 
> These patches have been tested on a TI DRA7xx-based SOM with U-Boot
> 2015.07.  The storage device is an eMMC.
> 
> Alison Chaiken (3):
>   GPT: add accessor function for disk GUID
>   GPT: read partition table from device into a data structure
>   rename GPT partitions to detect boot failure
> 
>  cmd/gpt.c       | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  disk/part_efi.c |  31 ++++++
>  include/part.h  |  24 ++++
>  3 files changed, 392 insertions(+), 2 deletions(-)

Interesting.  Adding Lukasz for comments as well.  I was thinking
perhaps the final patch in the series might want to be guarded with some
Kconfig option as it's rather specific to this update mechanism and
probably causes a noticeable size increase due to the strings.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/8de5c53d/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID
  2017-05-21  2:27 ` [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-05-26 12:38   ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-05-26 12:38 UTC (permalink / raw)
  To: u-boot

On Sat, May 20, 2017 at 07:27:53PM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> In order to read the GPT, modify the partition name strings, and then
> write out a new GPT, the disk GUID is needed.  While there is an
> existing accessor for the partition UUIDs, there is none yet for the
> disk GUID.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Overall looks good, a few style things:

> +	if (namestr != NULL)
> +		setenv(namestr, disk_guid);

You can just if (namestr) here

[snip]
> +	} else if (strcmp(argv[1], "guid") == 0) {
> +		if (argc == 5) strcpy(varname, argv[4]);

Go ahead and do this on multiple lines please.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/649a855f/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 2/3] GPT: read partition table from device into a data structure
  2017-05-21  2:27 ` [U-Boot] [PATCH 2/3] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-05-26 12:39   ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-05-26 12:39 UTC (permalink / raw)
  To: u-boot

On Sat, May 20, 2017 at 07:27:54PM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
[snip]
> +	/*
> +	 * 33 rather than 32, as each string must be null-terminated;
> +	 * other extract_val() above will fail.
> +	 */
> +	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, 33);
> +	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, 33);

This isn't right.  We have name[32]/type[32] so we're overflowing.  I'm
not quite sure where 32 came from and if we should be defining a name
for it as well.  But to make sure it is null-terminated we should be
here memset'ing after malloc.

> +	newpart->gpt_part_info.bootable = info->bootable;
> +#ifdef CONFIG_PARTITION_UUIDS
> +	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
> +		UUID_STR_LEN + 1);
> +#endif

Then this should just be copying UUID_STR_LEN over.

> +	if (!valid_parts) {
> +		printf("** No valid partitions found **\n");
> +		del_gpt_info();
> +		return -1;

We should return something from errno here rather than -1.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/569fea78/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure
  2017-05-21  2:27 ` [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-05-26 12:39   ` Tom Rini
  2017-05-29  9:25   ` Lothar Waßmann
  1 sibling, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-05-26 12:39 UTC (permalink / raw)
  To: u-boot

On Sat, May 20, 2017 at 07:27:55PM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via a new 'gpt flip'
> command.
[snip]
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 201 insertions(+), 6 deletions(-)

There's some whitespace-only chunks, please drop.  Also:

[snip]
> +/* ONEMIB is 2**20 */
> +#define ONEMIB 1024*1024

SZ_1MB from <linux/sizes.h>

> +/*
> + * The number '33' comes from the '32' in the definition of disk_partition_t
> + * in include/part.h.   That file has '37' rather than UUID_STR_LEN + 1, from
> + * include/uuid.h
> + */

Lets update include/part.h in a new patch earlier in the series,
possibly as part of addressing the problems I mention with the previous
patch.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170526/8de83231/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure
  2017-05-21  2:27 ` [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure alison at peloton-tech.com
  2017-05-26 12:39   ` Tom Rini
@ 2017-05-29  9:25   ` Lothar Waßmann
  1 sibling, 0 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-29  9:25 UTC (permalink / raw)
  To: u-boot

alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via a new 'gpt flip'
> command.
> 
> The concept for the bootloader state machine is the following:
> 
> -- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
>    to boot them.
> -- Linux, at boot, will rename ‘candidate’ partitions as
>    ‘primary’.
> -- If u-boot sees a ‘candidate’ partition after a boot attempt,
>    it renames it failed’ and renames the ‘backup’ partition as
>    ‘candidate’.
> 
> Logic:
> -- Partitions can go to ‘failed’ only from ‘candidate’ and only
>    via u-boot.  Partitions can go to ‘backup’ only from ‘primary’
>    and vice-versa, only via Linux.  Partitions go to ‘candidate’
>    from ‘primary’ or ‘backup’ only via u-boot.  Only system
>    update software will rename 'failed' partitions.
> 
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 201 insertions(+), 6 deletions(-)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 128c895..f2c32ae 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -21,6 +21,9 @@
>  #include <memalign.h>
>  #include <linux/compat.h>
>  
> +/* ONEMIB is 2**20 */
> +#define ONEMIB 1024*1024
>
'()' are missing around the expression!
But anyway, there is no need to reinvent the wheel, since SZ_1M exists
in include/linux/sizes.h.

> +
>  static LIST_HEAD(disk_partitions);
>  
>  /**
> @@ -114,7 +117,6 @@ static char *extract_val(const char *str, const char *key)
>  			break;
>  		}
>  	}
> -
>  	free(strcopy);
>  
>  	return new;
> @@ -158,6 +160,7 @@ static void del_gpt_info(void)
>  {
>  	struct list_head *pos = &disk_partitions;
>  	struct disk_part *curr;
> +
>  	while (!list_empty(pos)) {
>  		curr = list_entry(pos->next, struct disk_part, list);
>  		list_del(pos->next);
> @@ -165,6 +168,11 @@ static void del_gpt_info(void)
>  	}
>  }
>  
> +/*
> + * The number '33' comes from the '32' in the definition of disk_partition_t
> + * in include/part.h.   That file has '37' rather than UUID_STR_LEN + 1, from
> + * include/uuid.h
> + */
>  static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
>  {
>  	struct disk_part *newpart;
> @@ -191,16 +199,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
>  	return newpart;
>  }
>  
> +static void prettyprint_part_size(char *sizestr, unsigned long partsize,
> +				  unsigned long blksize)
> +{
> +	unsigned long long partbytes;
> +	unsigned long partmegabytes;
> +
> +	partbytes = partsize * blksize;
> +	partmegabytes = lldiv(partbytes, ONEMIB);
> +	snprintf(sizestr, 16, "%luMiB", partmegabytes);
> +}
> +
>  static void print_gpt_info(void)
>  {
>  	struct list_head *pos;
>  	struct disk_part *curr;
> +	char partstartstr[16];
> +	char partsizestr[16];
>  
>  	list_for_each(pos, &disk_partitions) {
>  		curr = list_entry(pos, struct disk_part, list);
> +		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +
>  		printf("Partition %d:\n", curr->partnum);
> -		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> -		       (unsigned)curr->gpt_part_info.size);
> +		printf("Start %s, size %s\n", partstartstr, partsizestr);
>  		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
>  		       curr->gpt_part_info.name);
>  		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> @@ -212,6 +237,89 @@ static void print_gpt_info(void)
>  	}
>  }
>  
> +static int calc_parts_list_len(int numparts)
> +{
> +	/*
> +	 * prefatory string:
> +	 * doc/README.GPT, suggests that
> +	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
> +	 * is correct, but extract_val() expects "uuid_disk" first.
> +	 */
> +	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> +	/* for the comma */
> +	partlistlen++;
> +
> +	/* per-partition additions; numparts starts at 1, so this should be correct */
> +	partlistlen += numparts * (strlen("name=,") + 33);
> +	/* 17 because partstr below is 16 chars */
> +	partlistlen += numparts * (strlen("start=MiB,") + 17);
> +	partlistlen += numparts * (strlen("size=MiB,") + 17);
> +	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
> +	/* for the terminating null */
> +	partlistlen ++;
>
partlistlen++;

> +	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
> +	       numparts);
> +	return partlistlen;
> +}
> +
> +/*
> + * create the string that upstream 'gpt write' command will accept as an
> + * argument
> + *
> + * From doc/README.gpt, Format of partitions layout:
> + *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> + *	name=kernel,size=60MiB,uuid=...;"
> + * The fields 'name' and 'size' are mandatory for every partition.
> + * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
> + * are optional if CONFIG_RANDOM_UUID is enabled.
> + */
> +static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	char partstr[16];
> +
> +	if (!partitions_list)
> +		return -1;
> +
> +	/*
> +	 * README.gpt specifies starting with "partitions=" like so:
> +	 *      strcpy(partitions_list, "partitions=uuid_disk=");
> +	 * but that breaks extract_val, which doesn't skip over 'partitions='.
> +	 */
> +	strcpy(partitions_list, "uuid_disk=");
> +	strncat(partitions_list, guid, UUID_STR_LEN + 1);
> +	strcat(partitions_list, ";");
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		strcat(partitions_list, "name=");
> +		/*
> +		 * name is 32 chars long, per definition of disk_partition_t in part.h,
> +		 * plus one extra byte for NULL
> +		 */
> +		strncat(partitions_list, (const char *)curr->gpt_part_info.name, 33);
>
unnecessary cast. The same holds for all the other (const char *) casts
in this patch.

> +
> +		strcat(partitions_list, ",start=");
> +		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		strncat(partitions_list, partstr, 17);
> +
> +		strcat(partitions_list, ",size=");
> +		/* lbaint_t is unsigned long, per include/ide.h */
> +		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		/* one extra byte for NULL */
> +		strncat(partitions_list, partstr, 17);
> +
> +		strcat(partitions_list, ",uuid=");
> +		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
> +			UUID_STR_LEN + 1);
> +		strcat(partitions_list, ";");
> +	}
> +	return 0;
> +}
> +
>  /*
>   * read partition info into disk_partitions list where
>   * it can be printed or modified
> @@ -223,8 +331,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
>  	disk_partition_t info;
>  	struct disk_part *new_disk_part;
>  
> -	if (disk_partitions.next == NULL)
> -		INIT_LIST_HEAD(&disk_partitions);
> +	/*
> +	 * Always re-read partition info from device, in case
> +	 * it has changed
> +	 */
> +	INIT_LIST_HEAD(&disk_partitions);
>  
>  	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
>  		ret = part_get_info(dev_desc, p, &info);
> @@ -241,7 +352,6 @@ static int get_gpt_info(struct blk_desc *dev_desc)
>  	if (!valid_parts) {
>  		printf("** No valid partitions found **\n");
>  		del_gpt_info();
> -		return -1;
>  	}
>  	return --valid_parts;
>  }
> @@ -295,10 +405,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  		return -1;
>  
>  	str = strdup(str_part);
> +	if (str == NULL)
> +		return -ENOMEM;
>  
>  	/* extract disk guid */
>  	s = str;
>  	val = extract_val(str, "uuid_disk");
> +
>  	if (!val) {
>  #ifdef CONFIG_RANDOM_UUID
>  		*str_disk_guid = malloc(UUID_STR_LEN + 1);
> @@ -312,6 +425,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  		if (extract_env(val, &p))
>  			p = val;
>  		*str_disk_guid = strdup(p);
> +
>  		free(val);
>  		/* Move s to first partition */
>  		strsep(&s, ";");
> @@ -524,6 +638,83 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
>  	return 0;
>  }
>  
> +static int do_flip_gpt_parts(struct blk_desc *dev_desc)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	disk_partition_t *new_partitions = NULL;
> +	char disk_guid[UUID_STR_LEN + 1];
> +	char *partitions_list, *str_disk_guid;
> +	u8 part_count = 0;
> +	int partlistlen, ret, numparts = 0;
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return ret;
> +
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
> +	printf("Current partition table with %d partitions is:\n", numparts);
> +	print_gpt_info();
> +
> +	partlistlen = calc_parts_list_len(numparts);
> +	partitions_list = (char *)malloc(partlistlen);
>
Useless cast.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 0/6] add support for GPT partition name manipulation
  2017-05-26 12:38 ` [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation Tom Rini
@ 2017-05-29 16:49   ` alison at peloton-tech.com
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
                       ` (5 more replies)
  0 siblings, 6 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

One way for userspace and the bootloader to exchange information about
dynamic image selection is via the storage device partition table, as
described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag.
When no partition on a device is bootable since the kernel and U-Boot
are stored elsewhere, the name field in the GPT partition table offers
another logical place to store information.  These patches allow users
to easily modify GPT partition names via bootscripts that can select
different images based on a boot-failure counter, or when userspace
installs a software update.

These patches have been tested on a TI DRA7xx-based SOM with U-Boot
2015.07.  The storage device is an eMMC.

Significant changes since v1:
-- Put the gpt_flip() function and auxiliary ones inside a new
   CONFIG_CMD_GPT_FLIP option that depends on CMD_GPT.
-- Replace intentional overwriting of name and type string arrays with
   memset() instead.
-- Move part.h changes earlier in the patchset.
-- Add a few lines to README.gpt about the new gpt subcommands.

Added a few simple patches to do the following:
-- Replace remaining occurrences of '37' with UUID_STR_LEN+1;
-- Introduce new macros to get rid of the similar '32';
-- fix a smaller error in doc/README.gpt.

There are also some fixups of whitespace and formatting errors (plus
usual inevitable addition of new ones).

To do in future:
-- Add support for preserving the type flag for partitions. The u-boot
   version on which this patchset is based did not have this feature,
   and it's easy to add, but I need to figure how to test it first.



Alison Chaiken (6):
  EFI: replace number with UUID_STR_LEN macro
  disk_partition: introduce macros for description string lengths
  GPT: add accessor function for disk GUID
  GPT: read partition table from device into a data structure
  rename GPT partitions to detect boot failure
  GPT: fix error in partitions string doc

 cmd/Kconfig     |   7 ++
 cmd/gpt.c       | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 disk/part_efi.c |  33 +++++-
 doc/README.gpt  |  24 ++++-
 include/part.h  |  35 +++++-
 5 files changed, 410 insertions(+), 11 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
@ 2017-05-29 16:49     ` alison at peloton-tech.com
  2017-05-31  2:07       ` Tom Rini
  2017-05-31  7:37       ` Lukasz Majewski
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
                       ` (4 subsequent siblings)
  5 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 disk/part_efi.c | 2 +-
 include/part.h  | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/disk/part_efi.c b/disk/part_efi.c
index 1b7ba27..20d33ef 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -183,7 +183,7 @@ void part_print_efi(struct blk_desc *dev_desc)
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
 	gpt_entry *gpt_pte = NULL;
 	int i = 0;
-	char uuid[37];
+	char uuid[UUID_STR_LEN + 1];
 	unsigned char *uuid_bin;
 
 	/* This function validates AND fills in the GPT header and PTE */
diff --git a/include/part.h b/include/part.h
index 83bce05..6ace09f 100644
--- a/include/part.h
+++ b/include/part.h
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <uuid.h>
 
 struct block_drvr {
 	char *name;
@@ -54,10 +55,10 @@ typedef struct disk_partition {
 	uchar	type[32];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-	char	uuid[37];	/* filesystem UUID as string, if exists	*/
+	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
 #endif
 #ifdef CONFIG_PARTITION_TYPE_GUID
-	char	type_guid[37];	/* type GUID as string, if exists	*/
+	char	type_guid[UUID_STR_LEN + 1];	/* type GUID as string, if exists	*/
 #endif
 #ifdef CONFIG_DOS_PARTITION
 	uchar	sys_ind;	/* partition type 			*/
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
@ 2017-05-29 16:49     ` alison at peloton-tech.com
  2017-05-31  7:37       ` Lukasz Majewski
  2017-05-31 13:50       ` Tom Rini
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID alison at peloton-tech.com
                       ` (3 subsequent siblings)
  5 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 include/part.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/part.h b/include/part.h
index 6ace09f..87b1111 100644
--- a/include/part.h
+++ b/include/part.h
@@ -47,12 +47,15 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define PART_NAME_LEN 32
+#define PART_TYPE_LEN 32
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
 	lbaint_t	size;	/* number of blocks in partition	*/
 	ulong	blksz;		/* block size in bytes			*/
-	uchar	name[32];	/* partition name			*/
-	uchar	type[32];	/* string type description		*/
+	uchar	name[PART_NAME_LEN];	/* partition name			*/
+	uchar	type[PART_TYPE_LEN];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
@ 2017-05-29 16:49     ` alison at peloton-tech.com
  2017-05-30  6:46       ` Lothar Waßmann
  2017-05-31  7:44       ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID Lukasz Majewski
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure alison at peloton-tech.com
                       ` (2 subsequent siblings)
  5 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

In order to read the GPT, modify the partition name strings, and then
write out a new GPT, the disk GUID is needed.  While there is an
existing accessor for the partition UUIDs, there is none yet for the
disk GUID.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c       | 30 +++++++++++++++++++++++++++++-
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 3e98821..3b7d929 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return 1;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return 0;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	int ret = CMD_RET_SUCCESS;
 	int dev = 0;
-	char *ep;
+	char *ep, *varname = NULL;
 	struct blk_desc *blk_dev_desc = NULL;
 
 	if (argc < 4 || argc > 5)
@@ -436,6 +453,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		if (argc == 5)
+		       strcpy(varname, argv[4]);
+		return do_disk_guid(blk_dev_desc, varname);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +479,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 20d33ef..ff9f408 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -1;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
diff --git a/doc/README.gpt b/doc/README.gpt
index 3fcd835..c0779a4 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
diff --git a/include/part.h b/include/part.h
index 87b1111..16c4a46 100644
--- a/include/part.h
+++ b/include/part.h
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
                       ` (2 preceding siblings ...)
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-05-29 16:49     ` alison at peloton-tech.com
  2017-05-30  7:37       ` Lothar Waßmann
  2017-05-31  7:48       ` Lukasz Majewski
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure alison at peloton-tech.com
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc alison at peloton-tech.com
  5 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   8 +++++
 2 files changed, 120 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 3b7d929..c61d2b1 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	memset(newpart, '\0', sizeof(newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	memset(newpart->gpt_part_info.name + 31, '\0', 1);
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	memset(newpart->gpt_part_info.type + 31, '\0', 1);
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as u-boot does */
+	int valid_parts = 1, p, ret = 0;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
+			return -1;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		if (argc == 5)
 		       strcpy(varname, argv[4]);
 		return do_disk_guid(blk_dev_desc, varname);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index 16c4a46..7d7052a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -49,6 +50,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 16
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
@@ -68,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
                       ` (3 preceding siblings ...)
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-05-29 16:49     ` alison at peloton-tech.com
  2017-05-30  7:38       ` Lothar Waßmann
  2017-05-31  8:12       ` Lukasz Majewski
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc alison at peloton-tech.com
  5 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via a new 'gpt flip'
command which is enabled via a CONFIG_CMD_GPT_FLIP option.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
   to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
   ‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
   it renames it failed’ and renames the ‘backup’ partition as
   ‘candidate’.

Logic:
-- Partitions can go to ‘failed’ only from ‘candidate’ and only
   via u-boot.  Partitions can go to ‘backup’ only from ‘primary’
   and vice-versa, only via Linux.  Partitions go to ‘candidate’
   from ‘primary’ or ‘backup’ only via u-boot.  Only system
   update software will rename 'failed' partitions.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 215 insertions(+), 4 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 5ee52f6..a8f7716 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -575,6 +575,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index c61d2b1..6a0b70f 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -190,16 +191,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -211,6 +229,85 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over 'partitions='.
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -222,8 +319,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -294,6 +394,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return 0;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -567,6 +749,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, varname);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -598,4 +784,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_FLIP
+	"gpt partition-flip command\n"
+	"gpt flip <interface> <dev>\n"
+	"    - exchange device's 'primary' and 'backup' partition names\n"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index c0779a4..e29b188 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc
  2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
                       ` (4 preceding siblings ...)
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-05-29 16:49     ` alison at peloton-tech.com
  2017-05-31  8:14       ` Lukasz Majewski
  5 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-05-29 16:49 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

The existing partitions-list parsing in cmd/gpt.c passes a value
from gpt_default() to set_gpt_info() that README.gpt suggests
should begin with 'partitions='.  Partition-list strings should
in fact begin with 'uuid_disk', as otherwise the call from
set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
Change README.gpt and file comments accordingly.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 13 +------------
 doc/README.gpt |  8 ++++----
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 6a0b70f..487314b 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -232,12 +232,6 @@ static void print_gpt_info(void)
 #ifdef CONFIG_CMD_GPT_FLIP
 static int calc_parts_list_len(int numparts)
 {
-	/*
-	 * prefatory string:
-	 * doc/README.GPT, suggests that
-	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
-	 * is correct, but extract_val() expects "uuid_disk" first.
-	 */
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
 	/* for the comma */
 	partlistlen++;
@@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
  * argument
  *
  * From doc/README.gpt, Format of partitions layout:
- *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
  *	name=kernel,size=60MiB,uuid=...;"
  * The fields 'name' and 'size' are mandatory for every partition.
  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
@@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int numparts, const char *guid, char *part
 	if (!partitions_list)
 		return -1;
 
-	/*
-	 * README.gpt specifies starting with "partitions=" like so:
-	 *      strcpy(partitions_list, "partitions=uuid_disk=");
-	 * but that breaks extract_val, which doesn't skip over 'partitions='.
-	 */
 	strcpy(partitions_list, "uuid_disk=");
 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
 	strcat(partitions_list, ";");
diff --git a/doc/README.gpt b/doc/README.gpt
index e29b188..754e490 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -255,7 +255,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-05-30  6:46       ` Lothar Waßmann
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-05-31  7:44       ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID Lukasz Majewski
  1 sibling, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-30  6:46 UTC (permalink / raw)
  To: u-boot

alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> In order to read the GPT, modify the partition name strings, and then
> write out a new GPT, the disk GUID is needed.  While there is an
> existing accessor for the partition UUIDs, there is none yet for the
> disk GUID.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c       | 30 +++++++++++++++++++++++++++++-
>  disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
>  doc/README.gpt  |  3 ++-
>  include/part.h  | 15 +++++++++++++++
>  4 files changed, 77 insertions(+), 2 deletions(-)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 3e98821..3b7d929 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
>  	return ret;
>  }
>  
> +static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
> +{
> +	int ret;
> +	char disk_guid[UUID_STR_LEN + 1];
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return 1;
> +
Since you are calling this function from a CMD handler and passing its
return value as the CMD handlers exit code this should be:
		return CMD_RET_FAILURE;

> +	if (namestr)
> +		setenv(namestr, disk_guid);
> +	else
> +		printf("%s\n", disk_guid);
> +
> +	return 0;
>
... and this:
	return CMD_RET_SUCCESS;

>  /**
>   * do_gpt(): Perform GPT operations
>   *
> @@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  {
>  	int ret = CMD_RET_SUCCESS;
>  	int dev = 0;
> -	char *ep;
> +	char *ep, *varname = NULL;
>  	struct blk_desc *blk_dev_desc = NULL;
>  
>  	if (argc < 4 || argc > 5)
> @@ -436,6 +453,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  	} else if ((strcmp(argv[1], "verify") == 0)) {
>  		ret = gpt_verify(blk_dev_desc, argv[4]);
>  		printf("Verify GPT: ");
> +	} else if (strcmp(argv[1], "guid") == 0) {
> +		if (argc == 5)
> +		       strcpy(varname, argv[4]);
>
You didn't allocate any memory for varname and copy the argument string
to a NULL pointer!
Maybe use strdup() and free varname after use?

> +		return do_disk_guid(blk_dev_desc, varname);
>  	} else {
>  		return CMD_RET_USAGE;
>  	}
> @@ -458,4 +479,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt write mmc 0 $partitions\n"
>  	" gpt verify mmc 0 $partitions\n"
> +	" guid <interface> <dev>\n"
> +	"    - print disk GUID\n"
> +	" guid <interface> <dev> <varname>\n"
> +	"    - set environment variable to disk GUID\n"
> +	" Example usage:\n"
> +	" gpt guid mmc 0\n"
> +	" gpt guid mmc 0 varname\n"
>  );
> diff --git a/disk/part_efi.c b/disk/part_efi.c
> index 20d33ef..ff9f408 100644
> --- a/disk/part_efi.c
> +++ b/disk/part_efi.c
> @@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
>   * Public Functions (include/part.h)
>   */
>  
> +/*
> + * UUID is displayed as 32 hexadecimal digits, in 5 groups,
> + * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
> + */
> +int get_disk_guid(struct blk_desc * dev_desc, char *guid)
> +{
> +	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
> +	gpt_entry *gpt_pte = NULL;
> +	unsigned char *guid_bin;
> +
> +	/* This function validates AND fills in the GPT header and PTE */
> +	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
> +			 gpt_head, &gpt_pte) != 1) {
> +		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
> +		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
>
useless '()'

> +				 gpt_head, &gpt_pte) != 1) {
> +			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
> +			       __func__);
> +			return -1;
	return -EINVAL;?

> +		} else {
> +			printf("%s: ***        Using Backup GPT ***\n",
> +			       __func__);
> +		}
> +	}
> +
> +	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
>
disk_guid.b is of type u8 which is the same as unsigned char.
No need for a type cast here (and the () around gpt_head->... are
unnecessary).

> +	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
> +
> +	return 0;
> +}
> +
>  void part_print_efi(struct blk_desc *dev_desc)
>  {
>  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
> diff --git a/doc/README.gpt b/doc/README.gpt
> index 3fcd835..c0779a4 100644
> --- a/doc/README.gpt
> +++ b/doc/README.gpt
> @@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
>     The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
>     enabled. A random uuid will be used if omitted or they point to an empty/
>     non-existent environment variable. The environment variable will be set to
> -   the generated UUID.
> +   the generated UUID.  The 'gpt guid' command reads the current value of the
> +   uuid_disk from the GPT.
>  
>     The field 'bootable' is optional, it is used to mark the GPT partition
>     bootable (set attribute flags "Legacy BIOS bootable").
> diff --git a/include/part.h b/include/part.h
> index 87b1111..16c4a46 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
>  int gpt_verify_partitions(struct blk_desc *dev_desc,
>  			  disk_partition_t *partitions, int parts,
>  			  gpt_header *gpt_head, gpt_entry **gpt_pte);
> +
> +
> +/**
> + * get_disk_guid() - Function to read the GUID string from a device's GPT
> + *
> + * This function reads the GUID string from a block device whose descriptor
> + * is provided.
> + *
> + * @param dev_desc - block device descriptor
> + * @param guid - pre-allocated string in which to return the GUID
> + *
> + * @return - '0' on success, otherwise error
> + */
> +int get_disk_guid(struct blk_desc *dev_desc, char *guid);
> +
>  #endif
>  
>  #if CONFIG_IS_ENABLED(DOS_PARTITION)



-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-05-30  7:37       ` Lothar Waßmann
  2017-06-01  6:34         ` Chaiken, Alison
  2017-05-31  7:48       ` Lukasz Majewski
  1 sibling, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-30  7:37 UTC (permalink / raw)
  To: u-boot

alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/part.h |   8 +++++
>  2 files changed, 120 insertions(+)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 3b7d929..c61d2b1 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -19,6 +19,9 @@
>  #include <linux/ctype.h>
>  #include <div64.h>
>  #include <memalign.h>
> +#include <linux/compat.h>
> +
> +static LIST_HEAD(disk_partitions);
>  
>  /**
>   * extract_env(): Expand env name from string format '&{env_name}'
> @@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
>  	return result;
>  }
>  
> +static void del_gpt_info(void)
> +{
> +	struct list_head *pos = &disk_partitions;
> +	struct disk_part *curr;
> +	while (!list_empty(pos)) {
>
empty line between declarations and code?

> +		curr = list_entry(pos->next, struct disk_part, list);
> +		list_del(pos->next);
> +		free(curr);
> +	}
> +}
> +
> +static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
> +{
> +	struct disk_part *newpart;
> +	newpart = (struct disk_part *)malloc(sizeof(*newpart));
>
useless type cast. malloc returns a void pointer which can be assigned
to any typed pointer without a cast.

> +	memset(newpart, '\0', sizeof(newpart));
> +	if (!newpart)
>
This NULL check should be done before the memset()!

> +		return ERR_PTR(-ENOMEM);
> +
> +	newpart->gpt_part_info.start = info->start;
> +	newpart->gpt_part_info.size = info->size;
> +	newpart->gpt_part_info.blksz = info->blksz;
> +	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
> +	memset(newpart->gpt_part_info.name + 31, '\0', 1);
	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
1. No need for memset here.
2. You are copying PART_NAME_LEN bytes, but set the byte at pos 31 to
   '\0'. => This code will blow up if PART_NAME_LEN is changed to a
different value!

> +	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
> +	memset(newpart->gpt_part_info.type + 31, '\0', 1);
dto.

> +	newpart->gpt_part_info.bootable = info->bootable;
> +#ifdef CONFIG_PARTITION_UUIDS
> +	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
> +		UUID_STR_LEN);
> +#endif
> +	newpart->partnum = partnum;
> +
> +	return newpart;
> +}
> +
> +static void print_gpt_info(void)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		printf("Partition %d:\n", curr->partnum);
> +		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> +		       (unsigned)curr->gpt_part_info.size);
> +		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
> +		       curr->gpt_part_info.name);
> +		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> +		       curr->gpt_part_info.bootable);
> +#ifdef CONFIG_PARTITION_UUIDS
> +		printf("UUID %s\n", curr->gpt_part_info.uuid);
> +#endif
> +		printf("\n");
> +	}
> +}
> +
> +/*
> + * read partition info into disk_partitions list where
> + * it can be printed or modified
> + */
> +static int get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	/* start partition numbering at 1, as u-boot does */
>
s/u-boot/U-Boot/

> +	int valid_parts = 1, p, ret = 0;
>
No need to initialize ret here (no need to declare it here either).

> +	disk_partition_t info;
> +	struct disk_part *new_disk_part;
> +
> +	if (disk_partitions.next == NULL)
> +		INIT_LIST_HEAD(&disk_partitions);
> +
> +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> +		ret = part_get_info(dev_desc, p, &info);
> +		if (ret)
> +			continue;
> +
> +		new_disk_part = allocate_disk_part(&info, valid_parts);
> +		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
>
No need for () around the '>=' expression.

> +			return -1;
You return -ENODEV lateron, so you should return a valid errno value
here. -1 (-EPERM) is most probably not the error code you want to use
here.

> +		list_add_tail(&new_disk_part->list, &disk_partitions);
> +		valid_parts++;
> +	}
> +	if (!valid_parts) {
> +		printf("** No valid partitions found **\n");
> +		del_gpt_info();
> +		return -ENODEV;
> +	}
> +	return --valid_parts;
> +}
> +
> +/* a wrapper to test get_gpt_info */
> +static int do_get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	int ret;
> +
> +	ret = get_gpt_info(dev_desc);
> +	if (ret > 0) {
> +		print_gpt_info();
> +		del_gpt_info();
> +	}
> +	return ret;
>
Since the return value of this function is passed on as the exit code
of the calling CMD handler it should be one of CMD_RET_SUCCESS or
CMD_RET_FAILURE:
	return ret ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
But see my comment below!

>  /**
>   * set_gpt_info(): Fill partition information from string
>   *		function allocates memory, remember to free!
> @@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  		if (argc == 5)
>  		       strcpy(varname, argv[4]);
>  		return do_disk_guid(blk_dev_desc, varname);
> +	} else if (strcmp(argv[1], "read") == 0) {
> +		return do_get_gpt_info(blk_dev_desc);
>
If you have a careful look at the succeeding code in this function you
would see, that it does not blindly pass on the return value of the
functions called for each subcommand but does:
|	if (ret) {
|		printf("error!\n");
|		return CMD_RET_FAILURE;
|	}
|
|	printf("success!\n");
|	return CMD_RET_SUCCESS;

So you should just assign the return value of do_disk_guid() and
do_get_gpt_info() to the variable 'ret' and let the original code
handle it.

>  	} else {
>  		return CMD_RET_USAGE;
>  	}
> @@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt write mmc 0 $partitions\n"
>  	" gpt verify mmc 0 $partitions\n"
> +	" read <interface> <dev>\n"
> +	"    - read GPT into a data structure for manipulation\n"
>  	" guid <interface> <dev>\n"
>  	"    - print disk GUID\n"
>  	" guid <interface> <dev> <varname>\n"
> diff --git a/include/part.h b/include/part.h
> index 16c4a46..7d7052a 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -10,6 +10,7 @@
>  #include <blk.h>
>  #include <ide.h>
>  #include <uuid.h>
> +#include <linux/list.h>
>  
>  struct block_drvr {
>  	char *name;
> @@ -49,6 +50,7 @@ struct block_drvr {
>  
>  #define PART_NAME_LEN 32
>  #define PART_TYPE_LEN 32
> +#define MAX_SEARCH_PARTITIONS 16
>  
Why the hard limit to 16 partitions?
A standard Android system will jump right in your face with this limit.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-05-30  7:38       ` Lothar Waßmann
  2017-05-31  8:12       ` Lukasz Majewski
  1 sibling, 0 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-30  7:38 UTC (permalink / raw)
  To: u-boot

alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via a new 'gpt flip'
> command which is enabled via a CONFIG_CMD_GPT_FLIP option.
> 
> The concept for the bootloader state machine is the following:
> 
> -- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
>    to boot them.
> -- Linux, at boot, will rename ‘candidate’ partitions as
>    ‘primary’.
> -- If u-boot sees a ‘candidate’ partition after a boot attempt,
>    it renames it failed’ and renames the ‘backup’ partition as
>    ‘candidate’.
> 
> Logic:
> -- Partitions can go to ‘failed’ only from ‘candidate’ and only
>    via u-boot.  Partitions can go to ‘backup’ only from ‘primary’
>    and vice-versa, only via Linux.  Partitions go to ‘candidate’
>    from ‘primary’ or ‘backup’ only via u-boot.  Only system
>    update software will rename 'failed' partitions.
> 
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/Kconfig    |   7 ++
>  cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  doc/README.gpt |  13 ++++
>  3 files changed, 215 insertions(+), 4 deletions(-)
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 5ee52f6..a8f7716 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -575,6 +575,13 @@ config CMD_GPT
>  	  Enable the 'gpt' command to ready and write GPT style partition
>  	  tables.
>  
> +config CMD_GPT_FLIP
> +	bool "GPT flip-partitions command"
> +	depends on CMD_GPT
> +	help
> +	  Enables the 'gpt' command to write modified GPT partition
> +	  tables via the 'gpt flip' command.
> +
>  config CMD_ARMFLASH
>  	#depends on FLASH_CFI_DRIVER
>  	bool "armflash"
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index c61d2b1..6a0b70f 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -20,6 +20,7 @@
>  #include <div64.h>
>  #include <memalign.h>
>  #include <linux/compat.h>
> +#include <linux/sizes.h>
>  
>  static LIST_HEAD(disk_partitions);
>  
> @@ -190,16 +191,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
>  	return newpart;
>  }
>  
> +static void prettyprint_part_size(char *sizestr, unsigned long partsize,
> +				  unsigned long blksize)
> +{
> +	unsigned long long partbytes;
> +	unsigned long partmegabytes;
> +
> +	partbytes = partsize * blksize;
> +	partmegabytes = lldiv(partbytes, SZ_1M);
> +	snprintf(sizestr, 16, "%luMiB", partmegabytes);
> +}
> +
>  static void print_gpt_info(void)
>  {
>  	struct list_head *pos;
>  	struct disk_part *curr;
> +	char partstartstr[16];
> +	char partsizestr[16];
>  
>  	list_for_each(pos, &disk_partitions) {
>  		curr = list_entry(pos, struct disk_part, list);
> +		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +
>  		printf("Partition %d:\n", curr->partnum);
> -		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> -		       (unsigned)curr->gpt_part_info.size);
> +		printf("Start %s, size %s\n", partstartstr, partsizestr);
>  		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
>  		       curr->gpt_part_info.name);
>  		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> @@ -211,6 +229,85 @@ static void print_gpt_info(void)
>  	}
>  }
>  
> +#ifdef CONFIG_CMD_GPT_FLIP
> +static int calc_parts_list_len(int numparts)
> +{
> +	/*
> +	 * prefatory string:
> +	 * doc/README.GPT, suggests that
> +	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
> +	 * is correct, but extract_val() expects "uuid_disk" first.
> +	 */
> +	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> +	/* for the comma */
> +	partlistlen++;
> +
> +	/* per-partition additions; numparts starts at 1, so this should be correct */
> +	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
> +	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
> +	partlistlen += numparts * (strlen("start=MiB,") + 17);
> +	partlistlen += numparts * (strlen("size=MiB,") + 17);
> +	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
> +	/* for the terminating null */
> +	partlistlen++;
> +	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
> +	       numparts);
> +	return partlistlen;
> +}
> +
> +/*
> + * create the string that upstream 'gpt write' command will accept as an
> + * argument
> + *
> + * From doc/README.gpt, Format of partitions layout:
> + *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> + *	name=kernel,size=60MiB,uuid=...;"
> + * The fields 'name' and 'size' are mandatory for every partition.
> + * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
> + * are optional if CONFIG_RANDOM_UUID is enabled.
> + */
> +static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	char partstr[PART_NAME_LEN + 1];
> +
> +	if (!partitions_list)
> +		return -1;
> +
> +	/*
> +	 * README.gpt specifies starting with "partitions=" like so:
> +	 *      strcpy(partitions_list, "partitions=uuid_disk=");
> +	 * but that breaks extract_val, which doesn't skip over 'partitions='.
> +	 */
> +	strcpy(partitions_list, "uuid_disk=");
> +	strncat(partitions_list, guid, UUID_STR_LEN + 1);
> +	strcat(partitions_list, ";");
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		strcat(partitions_list, "name=");
> +		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
> +		strcat(partitions_list, ",start=");
> +		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		/* one extra byte for NULL */
> +		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
> +		strcat(partitions_list, ",size=");
> +		/* lbaint_t is unsigned long, per include/ide.h */
> +		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
> +
> +		strcat(partitions_list, ",uuid=");
> +		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
> +			UUID_STR_LEN + 1);
> +		strcat(partitions_list, ";");
> +	}
> +	return 0;
> +}
> +#endif
> +
>  /*
>   * read partition info into disk_partitions list where
>   * it can be printed or modified
> @@ -222,8 +319,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
>  	disk_partition_t info;
>  	struct disk_part *new_disk_part;
>  
> -	if (disk_partitions.next == NULL)
> -		INIT_LIST_HEAD(&disk_partitions);
> +	/*
> +	 * Always re-read partition info from device, in case
> +	 * it has changed
> +	 */
> +	INIT_LIST_HEAD(&disk_partitions);
>  
>  	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
>  		ret = part_get_info(dev_desc, p, &info);
> @@ -294,6 +394,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  		return -1;
>  
>  	str = strdup(str_part);
> +	if (str == NULL)
> +		return -ENOMEM;
>  
>  	/* extract disk guid */
>  	s = str;
> @@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_CMD_GPT_FLIP
> +static int do_flip_gpt_parts(struct blk_desc *dev_desc)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	disk_partition_t *new_partitions = NULL;
> +	char disk_guid[UUID_STR_LEN + 1];
> +	char *partitions_list, *str_disk_guid;
> +	u8 part_count = 0;
> +	int partlistlen, ret, numparts = 0;
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return ret;
>
This function should return either CMD_RET_FAILURE or CMD_RET_SUCCESS,
since the return value is passed on as the exit code of the calling CMD
handler function!

> +
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
see above.

> +	printf("Current partition table with %d partitions is:\n", numparts);
> +	print_gpt_info();
> +
> +	partlistlen = calc_parts_list_len(numparts);
> +	partitions_list = (char *)malloc(partlistlen);
> +	memset(partitions_list, '\0', partlistlen);
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
> +					 partitions_list);
> +	if (ret < 0)
> +		return ret;
see above.

> +	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
> +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
> +			   &new_partitions, &part_count);
> +	if (ret < 0)
> +		return ret;
see above.

> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
> +			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
> +		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
> +			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
> +		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
> +			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
> +		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
> +			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
> +	}
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
> +	if (ret < 0)
> +		return ret;
see above.

> +	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
> +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
> +			   &new_partitions, &part_count);
> +	if (ret < 0)
> +		return ret;
see above.

> +	debug("Writing new partition table\n");
> +	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
> +	if (ret < 0) {
> +		printf("Writing new partition table failed\n");
> +		return ret;
see above.

> +	}
> +
> +	debug("Reading back new partition table\n");
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
see above.

> +	printf("new partition table with %d partitions is:\n", numparts);
> +	print_gpt_info();
> +
> +	del_gpt_info();
> +	free(partitions_list);
> +	free(str_disk_guid);
> +	free(new_partitions);
> +	return ret;
see above.

> +}
> +#endif
> +
>  /**
>   * do_gpt(): Perform GPT operations
>   *
> @@ -567,6 +749,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  		return do_disk_guid(blk_dev_desc, varname);
>  	} else if (strcmp(argv[1], "read") == 0) {
>  		return do_get_gpt_info(blk_dev_desc);
> +#ifdef CONFIG_CMD_GPT_FLIP
> +	} else if (strcmp(argv[1], "flip") == 0) {
> +		return do_flip_gpt_parts(blk_dev_desc);
>
Either make do_flip_gpt_part() return CMD_RET_... as indicated above, or
check its return value here and convert it to CMD_RET_SUCCESS or
CMD_RET_FAILURE.

Also see my comment to your patch 4/6 concerning this code location.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
@ 2017-05-31  2:07       ` Tom Rini
  2017-05-31  7:37       ` Lukasz Majewski
  1 sibling, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-05-31  2:07 UTC (permalink / raw)
  To: u-boot

On Mon, May 29, 2017 at 09:49:28AM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Reviewed-by: Tom Rini <trini@konsulko.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170530/17d50781/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
  2017-05-31  2:07       ` Tom Rini
@ 2017-05-31  7:37       ` Lukasz Majewski
  1 sibling, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31  7:37 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@she-devel.com>
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Acked-by: Lukasz Majewski <lukma@denx.de>

> ---
>  disk/part_efi.c | 2 +-
>  include/part.h  | 5 +++--
>  2 files changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/disk/part_efi.c b/disk/part_efi.c
> index 1b7ba27..20d33ef 100644
> --- a/disk/part_efi.c
> +++ b/disk/part_efi.c
> @@ -183,7 +183,7 @@ void part_print_efi(struct blk_desc *dev_desc)
>  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
> dev_desc->blksz); gpt_entry *gpt_pte = NULL;
>  	int i = 0;
> -	char uuid[37];
> +	char uuid[UUID_STR_LEN + 1];
>  	unsigned char *uuid_bin;
>  
>  	/* This function validates AND fills in the GPT header and
> PTE */ diff --git a/include/part.h b/include/part.h
> index 83bce05..6ace09f 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -9,6 +9,7 @@
>  
>  #include <blk.h>
>  #include <ide.h>
> +#include <uuid.h>
>  
>  struct block_drvr {
>  	char *name;
> @@ -54,10 +55,10 @@ typedef struct disk_partition {
>  	uchar	type[32];	/* string type
> description		*/ int	bootable;	/*
> Active/Bootable flag is set		*/ #if
> CONFIG_IS_ENABLED(PARTITION_UUIDS)
> -	char	uuid[37];	/* filesystem UUID as string,
> if exists	*/
> +	char	uuid[UUID_STR_LEN + 1];	/* filesystem
> UUID as string, if exists	*/ #endif
>  #ifdef CONFIG_PARTITION_TYPE_GUID
> -	char	type_guid[37];	/* type GUID as string, if
> exists	*/
> +	char	type_guid[UUID_STR_LEN + 1];	/* type GUID
> as string, if exists	*/ #endif
>  #ifdef CONFIG_DOS_PARTITION
>  	uchar	sys_ind;	/* partition type
> 			*/




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
@ 2017-05-31  7:37       ` Lukasz Majewski
  2017-05-31 13:50       ` Tom Rini
  1 sibling, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31  7:37 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@she-devel.com>
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  include/part.h | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
> 
> diff --git a/include/part.h b/include/part.h
> index 6ace09f..87b1111 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -47,12 +47,15 @@ struct block_drvr {
>  #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
>  #define DEV_TYPE_OPDISK		0x07	/* optical disk */
>  
> +#define PART_NAME_LEN 32
> +#define PART_TYPE_LEN 32
> +
>  typedef struct disk_partition {
>  	lbaint_t	start;	/* # of first block in
> partition	*/ lbaint_t	size;	/* number of blocks
> in partition	*/ ulong	blksz;		/* block
> size in bytes			*/
> -	uchar	name[32];	/* partition
> name			*/
> -	uchar	type[32];	/* string type
> description		*/
> +	uchar	name[PART_NAME_LEN];	/* partition
> name			*/
> +	uchar	type[PART_TYPE_LEN];	/* string type
> description		*/ int	bootable;	/*
> Active/Bootable flag is set		*/ #if
> CONFIG_IS_ENABLED(PARTITION_UUIDS) char	uuid[UUID_STR_LEN +
> 1];	/* filesystem UUID as string, if exists	*/


Acked-by: Lukasz Majewski <lukma@denx.de>

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID alison at peloton-tech.com
  2017-05-30  6:46       ` Lothar Waßmann
@ 2017-05-31  7:44       ` Lukasz Majewski
  2017-05-31  8:47         ` Lothar Waßmann
  1 sibling, 1 reply; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31  7:44 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@she-devel.com>
> 
> In order to read the GPT, modify the partition name strings, and then
> write out a new GPT, the disk GUID is needed.  While there is an
> existing accessor for the partition UUIDs, there is none yet for the
> disk GUID.

Acked-by: Lukasz Majewski <lukma@denx.de>

> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c       | 30 +++++++++++++++++++++++++++++-
>  disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
>  doc/README.gpt  |  3 ++-
>  include/part.h  | 15 +++++++++++++++
>  4 files changed, 77 insertions(+), 2 deletions(-)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 3e98821..3b7d929 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc
> *blk_dev_desc, const char *str_part) return ret;
>  }
>  
> +static int do_disk_guid(struct blk_desc *dev_desc, char * const
> namestr) +{
> +	int ret;
> +	char disk_guid[UUID_STR_LEN + 1];
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return 1;
> +
> +	if (namestr)
> +		setenv(namestr, disk_guid);
> +	else
> +		printf("%s\n", disk_guid);
> +
> +	return 0;
> +}
> +
>  /**
>   * do_gpt(): Perform GPT operations
>   *
> @@ -412,7 +429,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int
> argc, char * const argv[]) {
>  	int ret = CMD_RET_SUCCESS;
>  	int dev = 0;
> -	char *ep;
> +	char *ep, *varname = NULL;
>  	struct blk_desc *blk_dev_desc = NULL;
>  
>  	if (argc < 4 || argc > 5)
> @@ -436,6 +453,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag,
> int argc, char * const argv[]) } else if ((strcmp(argv[1], "verify")
> == 0)) { ret = gpt_verify(blk_dev_desc, argv[4]);
>  		printf("Verify GPT: ");
> +	} else if (strcmp(argv[1], "guid") == 0) {
> +		if (argc == 5)
> +		       strcpy(varname, argv[4]);
> +		return do_disk_guid(blk_dev_desc, varname);
>  	} else {
>  		return CMD_RET_USAGE;
>  	}
> @@ -458,4 +479,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt write mmc 0 $partitions\n"
>  	" gpt verify mmc 0 $partitions\n"
> +	" guid <interface> <dev>\n"
> +	"    - print disk GUID\n"
> +	" guid <interface> <dev> <varname>\n"
> +	"    - set environment variable to disk GUID\n"
> +	" Example usage:\n"
> +	" gpt guid mmc 0\n"
> +	" gpt guid mmc 0 varname\n"
>  );
> diff --git a/disk/part_efi.c b/disk/part_efi.c
> index 20d33ef..ff9f408 100644
> --- a/disk/part_efi.c
> +++ b/disk/part_efi.c
> @@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header
> *gpt_h)
>   * Public Functions (include/part.h)
>   */
>  
> +/*
> + * UUID is displayed as 32 hexadecimal digits, in 5 groups,
> + * separated by hyphens, in the form 8-4-4-4-12 for a total of 36
> characters
> + */
> +int get_disk_guid(struct blk_desc * dev_desc, char *guid)
> +{
> +	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
> dev_desc->blksz);
> +	gpt_entry *gpt_pte = NULL;
> +	unsigned char *guid_bin;
> +
> +	/* This function validates AND fills in the GPT header and
> PTE */
> +	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
> +			 gpt_head, &gpt_pte) != 1) {
> +		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
> +		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
> +				 gpt_head, &gpt_pte) != 1) {
> +			printf("%s: *** ERROR: Invalid Backup GPT
> ***\n",
> +			       __func__);
> +			return -1;
> +		} else {
> +			printf("%s: ***        Using Backup GPT
> ***\n",
> +			       __func__);
> +		}
> +	}
> +
> +	guid_bin = (unsigned char *)(gpt_head->disk_guid.b);
> +	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
> +
> +	return 0;
> +}
> +
>  void part_print_efi(struct blk_desc *dev_desc)
>  {
>  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
> dev_desc->blksz); diff --git a/doc/README.gpt b/doc/README.gpt
> index 3fcd835..c0779a4 100644
> --- a/doc/README.gpt
> +++ b/doc/README.gpt
> @@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
>     The fields 'uuid' and 'uuid_disk' are optional if
> CONFIG_RANDOM_UUID is enabled. A random uuid will be used if omitted
> or they point to an empty/ non-existent environment variable. The
> environment variable will be set to
> -   the generated UUID.
> +   the generated UUID.  The 'gpt guid' command reads the current
> value of the
> +   uuid_disk from the GPT.
>  
>     The field 'bootable' is optional, it is used to mark the GPT
> partition bootable (set attribute flags "Legacy BIOS bootable").
> diff --git a/include/part.h b/include/part.h
> index 87b1111..16c4a46 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc
> *dev_desc, gpt_header *gpt_head, int gpt_verify_partitions(struct
> blk_desc *dev_desc, disk_partition_t *partitions, int parts,
>  			  gpt_header *gpt_head, gpt_entry **gpt_pte);
> +
> +
> +/**
> + * get_disk_guid() - Function to read the GUID string from a
> device's GPT
> + *
> + * This function reads the GUID string from a block device whose
> descriptor
> + * is provided.
> + *
> + * @param dev_desc - block device descriptor
> + * @param guid - pre-allocated string in which to return the GUID
> + *
> + * @return - '0' on success, otherwise error
> + */
> +int get_disk_guid(struct blk_desc *dev_desc, char *guid);
> +
>  #endif
>  
>  #if CONFIG_IS_ENABLED(DOS_PARTITION)




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure alison at peloton-tech.com
  2017-05-30  7:37       ` Lothar Waßmann
@ 2017-05-31  7:48       ` Lukasz Majewski
  2017-05-31  8:48         ` Lothar Waßmann
  2017-05-31 14:07         ` Lukasz Majewski
  1 sibling, 2 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31  7:48 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@she-devel.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.

Acked-by: Lukasz Majewski <lukma@denx.de>

> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c      | 112
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> include/part.h |   8 +++++ 2 files changed, 120 insertions(+)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 3b7d929..c61d2b1 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -19,6 +19,9 @@
>  #include <linux/ctype.h>
>  #include <div64.h>
>  #include <memalign.h>
> +#include <linux/compat.h>
> +
> +static LIST_HEAD(disk_partitions);
>  
>  /**
>   * extract_env(): Expand env name from string format '&{env_name}'
> @@ -151,6 +154,111 @@ static bool found_key(const char *str, const
> char *key) return result;
>  }
>  
> +static void del_gpt_info(void)
> +{
> +	struct list_head *pos = &disk_partitions;
> +	struct disk_part *curr;
> +	while (!list_empty(pos)) {
> +		curr = list_entry(pos->next, struct disk_part, list);
> +		list_del(pos->next);
> +		free(curr);
> +	}
> +}
> +
> +static struct disk_part *allocate_disk_part(disk_partition_t *info,
> int partnum) +{
> +	struct disk_part *newpart;
> +	newpart = (struct disk_part *)malloc(sizeof(*newpart));
> +	memset(newpart, '\0', sizeof(newpart));
> +	if (!newpart)
> +		return ERR_PTR(-ENOMEM);
> +
> +	newpart->gpt_part_info.start = info->start;
> +	newpart->gpt_part_info.size = info->size;
> +	newpart->gpt_part_info.blksz = info->blksz;
> +	strncpy((char *)newpart->gpt_part_info.name, (const char
> *)info->name, PART_NAME_LEN);
> +	memset(newpart->gpt_part_info.name + 31, '\0', 1);
> +	strncpy((char *)newpart->gpt_part_info.type, (const char
> *)info->type, PART_TYPE_LEN);
> +	memset(newpart->gpt_part_info.type + 31, '\0', 1);
> +	newpart->gpt_part_info.bootable = info->bootable;
> +#ifdef CONFIG_PARTITION_UUIDS
> +	strncpy(newpart->gpt_part_info.uuid, (const char
> *)info->uuid,
> +		UUID_STR_LEN);
> +#endif
> +	newpart->partnum = partnum;
> +
> +	return newpart;
> +}
> +
> +static void print_gpt_info(void)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		printf("Partition %d:\n", curr->partnum);
> +		printf("1st block %x, size %x\n",
> (unsigned)curr->gpt_part_info.start,
> +		       (unsigned)curr->gpt_part_info.size);
> +		printf("Block size %lu, name %s\n",
> curr->gpt_part_info.blksz,
> +		       curr->gpt_part_info.name);
> +		printf("Type %s, bootable %d\n",
> curr->gpt_part_info.type,
> +		       curr->gpt_part_info.bootable);
> +#ifdef CONFIG_PARTITION_UUIDS
> +		printf("UUID %s\n", curr->gpt_part_info.uuid);
> +#endif
> +		printf("\n");
> +	}
> +}
> +
> +/*
> + * read partition info into disk_partitions list where
> + * it can be printed or modified
> + */
> +static int get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	/* start partition numbering at 1, as u-boot does */
> +	int valid_parts = 1, p, ret = 0;
> +	disk_partition_t info;
> +	struct disk_part *new_disk_part;
> +
> +	if (disk_partitions.next == NULL)
> +		INIT_LIST_HEAD(&disk_partitions);
> +
> +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> +		ret = part_get_info(dev_desc, p, &info);
> +		if (ret)
> +			continue;
> +
> +		new_disk_part = allocate_disk_part(&info,
> valid_parts);
> +		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
> +			return -1;
> +
> +		list_add_tail(&new_disk_part->list,
> &disk_partitions);
> +		valid_parts++;
> +	}
> +	if (!valid_parts) {
> +		printf("** No valid partitions found **\n");
> +		del_gpt_info();
> +		return -ENODEV;
> +	}
> +	return --valid_parts;
> +}
> +
> +/* a wrapper to test get_gpt_info */
> +static int do_get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	int ret;
> +
> +	ret = get_gpt_info(dev_desc);
> +	if (ret > 0) {
> +		print_gpt_info();
> +		del_gpt_info();
> +	}
> +	return ret;
> +}
> +
> +
>  /**
>   * set_gpt_info(): Fill partition information from string
>   *		function allocates memory, remember to free!
> @@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int
> argc, char * const argv[]) if (argc == 5)
>  		       strcpy(varname, argv[4]);
>  		return do_disk_guid(blk_dev_desc, varname);
> +	} else if (strcmp(argv[1], "read") == 0) {
> +		return do_get_gpt_info(blk_dev_desc);
>  	} else {
>  		return CMD_RET_USAGE;
>  	}
> @@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt write mmc 0 $partitions\n"
>  	" gpt verify mmc 0 $partitions\n"
> +	" read <interface> <dev>\n"
> +	"    - read GPT into a data structure for manipulation\n"
>  	" guid <interface> <dev>\n"
>  	"    - print disk GUID\n"
>  	" guid <interface> <dev> <varname>\n"
> diff --git a/include/part.h b/include/part.h
> index 16c4a46..7d7052a 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -10,6 +10,7 @@
>  #include <blk.h>
>  #include <ide.h>
>  #include <uuid.h>
> +#include <linux/list.h>
>  
>  struct block_drvr {
>  	char *name;
> @@ -49,6 +50,7 @@ struct block_drvr {
>  
>  #define PART_NAME_LEN 32
>  #define PART_TYPE_LEN 32
> +#define MAX_SEARCH_PARTITIONS 16
>  
>  typedef struct disk_partition {
>  	lbaint_t	start;	/* # of first block in
> partition	*/ @@ -68,6 +70,12 @@ typedef struct disk_partition {
>  #endif
>  } disk_partition_t;
>  
> +struct disk_part {
> +	int partnum;
> +	disk_partition_t gpt_part_info;
> +	struct list_head list;
> +};
> +
>  /* Misc _get_dev functions */
>  #ifdef CONFIG_PARTITIONS
>  /**




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure alison at peloton-tech.com
  2017-05-30  7:38       ` Lothar Waßmann
@ 2017-05-31  8:12       ` Lukasz Majewski
  2017-06-01  7:04         ` Chaiken, Alison
                           ` (2 more replies)
  1 sibling, 3 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31  8:12 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@she-devel.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via a new 'gpt flip'
> command which is enabled via a CONFIG_CMD_GPT_FLIP option.
> 
> The concept for the bootloader state machine is the following:
> 
> -- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
>    to boot them.
> -- Linux, at boot, will rename ‘candidate’ partitions as
>    ‘primary’.
> -- If u-boot sees a ‘candidate’ partition after a boot attempt,
>    it renames it failed’ and renames the ‘backup’ partition as
>    ‘candidate’.
> 
> Logic:
> -- Partitions can go to ‘failed’ only from ‘candidate’ and only
>    via u-boot.  Partitions can go to ‘backup’ only from ‘primary’
>    and vice-versa, only via Linux.  Partitions go to ‘candidate’
>    from ‘primary’ or ‘backup’ only via u-boot.  Only system
>    update software will rename 'failed' partitions.
> 
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/Kconfig    |   7 ++
>  cmd/gpt.c      | 199
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> doc/README.gpt |  13 ++++ 3 files changed, 215 insertions(+), 4
> deletions(-)
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 5ee52f6..a8f7716 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -575,6 +575,13 @@ config CMD_GPT
>  	  Enable the 'gpt' command to ready and write GPT style
> partition tables.
>  
> +config CMD_GPT_FLIP
> +	bool "GPT flip-partitions command"
> +	depends on CMD_GPT
> +	help
> +	  Enables the 'gpt' command to write modified GPT partition
> +	  tables via the 'gpt flip' command.
> +
>  config CMD_ARMFLASH
>  	#depends on FLASH_CFI_DRIVER
>  	bool "armflash"
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index c61d2b1..6a0b70f 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -20,6 +20,7 @@
>  #include <div64.h>
>  #include <memalign.h>
>  #include <linux/compat.h>
> +#include <linux/sizes.h>
>  
>  static LIST_HEAD(disk_partitions);
>  
> @@ -190,16 +191,33 @@ static struct disk_part
> *allocate_disk_part(disk_partition_t *info, int partnum) return
> newpart; }
>  
> +static void prettyprint_part_size(char *sizestr, unsigned long
> partsize,
> +				  unsigned long blksize)
> +{
> +	unsigned long long partbytes;
> +	unsigned long partmegabytes;
> +
> +	partbytes = partsize * blksize;
> +	partmegabytes = lldiv(partbytes, SZ_1M);
> +	snprintf(sizestr, 16, "%luMiB", partmegabytes);
> +}
> +
>  static void print_gpt_info(void)
>  {
>  	struct list_head *pos;
>  	struct disk_part *curr;
> +	char partstartstr[16];
> +	char partsizestr[16];
>  
>  	list_for_each(pos, &disk_partitions) {
>  		curr = list_entry(pos, struct disk_part, list);
> +		prettyprint_part_size(partstartstr, (unsigned
> long)curr->gpt_part_info.start,
> +				      (unsigned long)
> curr->gpt_part_info.blksz);
> +		prettyprint_part_size(partsizestr, (unsigned
> long)curr->gpt_part_info.size,
> +				      (unsigned long)
> curr->gpt_part_info.blksz); +
>  		printf("Partition %d:\n", curr->partnum);
> -		printf("1st block %x, size %x\n",
> (unsigned)curr->gpt_part_info.start,
> -		       (unsigned)curr->gpt_part_info.size);
> +		printf("Start %s, size %s\n", partstartstr,
> partsizestr); printf("Block size %lu, name %s\n",
> curr->gpt_part_info.blksz, curr->gpt_part_info.name);
>  		printf("Type %s, bootable %d\n",
> curr->gpt_part_info.type, @@ -211,6 +229,85 @@ static void
> print_gpt_info(void) }
>  }
>  
> +#ifdef CONFIG_CMD_GPT_FLIP
> +static int calc_parts_list_len(int numparts)
> +{
> +	/*
> +	 * prefatory string:
> +	 * doc/README.GPT, suggests that
> +	 * int partlistlen = UUID_STR_LEN + 1 +
> strlen("partitions=uuid_disk=");
> +	 * is correct, but extract_val() expects "uuid_disk" first.
> +	 */
> +	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> +	/* for the comma */
> +	partlistlen++;
> +
> +	/* per-partition additions; numparts starts at 1, so this
> should be correct */
> +	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN
> + 1);
> +	/* 17 because partstr in create_gpt_partitions_list() is 16
> chars */
> +	partlistlen += numparts * (strlen("start=MiB,") + 17);
> +	partlistlen += numparts * (strlen("size=MiB,") + 17);
> +	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN +
> 1);
> +	/* for the terminating null */
> +	partlistlen++;
> +	debug("Length of partitions_list is %d for %d partitions\n",
> partlistlen,
> +	       numparts);
> +	return partlistlen;
> +}
> +
> +/*
> + * create the string that upstream 'gpt write' command will accept
> as an
> + * argument
> + *
> + * From doc/README.gpt, Format of partitions layout:
> + *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> + *	name=kernel,size=60MiB,uuid=...;"
> + * The fields 'name' and 'size' are mandatory for every partition.
> + * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
> + * are optional if CONFIG_RANDOM_UUID is enabled.
> + */
> +static int create_gpt_partitions_list(int numparts, const char
> *guid, char *partitions_list) +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	char partstr[PART_NAME_LEN + 1];
> +
> +	if (!partitions_list)
> +		return -1;
> +
> +	/*
> +	 * README.gpt specifies starting with "partitions=" like so:
> +	 *      strcpy(partitions_list, "partitions=uuid_disk=");
> +	 * but that breaks extract_val, which doesn't skip over
> 'partitions='.
> +	 */
> +	strcpy(partitions_list, "uuid_disk=");
> +	strncat(partitions_list, guid, UUID_STR_LEN + 1);
> +	strcat(partitions_list, ";");
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		strcat(partitions_list, "name=");
> +		strncat(partitions_list, (const char
> *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
> +		strcat(partitions_list, ",start=");
> +		prettyprint_part_size(partstr, (unsigned
> long)curr->gpt_part_info.start,
> +				      (unsigned long)
> curr->gpt_part_info.blksz);
> +		/* one extra byte for NULL */
> +		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
> +		strcat(partitions_list, ",size=");
> +		/* lbaint_t is unsigned long, per include/ide.h */
> +		prettyprint_part_size(partstr, (unsigned
> long)curr->gpt_part_info.size,
> +				      (unsigned long)
> curr->gpt_part_info.blksz);
> +		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
> +
> +		strcat(partitions_list, ",uuid=");
> +		strncat(partitions_list, (const char
> *)curr->gpt_part_info.uuid,
> +			UUID_STR_LEN + 1);
> +		strcat(partitions_list, ";");
> +	}
> +	return 0;
> +}
> +#endif
> +
>  /*
>   * read partition info into disk_partitions list where
>   * it can be printed or modified
> @@ -222,8 +319,11 @@ static int get_gpt_info(struct blk_desc
> *dev_desc) disk_partition_t info;
>  	struct disk_part *new_disk_part;
>  
> -	if (disk_partitions.next == NULL)
> -		INIT_LIST_HEAD(&disk_partitions);
> +	/*
> +	 * Always re-read partition info from device, in case
> +	 * it has changed
> +	 */
> +	INIT_LIST_HEAD(&disk_partitions);
>  
>  	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
>  		ret = part_get_info(dev_desc, p, &info);
> @@ -294,6 +394,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  		return -1;
>  
>  	str = strdup(str_part);
> +	if (str == NULL)
> +		return -ENOMEM;
>  
>  	/* extract disk guid */
>  	s = str;
> @@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc
> *dev_desc, char * const namestr) return 0;
>  }
>  
> +#ifdef CONFIG_CMD_GPT_FLIP
> +static int do_flip_gpt_parts(struct blk_desc *dev_desc)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	disk_partition_t *new_partitions = NULL;
> +	char disk_guid[UUID_STR_LEN + 1];
> +	char *partitions_list, *str_disk_guid;
> +	u8 part_count = 0;
> +	int partlistlen, ret, numparts = 0;
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return ret;
> +
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
> +	printf("Current partition table with %d partitions is:\n",
> numparts);
> +	print_gpt_info();
> +
> +	partlistlen = calc_parts_list_len(numparts);
> +	partitions_list = (char *)malloc(partlistlen);
> +	memset(partitions_list, '\0', partlistlen);
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *)
> disk_guid,
> +					 partitions_list);
> +	if (ret < 0)
> +		return ret;
> +	debug("OLD partitions_list is %s with %d chars\n",
> partitions_list, strlen(partitions_list)); +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list,
> &str_disk_guid,
> +			   &new_partitions, &part_count);
> +	if (ret < 0)
> +		return ret;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		if (!strcmp((char *)curr->gpt_part_info.name,
> "backup_kernel"))
> +			strcpy((char *)curr->gpt_part_info.name,
> "candidate_kernel");
> +		if (!strcmp((char *)curr->gpt_part_info.name,
> "primary_kernel"))
> +			strcpy((char *)curr->gpt_part_info.name,
> "backup_kernel");
> +		if (!strcmp((char *)curr->gpt_part_info.name,
> "backup_rootfs"))
> +			strcpy((char *)curr->gpt_part_info.name,
> "candidate_rootfs");
> +		if (!strcmp((char *)curr->gpt_part_info.name,
> "primary_rootfs"))
> +			strcpy((char *)curr->gpt_part_info.name,
> "backup_rootfs");
> +	}
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *)
> disk_guid, partitions_list);
> +	if (ret < 0)
> +		return ret;
> +	debug("NEW partitions_list is %s with %d chars\n",
> partitions_list, strlen(partitions_list)); +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list,
> &str_disk_guid,
> +			   &new_partitions, &part_count);
> +	if (ret < 0)
> +		return ret;
> +
> +	debug("Writing new partition table\n");
> +	ret = gpt_restore(dev_desc, disk_guid, new_partitions,
> numparts);
> +	if (ret < 0) {
> +		printf("Writing new partition table failed\n");
> +		return ret;
> +	}
> +
> +	debug("Reading back new partition table\n");
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
> +	printf("new partition table with %d partitions is:\n",
> numparts);
> +	print_gpt_info();
> +
> +	del_gpt_info();
> +	free(partitions_list);
> +	free(str_disk_guid);
> +	free(new_partitions);
> +	return ret;
> +}
> +#endif
> +
>  /**
>   * do_gpt(): Perform GPT operations
>   *
> @@ -567,6 +749,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag,
> int argc, char * const argv[]) return do_disk_guid(blk_dev_desc,
> varname); } else if (strcmp(argv[1], "read") == 0) {
>  		return do_get_gpt_info(blk_dev_desc);
> +#ifdef CONFIG_CMD_GPT_FLIP
> +	} else if (strcmp(argv[1], "flip") == 0) {
> +		return do_flip_gpt_parts(blk_dev_desc);
> +#endif
>  	} else {
>  		return CMD_RET_USAGE;
>  	}
> @@ -598,4 +784,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt guid mmc 0\n"
>  	" gpt guid mmc 0 varname\n"
> +#ifdef CONFIG_CMD_GPT_FLIP
> +	"gpt partition-flip command\n"
> +	"gpt flip <interface> <dev>\n"
> +	"    - exchange device's 'primary' and 'backup' partition
> names\n" +#endif
>  );
> diff --git a/doc/README.gpt b/doc/README.gpt
> index c0779a4..e29b188 100644
> --- a/doc/README.gpt
> +++ b/doc/README.gpt
> @@ -210,6 +210,19 @@ Following line can be used to assess if GPT
> verification has succeed: U-BOOT> gpt verify mmc 0 $partitions
>  U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
>  
> +Renaming GPT partitions from U-Boot:
> +====================================
> +
> +GPT partition names are a mechanism via which userspace and U-Boot
> can +communicate about software updates and boot failure.  The 'gpt
> guid', +'gpt read' and 'gpt flip' commands facilitate programmatic
> renaming of +partitions from bootscripts by generating and modifying
> the partitions +layout string.  The code in gpt_flip() illustrates
> the case of +swapping 'primary' and 'backup' partitions via:
> +
> +U-BOOT> gpt flip mmc 0

Maybe it would be better to have 

gpt flip mmc 0 <optional parameter 'name'>

(By default we have "primary" and "backup")

In that way we could set other names to GPT partitions without the
need to modify the code.





And another request -> Could you consider adding tests for those new
gpt commands to the 'sandbox' (sandbox_defconfig) ?

Then you can 'mount' some gpt test image ('host' command) and use it
with:
gpt <command> host X .....


Despite above comments - you did a great job :-)

Reviewed-by: Lukasz Majewski <lukma@denx.de>

> +
> +Choose different partition names by modifying these strings in gpt.c.
>  
>  Partition type GUID:
>  ====================




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc alison at peloton-tech.com
@ 2017-05-31  8:14       ` Lukasz Majewski
  2017-05-31 11:21         ` Lukasz Majewski
  0 siblings, 1 reply; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31  8:14 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@she-devel.com>
> 
> The existing partitions-list parsing in cmd/gpt.c passes a value
> from gpt_default() to set_gpt_info() that README.gpt suggests
> should begin with 'partitions='.  Partition-list strings should
> in fact begin with 'uuid_disk', as otherwise the call from
> set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
> Change README.gpt and file comments accordingly.

Acked-by: Lukasz Majewski <lukma@denx.de>

Thank you for updating the README.gpt entry.

> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c      | 13 +------------
>  doc/README.gpt |  8 ++++----
>  2 files changed, 5 insertions(+), 16 deletions(-)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 6a0b70f..487314b 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -232,12 +232,6 @@ static void print_gpt_info(void)
>  #ifdef CONFIG_CMD_GPT_FLIP
>  static int calc_parts_list_len(int numparts)
>  {
> -	/*
> -	 * prefatory string:
> -	 * doc/README.GPT, suggests that
> -	 * int partlistlen = UUID_STR_LEN + 1 +
> strlen("partitions=uuid_disk=");
> -	 * is correct, but extract_val() expects "uuid_disk" first.
> -	 */
>  	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
>  	/* for the comma */
>  	partlistlen++;
> @@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
>   * argument
>   *
>   * From doc/README.gpt, Format of partitions layout:
> - *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> + *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
>   *	name=kernel,size=60MiB,uuid=...;"
>   * The fields 'name' and 'size' are mandatory for every partition.
>   * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
> @@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int
> numparts, const char *guid, char *part if (!partitions_list)
>  		return -1;
>  
> -	/*
> -	 * README.gpt specifies starting with "partitions=" like so:
> -	 *      strcpy(partitions_list, "partitions=uuid_disk=");
> -	 * but that breaks extract_val, which doesn't skip over
> 'partitions='.
> -	 */
>  	strcpy(partitions_list, "uuid_disk=");
>  	strncat(partitions_list, guid, UUID_STR_LEN + 1);
>  	strcat(partitions_list, ";");
> diff --git a/doc/README.gpt b/doc/README.gpt
> index e29b188..754e490 100644
> --- a/doc/README.gpt
> +++ b/doc/README.gpt
> @@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
>  To restore GUID partition table one needs to:
>  1. Define partition layout in the environment.
>     Format of partitions layout:
> -     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> +     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
>  	name=kernel,size=60MiB,uuid=...;"
>       or
> -     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
> +     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
>  	size=${uboot_size},uuid=${uboot_uuid};"
>  
>     The fields 'name' and 'size' are mandatory for every partition.
> @@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID
> (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7). If you define
> 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type' can
> specify a other partition type guid: 
> -     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> +     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
>  	name=kernel,size=60MiB,uuid=...,
>  	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
>  
> @@ -255,7 +255,7 @@ Some strings can be also used at the place of
> known GUID : "lvm"    = PARTITION_LINUX_LVM_GUID
>  	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
>  
> -    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> +    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
>  	name=kernel,size=60MiB,uuid=...,type=linux;"
>  
>  They are also used to display the type of partition in "part list"
> command.




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID
  2017-05-31  7:44       ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID Lukasz Majewski
@ 2017-05-31  8:47         ` Lothar Waßmann
  0 siblings, 0 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-31  8:47 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, 31 May 2017 09:44:43 +0200 Lukasz Majewski wrote:
> Hi Alison,
> 
> > From: Alison Chaiken <alison@she-devel.com>
> > 
> > In order to read the GPT, modify the partition name strings, and then
> > write out a new GPT, the disk GUID is needed.  While there is an
> > existing accessor for the partition UUIDs, there is none yet for the
> > disk GUID.
> 
> Acked-by: Lukasz Majewski <lukma@denx.de>
> 
Did you read my comments on this patch in:
<20170530084651.545d9954@ipc1.ka-ro>
e.g.:
|> +		if (argc == 5)
|> +		       strcpy(varname, argv[4]);
|>  
|You didn't allocate any memory for varname and copy the argument string
|to a NULL pointer!
|Maybe use strdup() and free varname after use?



Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-31  7:48       ` Lukasz Majewski
@ 2017-05-31  8:48         ` Lothar Waßmann
  2017-05-31 11:11           ` Lukasz Majewski
  2017-05-31 14:07         ` Lukasz Majewski
  1 sibling, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-31  8:48 UTC (permalink / raw)
  To: u-boot

Hi,

On Wed, 31 May 2017 09:48:45 +0200 Lukasz Majewski wrote:
> Hi Alison,
> 
> > From: Alison Chaiken <alison@she-devel.com>
> > 
> > Make the partition table available for modification by reading it from
> > the user-specified device into a linked list.   Provide an accessor
> > function for command-line testing.
> 
> Acked-by: Lukasz Majewski <lukma@denx.de>
> 
You definitely should read other peoples comments on patches before
blindly Acking them!


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-31  8:48         ` Lothar Waßmann
@ 2017-05-31 11:11           ` Lukasz Majewski
  2017-05-31 13:42             ` Lothar Waßmann
  0 siblings, 1 reply; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31 11:11 UTC (permalink / raw)
  To: u-boot

On Wed, 31 May 2017 10:48:59 +0200
Lothar Waßmann <LW@KARO-electronics.de> wrote:

> Hi,
> 
> On Wed, 31 May 2017 09:48:45 +0200 Lukasz Majewski wrote:
> > Hi Alison,
> > 
> > > From: Alison Chaiken <alison@she-devel.com>
> > > 
> > > Make the partition table available for modification by reading it
> > > from the user-specified device into a linked list.   Provide an
> > > accessor function for command-line testing.
> > 
> > Acked-by: Lukasz Majewski <lukma@denx.de>
> > 
> You definitely should read other peoples comments on patches before
> blindly Acking them!

Your reply to the original thread (v1):

From: Lothar Waßmann <LW@KARO-electronics.de>
To: alison at peloton-tech.com
Cc: u-boot at lists.denx.de, alison at she-devel.com, trini at konsulko.com

I was not added to TO/CC.

And unfortunately (from the lack of time) - I don't have time to
promptly reply/see all the responses to the ML.


Alison sent v2 on Mon (to which I was added to CC).

I've assumed that this was fixed for v2. Wasn't it?

> 
> 
> Lothar Waßmann




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc
  2017-05-31  8:14       ` Lukasz Majewski
@ 2017-05-31 11:21         ` Lukasz Majewski
  0 siblings, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31 11:21 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> Hi Alison,
> 
> > From: Alison Chaiken <alison@she-devel.com>
> > 
> > The existing partitions-list parsing in cmd/gpt.c passes a value
> > from gpt_default() to set_gpt_info() that README.gpt suggests
> > should begin with 'partitions='.  Partition-list strings should
> > in fact begin with 'uuid_disk', as otherwise the call from
> > set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
> > Change README.gpt and file comments accordingly.
> 
> Acked-by: Lukasz Majewski <lukma@denx.de>
> 
> Thank you for updating the README.gpt entry.

Please also use either patman or get_maintainer before sending the
patchset.

For exmaple:
./scripts/get_maintainer.pl 0001-wip.patch

In that way all relevant people would be informed :-)

> 
> > 
> > Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> > ---
> >  cmd/gpt.c      | 13 +------------
> >  doc/README.gpt |  8 ++++----
> >  2 files changed, 5 insertions(+), 16 deletions(-)
> > 
> > diff --git a/cmd/gpt.c b/cmd/gpt.c
> > index 6a0b70f..487314b 100644
> > --- a/cmd/gpt.c
> > +++ b/cmd/gpt.c
> > @@ -232,12 +232,6 @@ static void print_gpt_info(void)
> >  #ifdef CONFIG_CMD_GPT_FLIP
> >  static int calc_parts_list_len(int numparts)
> >  {
> > -	/*
> > -	 * prefatory string:
> > -	 * doc/README.GPT, suggests that
> > -	 * int partlistlen = UUID_STR_LEN + 1 +
> > strlen("partitions=uuid_disk=");
> > -	 * is correct, but extract_val() expects "uuid_disk" first.
> > -	 */
> >  	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> >  	/* for the comma */
> >  	partlistlen++;
> > @@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
> >   * argument
> >   *
> >   * From doc/README.gpt, Format of partitions layout:
> > - *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> > + *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> >   *	name=kernel,size=60MiB,uuid=...;"
> >   * The fields 'name' and 'size' are mandatory for every partition.
> >   * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
> > @@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int
> > numparts, const char *guid, char *part if (!partitions_list)
> >  		return -1;
> >  
> > -	/*
> > -	 * README.gpt specifies starting with "partitions=" like
> > so:
> > -	 *      strcpy(partitions_list, "partitions=uuid_disk=");
> > -	 * but that breaks extract_val, which doesn't skip over
> > 'partitions='.
> > -	 */
> >  	strcpy(partitions_list, "uuid_disk=");
> >  	strncat(partitions_list, guid, UUID_STR_LEN + 1);
> >  	strcat(partitions_list, ";");
> > diff --git a/doc/README.gpt b/doc/README.gpt
> > index e29b188..754e490 100644
> > --- a/doc/README.gpt
> > +++ b/doc/README.gpt
> > @@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
> >  To restore GUID partition table one needs to:
> >  1. Define partition layout in the environment.
> >     Format of partitions layout:
> > -     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> > +     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> >  	name=kernel,size=60MiB,uuid=...;"
> >       or
> > -     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
> > +     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
> >  	size=${uboot_size},uuid=${uboot_uuid};"
> >  
> >     The fields 'name' and 'size' are mandatory for every partition.
> > @@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID
> > (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7). If you define
> > 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type' can
> > specify a other partition type guid: 
> > -     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> > +     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> >  	name=kernel,size=60MiB,uuid=...,
> >  	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
> >  
> > @@ -255,7 +255,7 @@ Some strings can be also used at the place of
> > known GUID : "lvm"    = PARTITION_LINUX_LVM_GUID
> >  	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
> >  
> > -    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> > +    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> >  	name=kernel,size=60MiB,uuid=...,type=linux;"
> >  
> >  They are also used to display the type of partition in "part list"
> > command.
> 
> 
> 
> 
> Best regards,
> 
> Lukasz Majewski
> 
> --
> 
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de



Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-31 11:11           ` Lukasz Majewski
@ 2017-05-31 13:42             ` Lothar Waßmann
  0 siblings, 0 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-05-31 13:42 UTC (permalink / raw)
  To: u-boot

Lukasz Majewski <lukma@denx.de> wrote:

> On Wed, 31 May 2017 10:48:59 +0200
> Lothar Waßmann <LW@KARO-electronics.de> wrote:
> 
> > Hi,
> > 
> > On Wed, 31 May 2017 09:48:45 +0200 Lukasz Majewski wrote:
> > > Hi Alison,
> > > 
> > > > From: Alison Chaiken <alison@she-devel.com>
> > > > 
> > > > Make the partition table available for modification by reading it
> > > > from the user-specified device into a linked list.   Provide an
> > > > accessor function for command-line testing.
> > > 
> > > Acked-by: Lukasz Majewski <lukma@denx.de>
> > > 
> > You definitely should read other peoples comments on patches before
> > blindly Acking them!
> 
> Your reply to the original thread (v1):
> 
> From: Lothar Waßmann <LW@KARO-electronics.de>
> To: alison at peloton-tech.com
> Cc: u-boot at lists.denx.de, alison at she-devel.com, trini at konsulko.com
> 
> I was not added to TO/CC.
> 
> And unfortunately (from the lack of time) - I don't have time to
> promptly reply/see all the responses to the ML.
> 
> 
> Alison sent v2 on Mon (to which I was added to CC).
> 
> I've assumed that this was fixed for v2. Wasn't it?
> 
I replied to his v2 patch.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths
  2017-05-29 16:49     ` [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
  2017-05-31  7:37       ` Lukasz Majewski
@ 2017-05-31 13:50       ` Tom Rini
  1 sibling, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-05-31 13:50 UTC (permalink / raw)
  To: u-boot

On Mon, May 29, 2017 at 09:49:29AM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Reviewed-by: Tom Rini <trini@konsulko.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170531/f0de67f3/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-31  7:48       ` Lukasz Majewski
  2017-05-31  8:48         ` Lothar Waßmann
@ 2017-05-31 14:07         ` Lukasz Majewski
  1 sibling, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-05-31 14:07 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> Hi Alison,
> 
> > From: Alison Chaiken <alison@she-devel.com>
> > 
> > Make the partition table available for modification by reading it
> > from the user-specified device into a linked list.   Provide an
> > accessor function for command-line testing.
> 
> Acked-by: Lukasz Majewski <lukma@denx.de>

Sorry, but I was to fast.

Please fix problems pointed out by Lothar.

> 
> > 
> > Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> > ---
> >  cmd/gpt.c      | 112
> > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > include/part.h |   8 +++++ 2 files changed, 120 insertions(+)
> > 
> > diff --git a/cmd/gpt.c b/cmd/gpt.c
> > index 3b7d929..c61d2b1 100644
> > --- a/cmd/gpt.c
> > +++ b/cmd/gpt.c
> > @@ -19,6 +19,9 @@
> >  #include <linux/ctype.h>
> >  #include <div64.h>
> >  #include <memalign.h>
> > +#include <linux/compat.h>
> > +Lothar Waßmann <LW@KARO-electronics.de>
> > +static LIST_HEAD(disk_partitions);
> >  
> >  /**
> >   * extract_env(): Expand env name from string format '&{env_name}'
> > @@ -151,6 +154,111 @@ static bool found_key(const char *str, const
> > char *key) return result;
> >  }
> >  
> > +static void del_gpt_info(void)
> > +{
> > +	struct list_head *pos = &disk_partitions;
> > +	struct disk_part *curr;
> > +	while (!list_empty(pos)) {
> > +		curr = list_entry(pos->next, struct disk_part,
> > list);
> > +		list_del(pos->next);
> > +		free(curr);
> > +	}
> > +}
> > +
> > +static struct disk_part *allocate_disk_part(disk_partition_t *info,
> > int partnum) +{
> > +	struct disk_part *newpart;
> > +	newpart = (struct disk_part *)malloc(sizeof(*newpart));
> > +	memset(newpart, '\0', sizeof(newpart));
> > +	if (!newpart)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	newpart->gpt_part_info.start = info->start;
> > +	newpart->gpt_part_info.size = info->size;
> > +	newpart->gpt_part_info.blksz = info->blksz;
> > +	strncpy((char *)newpart->gpt_part_info.name, (const char
> > *)info->name, PART_NAME_LEN);
> > +	memset(newpart->gpt_part_info.name + 31, '\0', 1);
> > +	strncpy((char *)newpart->gpt_part_info.type, (const char
> > *)info->type, PART_TYPE_LEN);
> > +	memset(newpart->gpt_part_info.type + 31, '\0', 1);
> > +	newpart->gpt_part_info.bootable = info->bootable;
> > +#ifdef CONFIG_PARTITION_UUIDS
> > +	strncpy(newpart->gpt_part_info.uuid, (const char
> > *)info->uuid,
> > +		UUID_STR_LEN);
> > +#endif
> > +	newpart->partnum = partnum;
> > +
> > +	return newpart;
> > +}
> > +
> > +static void print_gpt_info(void)
> > +{
> > +	struct list_head *pos;
> > +	struct disk_part *curr;
> > +
> > +	list_for_each(pos, &disk_partitions) {
> > +		curr = list_entry(pos, struct disk_part, list);
> > +		printf("Partition %d:\n", curr->partnum);
> > +		printf("1st block %x, size %x\n",
> > (unsigned)curr->gpt_part_info.start,
> > +		       (unsigned)curr->gpt_part_info.size);
> > +		printf("Block size %lu, name %s\n",
> > curr->gpt_part_info.blksz,
> > +		       curr->gpt_part_info.name);
> > +		printf("Type %s, bootable %d\n",
> > curr->gpt_part_info.type,
> > +		       curr->gpt_part_info.bootable);
> > +#ifdef CONFIG_PARTITION_UUIDS
> > +		printf("UUID %s\n", curr->gpt_part_info.uuid);
> > +#endif
> > +		printf("\n");
> > +	}
> > +}
> > +
> > +/*
> > + * read partition info into disk_partitions list where
> > + * it can be printed or modified
> > + */
> > +static int get_gpt_info(struct blk_desc *dev_desc)
> > +{
> > +	/* start partition numbering at 1, as u-boot does */
> > +	int valid_parts = 1, p, ret = 0;
> > +	disk_partition_t info;
> > +	struct disk_part *new_disk_part;
> > +
> > +	if (disk_partitions.next == NULL)
> > +		INIT_LIST_HEAD(&disk_partitions);
> > +
> > +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> > +		ret = part_get_info(dev_desc, p, &info);
> > +		if (ret)
> > +			continue;
> > +
> > +		new_disk_part = allocate_disk_part(&info,
> > valid_parts);
> > +		if (IS_ERR(new_disk_part) && (valid_parts >= 2))
> > +			return -1;
> > +
> > +		list_add_tail(&new_disk_part->list,
> > &disk_partitions);
> > +		valid_parts++;
> > +	}
> > +	if (!valid_parts) {
> > +		printf("** No valid partitions found **\n");
> > +		del_gpt_info();
> > +		return -ENODEV;
> > +	}
> > +	return --valid_parts;
> > +}
> > +
> > +/* a wrapper to test get_gpt_info */
> > +static int do_get_gpt_info(struct blk_desc *dev_desc)
> > +{
> > +	int ret;
> > +
> > +	ret = get_gpt_info(dev_desc);
> > +	if (ret > 0) {
> > +		print_gpt_info();
> > +		del_gpt_info();
> > +	}
> > +	return ret;
> > +}
> > +
> > +
> >  /**
> >   * set_gpt_info(): Fill partition information from string
> >   *		function allocates memory, remember to free!
> > @@ -457,6 +565,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag,
> > int argc, char * const argv[]) if (argc == 5)
> >  		       strcpy(varname, argv[4]);
> >  		return do_disk_guid(blk_dev_desc, varname);
> > +	} else if (strcmp(argv[1], "read") == 0) {
> > +		return do_get_gpt_info(blk_dev_desc);
> >  	} else {
> >  		return CMD_RET_USAGE;
> >  	}
> > @@ -479,6 +589,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
> >  	" Example usage:\n"
> >  	" gpt write mmc 0 $partitions\n"
> >  	" gpt verify mmc 0 $partitions\n"
> > +	" read <interface> <dev>\n"
> > +	"    - read GPT into a data structure for manipulation\n"
> >  	" guid <interface> <dev>\n"
> >  	"    - print disk GUID\n"
> >  	" guid <interface> <dev> <varname>\n"
> > diff --git a/include/part.h b/include/part.h
> > index 16c4a46..7d7052a 100644
> > --- a/include/part.h
> > +++ b/include/part.h
> > @@ -10,6 +10,7 @@
> >  #include <blk.h>
> >  #include <ide.h>
> >  #include <uuid.h>
> > +#include <linux/list.h>
> >  
> >  struct block_drvr {
> >  	char *name;
> > @@ -49,6 +50,7 @@ struct block_drvr {
> >  
> >  #define PART_NAME_LEN 32
> >  #define PART_TYPE_LEN 32
> > +#define MAX_SEARCH_PARTITIONS 16
> >  
> >  typedef struct disk_partition {
> >  	lbaint_t	start;	/* # of first block in
> > partition	*/ @@ -68,6 +70,12 @@ typedef struct
> > disk_partition { #endif
> >  } disk_partition_t;
> >  
> > +struct disk_part {
> > +	int partnum;
> > +	disk_partition_t gpt_part_info;
> > +	struct list_head list;
> > +};
> > +
> >  /* Misc _get_dev functions */
> >  #ifdef CONFIG_PARTITIONS
> >  /**
> 
> 
> 
> 
> Best regards,
> 
> Lukasz Majewski
> 
> --
> 
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-05-30  7:37       ` Lothar Waßmann
@ 2017-06-01  6:34         ` Chaiken, Alison
  2017-06-01  9:48           ` Lothar Waßmann
  0 siblings, 1 reply; 116+ messages in thread
From: Chaiken, Alison @ 2017-06-01  6:34 UTC (permalink / raw)
  To: u-boot

On 2017-05-30 00:37, Lothar Waßmann wrote:
[ SNIP]
>> +#define MAX_SEARCH_PARTITIONS 16
> Why the hard limit to 16 partitions?
> A standard Android system will jump right in your face with this limit.

Lothar, I'm working on making the other changes you suggested.   
Meanwhile, the answer to this question is that I copied the macro from a 
header file in 2015.07, which is the version for which I developed the 
patches.   I saw no equivalent value in this latest release of Das 
U-Boot.   Do you have a better suggestion?   Is there a similar macro 
elsewhere that I failed to discover?

Thanks,
Alison

---
Alison Chaiken                      alison at she-devel.com, 650-279-5600
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos 
Simoudis

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-05-31  8:12       ` Lukasz Majewski
@ 2017-06-01  7:04         ` Chaiken, Alison
  2017-06-01  8:21           ` Lukasz Majewski
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-08-27 23:02         ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure Chaiken, Alison
  2 siblings, 1 reply; 116+ messages in thread
From: Chaiken, Alison @ 2017-06-01  7:04 UTC (permalink / raw)
  To: u-boot

On 2017-05-31 01:12, Lukasz Majewski wrote:

[ SNIP ]

> Maybe it would be better to have
> 
> gpt flip mmc 0 <optional parameter 'name'>
> 
> (By default we have "primary" and "backup")
> 
> In that way we could set other names to GPT partitions without the
> need to modify the code.

Another possibility is to support

     gpt flip mmc 0 <name 1> <name 2>

where two names are required, with defaults 'primary' and 'backup'.   
Perhaps I should rework patch 5 that way?  I considered this form for 
the original submission, but wasn't sure what other projects might find 
useful.

> And another request -> Could you consider adding tests for those new
> gpt commands to the 'sandbox' (sandbox_defconfig) ?

I will look into adding another patch to do that.   I'm sure such tests 
are a good idea for our project.

> Despite above comments - you did a great job :-)

Thanks.   I'm sorry to have omitted you, Lukasz, from the original 
submission, but I consulted an old version of MAINTAINERS from my 
original 2015.07.

-- Alison

---
Alison Chaiken                      alison at she-devel.com, 650-279-5600
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos 
Simoudis

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-06-01  7:04         ` Chaiken, Alison
@ 2017-06-01  8:21           ` Lukasz Majewski
  2017-06-01 15:06             ` Chaiken, Alison
  0 siblings, 1 reply; 116+ messages in thread
From: Lukasz Majewski @ 2017-06-01  8:21 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> On 2017-05-31 01:12, Lukasz Majewski wrote:
> 
> [ SNIP ]
> 
> > Maybe it would be better to have
> > 
> > gpt flip mmc 0 <optional parameter 'name'>
> > 
> > (By default we have "primary" and "backup")
> > 
> > In that way we could set other names to GPT partitions without the
> > need to modify the code.
> 
> Another possibility is to support
> 
>      gpt flip mmc 0 <name 1> <name 2>
> 
> where two names are required, with defaults 'primary' and 'backup'.   
> Perhaps I should rework patch 5 that way? 

Please correct my understanding if I'm wrong.

You parse GPT partitions to a list and there are only two names
possible:

"primary" and "backup".

When we call gpt filp we rename those names ("primary" -> "backup" and
the other way).

Ahhh..... so your patch would allow to rename "primary" to <name1> and
"backup" to <name2> for all names.

My idea was rather to have a gpt call to set name of a GPT partition....

> I considered this form for 
> the original submission, but wasn't sure what other projects might
> find useful.

I can image that somebody would like to change on the fly single GPT
partition name (when having/care about 2 partitions for his/her project
specific data).

But, I don't know how much effort it would take to implement it (and if
others would see it beneficial).

> 
> > And another request -> Could you consider adding tests for those new
> > gpt commands to the 'sandbox' (sandbox_defconfig) ?
> 
> I will look into adding another patch to do that.   I'm sure such
> tests are a good idea for our project.

It is relatively easy to use sandbox to test some high level stuff
(like file systems, gpt, etc). One don't need HW for it.

> 
> > Despite above comments - you did a great job :-)
> 
> Thanks.   I'm sorry to have omitted you, Lukasz, from the original 
> submission, but I consulted an old version of MAINTAINERS from my 
> original 2015.07.

It's Ok, don't worry. Things like that do happen....

> 
> -- Alison
> 
> ---
> Alison Chaiken                      alison at she-devel.com, 650-279-5600
> http://{ she-devel.com, exerciseforthereader.org }
> "We are giving up our privacy, one convenience at a time." --
> Evangelos Simoudis




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure
  2017-06-01  6:34         ` Chaiken, Alison
@ 2017-06-01  9:48           ` Lothar Waßmann
  0 siblings, 0 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-01  9:48 UTC (permalink / raw)
  To: u-boot

"Chaiken, Alison" <alison@she-devel.com> wrote:

> On 2017-05-30 00:37, Lothar Waßmann wrote:
> [ SNIP]
> >> +#define MAX_SEARCH_PARTITIONS 16
> > Why the hard limit to 16 partitions?
> > A standard Android system will jump right in your face with this limit.
> 
> Lothar, I'm working on making the other changes you suggested.   
> Meanwhile, the answer to this question is that I copied the macro from a 
> header file in 2015.07, which is the version for which I developed the 
> patches.   I saw no equivalent value in this latest release of Das 
> U-Boot.   Do you have a better suggestion?   Is there a similar macro 
> elsewhere that I failed to discover?
> 
I'm just concerned, that the limit may be too low for a certain class
of systems and see no reason why it shouldn't be set higher. There is
no memory allocation involved that would consume more memory with a
higher limit.

I'v seen, the macro is defined in disk/part.c. Maybe for consistency
this should be defined in some header file and used in the original
place and your patch.


Lothar Waßmann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-06-01  8:21           ` Lukasz Majewski
@ 2017-06-01 15:06             ` Chaiken, Alison
  2017-06-01 18:20               ` Lukasz Majewski
  0 siblings, 1 reply; 116+ messages in thread
From: Chaiken, Alison @ 2017-06-01 15:06 UTC (permalink / raw)
  To: u-boot

Lukasz Majewski wrote:

> Maybe it would be better to have
> 
> gpt flip mmc 0 <optional parameter 'name'>
> 
> (By default we have "primary" and "backup")
> 
> In that way we could set other names to GPT partitions without the
> need to modify the code.

I answered: 

>> Another possibility is to support
>> 
>> gpt flip mmc 0 <name 1> <name 2>
>> 
>> where two names are required, with defaults 'primary' and 'backup'.   
>> Perhaps I should rework patch 5 that way?

Lukasz responded: 

> Please correct my understanding if I'm wrong.
> 
> You parse GPT partitions to a list and there are only two names
> possible:
> 
> "primary" and "backup".
> 
> When we call gpt filp we rename those names ("primary" -> "backup" and
> the other way).
> 
> Ahhh..... so your patch would allow to rename "primary" to <name1> and
> "backup" to <name2> for all names.
> 
> My idea was rather to have a gpt call to set name of a GPT partition....

> I can image that somebody would like to change on the fly single GPT
> partition name (when having/care about 2 partitions for his/her project
> specific data).
> 
> But, I don't know how much effort it would take to implement it (and if
> others would see it beneficial).

I would propose then two options: 

    gpt rename mmc 0 <name 1> <name 2> 

which renames all the 1's to 2's, and 

    gpt flip mmc 0 <name 1> <name 2> 

which swaps the two name strings for all partitions where they're found.
 These two operations together with 'gpt write' then cover all the
common use cases I can imagine. 

I'm open to any other suggestions, of course.   I just posted what I
already had to get started. 

-- Alison 

---
Alison Chaiken                      alison at she-devel.com, 650-279-5600 
http://{ she-devel.com, exerciseforthereader.org } 
"We are giving up our privacy, one convenience at a time." -- Evangelos
Simoudis

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-06-01 15:06             ` Chaiken, Alison
@ 2017-06-01 18:20               ` Lukasz Majewski
  0 siblings, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-06-01 18:20 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> Lukasz Majewski wrote:
> 
> > Maybe it would be better to have
> > 
> > gpt flip mmc 0 <optional parameter 'name'>
> > 
> > (By default we have "primary" and "backup")
> > 
> > In that way we could set other names to GPT partitions without the
> > need to modify the code.
> 
> I answered: 
> 
> >> Another possibility is to support
> >> 
> >> gpt flip mmc 0 <name 1> <name 2>
> >> 
> >> where two names are required, with defaults 'primary' and
> >> 'backup'. Perhaps I should rework patch 5 that way?
> 
> Lukasz responded: 
> 
> > Please correct my understanding if I'm wrong.
> > 
> > You parse GPT partitions to a list and there are only two names
> > possible:
> > 
> > "primary" and "backup".
> > 
> > When we call gpt filp we rename those names ("primary" -> "backup"
> > and the other way).
> > 
> > Ahhh..... so your patch would allow to rename "primary" to <name1>
> > and "backup" to <name2> for all names.
> > 
> > My idea was rather to have a gpt call to set name of a GPT
> > partition....
> 
> > I can image that somebody would like to change on the fly single GPT
> > partition name (when having/care about 2 partitions for his/her
> > project specific data).
> > 
> > But, I don't know how much effort it would take to implement it
> > (and if others would see it beneficial).
> 
> I would propose then two options: 
> 
>     gpt rename mmc 0 <name 1> <name 2> 
> 
> which renames all the 1's to 2's, and 
> 
>     gpt flip mmc 0 <name 1> <name 2> 
> 
> which swaps the two name strings for all partitions where they're
> found. These two operations together with 'gpt write' then cover all
> the common use cases I can imagine. 

I think that this is enough. Let's wait for other's opinions (if
any).

> 
> I'm open to any other suggestions, of course.   I just posted what I
> already had to get started. 
> 
> -- Alison 
> 
> ---
> Alison Chaiken                      alison at she-devel.com,
> 650-279-5600 http://{ she-devel.com, exerciseforthereader.org } 
> "We are giving up our privacy, one convenience at a time." --
> Evangelos Simoudis



Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation
  2017-05-30  6:46       ` Lothar Waßmann
@ 2017-06-03  2:22         ` alison at peloton-tech.com
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID alison at peloton-tech.com
                             ` (5 more replies)
  0 siblings, 6 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-03  2:22 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

One way for userspace and the bootloader to exchange information about
dynamic image selection is via the storage device partition table, as
described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag.
When no partition on a device is bootable since the kernel and U-Boot
are stored elsewhere, the name field in the GPT partition table offers
another logical place to store information.  These patches allow users
to easily modify GPT partition names via bootscripts that can select
different images based on a boot-failure counter, or when userspace
installs a software update.

These patches have been (re)tested on a TI DRA7xx-based SOM with
U-Boot 2015.07.  The storage device is an eMMC.

Significant changes since v2:
-- Got rid of the need to allocate memory for the GUID string in
   do_gpt();
-- Fixed the problems with string NULL termination in
   allocate_disk_part();
-- Removed duplicate definition of MAX_SEARCH_PARTITIONS from
   disk/part.c and increased the value in include/part.h to 64;
-- Improved the commit message for "rename GPT partitions to detect
   boot failure" to better describe the version of the patch I
   submitted;
-- Fixed numerous small problems with function return values.

Significant changes since v1:
-- Put the gpt_flip() function and auxiliary ones inside a new
   CONFIG_CMD_GPT_FLIP option that depends on CMD_GPT.
-- Replace intentional overwriting of name and type string arrays with
   memset() instead.
-- Move part.h changes earlier in the patchset.
-- Add a few lines to README.gpt about the new gpt subcommands.

Added a few simple patches to do the following:
-- Replace remaining occurrences of '37' with UUID_STR_LEN+1;
-- Introduce new macros to get rid of the similar '32';
-- fix a smaller error in doc/README.gpt.

There are also some fixups of whitespace and formatting errors (plus
usual inevitable addition of new ones).

To do in future:
-- Add support for preserving the type flag for partitions. The u-boot
   version on which this patchset is based did not have this feature,
   and it's easy to add, but I need to figure how to test it first.

-- Add tests for the new gpt commands to the sandbox.


Alison Chaiken (5):
  GPT: add accessor function for disk GUID
  partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  GPT: read partition table from device into a data structure
  rename GPT partitions to detect boot failure
  GPT: fix error in partitions string doc

 cmd/Kconfig     |   7 ++
 cmd/gpt.c       | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 disk/part.c     |   1 -
 disk/part_efi.c |  31 ++++++
 doc/README.gpt  |  24 ++++-
 include/part.h  |  23 ++++
 6 files changed, 398 insertions(+), 6 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
@ 2017-06-03  2:22           ` alison at peloton-tech.com
  2017-06-06  8:20             ` Lothar Waßmann
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 2/5] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
                             ` (4 subsequent siblings)
  5 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-03  2:22 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

In order to read the GPT, modify the partition name strings, and then
write out a new GPT, the disk GUID is needed.  While there is an
existing accessor for the partition UUIDs, there is none yet for the
disk GUID.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 3e98821..4d00a35 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		return do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +477,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 20d33ef..71c3cb3 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -EINVAL;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = gpt_head->disk_guid.b;
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
diff --git a/doc/README.gpt b/doc/README.gpt
index 3fcd835..c0779a4 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
diff --git a/include/part.h b/include/part.h
index 87b1111..16c4a46 100644
--- a/include/part.h
+++ b/include/part.h
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 2/5] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-06-03  2:22           ` alison at peloton-tech.com
  2017-06-03 11:52             ` Lukasz Majewski
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
                             ` (3 subsequent siblings)
  5 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-03  2:22 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd
directory can find it.  At the same time, increase the value to
64 since some operating systems use many, and the resources
consumed by a larger value are minimal.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 disk/part.c    | 1 -
 include/part.h | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/disk/part.c b/disk/part.c
index 491b02d..e640a55 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -388,7 +388,6 @@ cleanup:
 
 #define PART_UNSPECIFIED -2
 #define PART_AUTO -1
-#define MAX_SEARCH_PARTITIONS 16
 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 			     struct blk_desc **dev_desc,
 			     disk_partition_t *info, int allow_whole_dev)
diff --git a/include/part.h b/include/part.h
index 16c4a46..c41aa6a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 64
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID alison at peloton-tech.com
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 2/5] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
@ 2017-06-03  2:22           ` alison at peloton-tech.com
  2017-06-06  8:28             ` Lothar Waßmann
  2017-06-06 10:43             ` [U-Boot] [PATCH v3 3/5] " Lothar Waßmann
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 4/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
                             ` (2 subsequent siblings)
  5 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-03  2:22 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 119 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 4d00a35..5c2651f 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && valid_parts >= 2)
+			return -ENODEV;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +563,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		return do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +587,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index c41aa6a..0cd803a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 4/5] rename GPT partitions to detect boot failure
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
                             ` (2 preceding siblings ...)
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-06-03  2:22           ` alison at peloton-tech.com
  2017-06-06  8:20             ` Lothar Waßmann
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 5/5] GPT: fix error in partitions string doc alison at peloton-tech.com
  2017-06-03 11:48           ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation Lukasz Majewski
  5 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-03  2:22 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via a new 'gpt flip'
command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
   to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
   ‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
   it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   7 ++
 cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 215 insertions(+), 4 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6f75b86..8b925e5 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 5c2651f..f6968de 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -190,16 +191,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -211,6 +229,85 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	/*
+	 * prefatory string:
+	 * doc/README.GPT, suggests that
+	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
+	 * is correct, but extract_val() expects "uuid_disk" first.
+	 */
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	/*
+	 * README.gpt specifies starting with "partitions=" like so:
+	 *      strcpy(partitions_list, "partitions=uuid_disk=");
+	 * but that breaks extract_val, which doesn't skip over 'partitions='.
+	 */
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -222,8 +319,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -294,6 +394,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -565,6 +747,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -596,4 +782,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_FLIP
+	"gpt partition-flip command\n"
+	"gpt flip <interface> <dev>\n"
+	"    - exchange device's 'primary' and 'backup' partition names\n"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index c0779a4..e29b188 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 5/5] GPT: fix error in partitions string doc
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
                             ` (3 preceding siblings ...)
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 4/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-06-03  2:22           ` alison at peloton-tech.com
  2017-06-03 11:48           ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation Lukasz Majewski
  5 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-03  2:22 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

The existing partitions-list parsing in cmd/gpt.c passes a value
from gpt_default() to set_gpt_info() that README.gpt suggests
should begin with 'partitions='.  Partition-list strings should
in fact begin with 'uuid_disk', as otherwise the call from
set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
Change README.gpt and file comments accordingly.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 13 +------------
 doc/README.gpt |  8 ++++----
 2 files changed, 5 insertions(+), 16 deletions(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index f6968de..e2cb2a1 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -232,12 +232,6 @@ static void print_gpt_info(void)
 #ifdef CONFIG_CMD_GPT_FLIP
 static int calc_parts_list_len(int numparts)
 {
-	/*
-	 * prefatory string:
-	 * doc/README.GPT, suggests that
-	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
-	 * is correct, but extract_val() expects "uuid_disk" first.
-	 */
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
 	/* for the comma */
 	partlistlen++;
@@ -260,7 +254,7 @@ static int calc_parts_list_len(int numparts)
  * argument
  *
  * From doc/README.gpt, Format of partitions layout:
- *    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
  *	name=kernel,size=60MiB,uuid=...;"
  * The fields 'name' and 'size' are mandatory for every partition.
  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
@@ -275,11 +269,6 @@ static int create_gpt_partitions_list(int numparts, const char *guid, char *part
 	if (!partitions_list)
 		return -1;
 
-	/*
-	 * README.gpt specifies starting with "partitions=" like so:
-	 *      strcpy(partitions_list, "partitions=uuid_disk=");
-	 * but that breaks extract_val, which doesn't skip over 'partitions='.
-	 */
 	strcpy(partitions_list, "uuid_disk=");
 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
 	strcat(partitions_list, ";");
diff --git a/doc/README.gpt b/doc/README.gpt
index e29b188..754e490 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -255,7 +255,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation
  2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
                             ` (4 preceding siblings ...)
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 5/5] GPT: fix error in partitions string doc alison at peloton-tech.com
@ 2017-06-03 11:48           ` Lukasz Majewski
  5 siblings, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-06-03 11:48 UTC (permalink / raw)
  To: u-boot

On Fri,  2 Jun 2017 19:22:29 -0700
alison at peloton-tech.com wrote:

> Significant changes since v2:
> -- Got rid of the need to allocate memory for the GUID string in
>    do_gpt();
> -- Fixed the problems with string NULL termination in
>    allocate_disk_part();
> -- Removed duplicate definition of MAX_SEARCH_PARTITIONS from
>    disk/part.c and increased the value in include/part.h to 64;
> -- Improved the commit message for "rename GPT partitions to detect
>    boot failure" to better describe the version of the patch I
>    submitted;
> -- Fixed numerous small problems with function return values.

Just informative - (no need to resend patches) - for next submissions -
please add changelog to each relevant patch.

In this way one can quickly refer to the code.


Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 2/5] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 2/5] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
@ 2017-06-03 11:52             ` Lukasz Majewski
  0 siblings, 0 replies; 116+ messages in thread
From: Lukasz Majewski @ 2017-06-03 11:52 UTC (permalink / raw)
  To: u-boot

Hi Alison,

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd
> directory can find it.  At the same time, increase the value to
> 64 since some operating systems use many, and the resources
> consumed by a larger value are minimal.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  disk/part.c    | 1 -
>  include/part.h | 1 +
>  2 files changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/disk/part.c b/disk/part.c
> index 491b02d..e640a55 100644
> --- a/disk/part.c
> +++ b/disk/part.c
> @@ -388,7 +388,6 @@ cleanup:
>  
>  #define PART_UNSPECIFIED -2
>  #define PART_AUTO -1
> -#define MAX_SEARCH_PARTITIONS 16
>  int blk_get_device_part_str(const char *ifname, const char
> *dev_part_str, struct blk_desc **dev_desc,
>  			     disk_partition_t *info, int
> allow_whole_dev) diff --git a/include/part.h b/include/part.h
> index 16c4a46..c41aa6a 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -49,6 +49,7 @@ struct block_drvr {
>  
>  #define PART_NAME_LEN 32
>  #define PART_TYPE_LEN 32
> +#define MAX_SEARCH_PARTITIONS 64
>  
>  typedef struct disk_partition {
>  	lbaint_t	start;	/* # of first block in
> partition	*/

Reviewed-by: Lukasz Majewski <lukma@denx.de>


Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation
  2017-05-31  8:12       ` Lukasz Majewski
  2017-06-01  7:04         ` Chaiken, Alison
@ 2017-06-04 22:11         ` alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 1/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
                             ` (4 more replies)
  2017-08-27 23:02         ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure Chaiken, Alison
  2 siblings, 5 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-04 22:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

One way for userspace and the bootloader to exchange information about
dynamic image selection is via the storage device partition table, as
described at

https://source.android.com/devices/tech/ota/ab_updates

The scheme described there relies on setting partitions' "boot" flag.
When no partition on a device is bootable since the kernel and U-Boot
are stored elsewhere, the name field in the GPT partition table offers
another logical place to store information.  These patches allow users
to easily modify GPT partition names via bootscripts that can select
different images based on a boot-failure counter, or when userspace
installs a software update.

These patches have been tested in the u-boot sandbox and (re)tested on
a TI DRA7xx-based SOM with U-Boot 2015.07.

Significant changes since v3:
-- Testing in sandbox showed error in NULL termination of UUID string
   in cmd/gpt.c.  That problem is fixed in
   0001-GPT-read-partition-table-from-device-into-a-data-str.patch.
-- Patch 3 "GPT: fix error in partitions string doc" now only treats
   the topic in the commit title, as the part dealing with the
   proposed 'flip' feature is moved to that patch.
-- Two new commits come from testing in the sandbox (of which I was
   previously unaware).   One fixes an error in README.sandbox, and
   one adds a few comments about sandbox testing to README.gpt.

Significant changes since v2:
-- Got rid of the need to allocate memory for the GUID string in
   do_gpt();
-- Fixed the problems with string NULL termination in
   allocate_disk_part();
-- Removed duplicate definition of MAX_SEARCH_PARTITIONS from
   disk/part.c and increased the value in include/part.h to 64;
-- Improved the commit message for "rename GPT partitions to detect
   boot failure" to better describe the version of the patch I
   submitted;
-- Fixed numerous small problems with function return values.

Significant changes since v1:
-- Put the gpt_flip() function and auxiliary ones inside a new
   CONFIG_CMD_GPT_FLIP option that depends on CMD_GPT.
-- Replace intentional overwriting of name and type string arrays with
   memset() instead.
-- Move part.h changes earlier in the patchset.
-- Add a few lines to README.gpt about the new gpt subcommands.

Added a few simple patches to do the following:
-- Replace remaining occurrences of '37' with UUID_STR_LEN+1;
-- Introduce new macros to get rid of the similar '32';
-- fix a smaller error in doc/README.gpt.

There are also some fixups of whitespace and formatting errors (plus
usual inevitable addition of new ones).

To do in future:
-- Add support for preserving the type flag for partitions. The u-boot
   version on which this patchset is based did not have this feature,
   and it's easy to add, but I need to figure how to test it first.

-- Add tests for the new gpt commands to the sandbox.

Alison Chaiken (5):
  GPT: read partition table from device into a data structure
  rename GPT partitions to detect boot failure
  GPT: fix error in partitions string doc
  sandbox: README: fix partition command invocation
  cmd gpt: test in sandbox

 board/sandbox/README.sandbox |   2 +-
 cmd/Kconfig                  |   7 +
 cmd/gpt.c                    | 298 +++++++++++++++++++++++++++++++++++++++++++
 doc/README.gpt               |  31 ++++-
 include/part.h               |   7 +
 5 files changed, 340 insertions(+), 5 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v4 1/5] GPT: read partition table from device into a data structure
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
@ 2017-06-04 22:11           ` alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 2/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-04 22:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Changes since v3:
Fixed problem with NULL termination of the newly created uuid[]
member of the partitions list in allocate_disk_part.   This
version has been tested in the u-boot sandbox.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 123 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 4d00a35..e898f35 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,115 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part) && valid_parts >= 2)
+			return -ENODEV;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		del_gpt_info();
+		return -ENODEV;
+	}
+	return --valid_parts;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +567,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		return do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		return do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +591,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index c41aa6a..0cd803a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v4 2/5] rename GPT partitions to detect boot failure
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 1/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-06-04 22:11           ` alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 3/5] GPT: fix error in partitions string doc alison at peloton-tech.com
                             ` (2 subsequent siblings)
  4 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-04 22:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via a new 'gpt flip'
command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
   to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
   ‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
   it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Changes since v3:
-- Squashed changes to comments that had been made in a different
   patch into this one.
-- Fixed lines over 80 chars.
-- Tested in u-boot sandbox.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   7 +++
 cmd/gpt.c      | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 206 insertions(+), 4 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6f75b86..8b925e5 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index e898f35..f806492 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +195,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +233,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
+	partlistlen += numparts * (strlen("start=MiB,") + 17);
+	partlistlen += numparts * (strlen("size=MiB,") + 17);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +312,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -298,6 +387,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -527,6 +618,88 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -569,6 +742,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		return do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		return do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		return do_flip_gpt_parts(blk_dev_desc);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -600,4 +777,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_FLIP
+	"gpt partition-flip command\n"
+	"gpt flip <interface> <dev>\n"
+	"    - exchange device's 'primary' and 'backup' partition names\n"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index c0779a4..e29b188 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v4 3/5] GPT: fix error in partitions string doc
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 1/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 2/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-06-04 22:11           ` alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation alison at peloton-tech.com
  2017-06-04 22:11           ` [U-Boot] [PATCH 5/5] cmd gpt: test in sandbox alison at peloton-tech.com
  4 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-04 22:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

The existing partitions-list parsing in cmd/gpt.c passes a value
from gpt_default() to set_gpt_info() that README.gpt suggests
should begin with 'partitions='.  Partition-list strings should
in fact begin with 'uuid_disk', as otherwise the call from
set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
Change README.gpt accordingly.

Changes since v3:
-- The part of this patch dealing with the partition-flipping
   behavior was squashed into the patch that introduces that
   feature.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 doc/README.gpt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/doc/README.gpt b/doc/README.gpt
index e29b188..754e490 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -233,7 +233,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -255,7 +255,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
                             ` (2 preceding siblings ...)
  2017-06-04 22:11           ` [U-Boot] [PATCH v4 3/5] GPT: fix error in partitions string doc alison at peloton-tech.com
@ 2017-06-04 22:11           ` alison at peloton-tech.com
  2017-06-09 12:28             ` Simon Glass
  2017-06-04 22:11           ` [U-Boot] [PATCH 5/5] cmd gpt: test in sandbox alison at peloton-tech.com
  4 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-04 22:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

The instructions for creating a disk image that are presently in
README.sandbox fail because sfdisk doesn't know about GPT.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 board/sandbox/README.sandbox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox
index 02d8ab3..9dc2eb0 100644
--- a/board/sandbox/README.sandbox
+++ b/board/sandbox/README.sandbox
@@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image
 A disk image can be created using the following commands:
 
 $> truncate -s 1200M ./disk.raw
-$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk  ./disk.raw
+$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk  ./disk.raw
 $> lodev=`sudo losetup -P -f --show ./disk.raw`
 $> sudo mkfs.vfat -n EFI -v ${lodev}p1
 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 5/5] cmd gpt: test in sandbox
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
                             ` (3 preceding siblings ...)
  2017-06-04 22:11           ` [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation alison at peloton-tech.com
@ 2017-06-04 22:11           ` alison at peloton-tech.com
  2017-06-15 19:21             ` sjg at google.com
  4 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-04 22:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make minor changes to README.gpt and sandbox_defconfig to support
testing of the gpt command's functionality in the sandbox.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 doc/README.gpt | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/doc/README.gpt b/doc/README.gpt
index 754e490..7b3936b 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -224,6 +224,16 @@ U-BOOT> gpt flip mmc 0
 
 Choose different partition names by modifying these strings in gpt.c.
 
+The GPT functionality may be tested with the 'sandbox' board by
+creating a disk image as described under 'Block Device Emulation' in
+board/sandbox/README.sandbox:
+
+=>host bind 0 ./disk.raw
+=> gpt read host 0
+[ . . . ]
+=> gpt flip host 0
+[ . . . ]
+
 Partition type GUID:
 ====================
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-06-06  8:20             ` Lothar Waßmann
  2017-06-10  5:27               ` [U-Boot] [PATCH v5 1/3] " alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-06  8:20 UTC (permalink / raw)
  To: u-boot

Hi,

On Fri,  2 Jun 2017 19:22:30 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> In order to read the GPT, modify the partition name strings, and then
> write out a new GPT, the disk GUID is needed.  While there is an
> existing accessor for the partition UUIDs, there is none yet for the
> disk GUID.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c       | 26 ++++++++++++++++++++++++++
>  disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
>  doc/README.gpt  |  3 ++-
>  include/part.h  | 15 +++++++++++++++
>  4 files changed, 74 insertions(+), 1 deletion(-)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 3e98821..4d00a35 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
>  	return ret;
>  }
>  
> +static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
> +{
> +	int ret;
> +	char disk_guid[UUID_STR_LEN + 1];
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return CMD_RET_FAILURE;
> +
> +	if (namestr)
> +		setenv(namestr, disk_guid);
> +	else
> +		printf("%s\n", disk_guid);
> +
> +	return ret;
>
For consistency this should be:
	return CMD_RET_SUCCESS;
but see below.

>  /**
>   * do_gpt(): Perform GPT operations
>   *
> @@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  	} else if ((strcmp(argv[1], "verify") == 0)) {
>  		ret = gpt_verify(blk_dev_desc, argv[4]);
>  		printf("Verify GPT: ");
> +	} else if (strcmp(argv[1], "guid") == 0) {
> +		return do_disk_guid(blk_dev_desc, argv[4]);
>  	} else {
>  		return CMD_RET_USAGE;
>  	}
IMO you should use the existing error handling infrastructure lateron
in this file and just assign the return value of the subcommand
handlers to 'ret' and let the existing code sort out the return code of
this function (just like the gpt_verify() call above does it).



Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 4/5] rename GPT partitions to detect boot failure
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 4/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
@ 2017-06-06  8:20             ` Lothar Waßmann
  2017-06-10  5:35               ` [U-Boot] [PATCH v5 3/3] " alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-06  8:20 UTC (permalink / raw)
  To: u-boot

Hi,

On Fri,  2 Jun 2017 19:22:33 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via a new 'gpt flip'
> command.
> 
> The concept for the bootloader state machine is the following:
> 
> -- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
>    to boot them.
> -- Linux, at boot, will rename ‘candidate’ partitions as
>    ‘primary’.
> -- If u-boot sees a ‘candidate’ partition after a boot attempt,
>    it tries to boot the ‘backup’ partition.
> 
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/Kconfig    |   7 ++
>  cmd/gpt.c      | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  doc/README.gpt |  13 ++++
>  3 files changed, 215 insertions(+), 4 deletions(-)
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 6f75b86..8b925e5 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -593,6 +593,13 @@ config CMD_GPT
>  	  Enable the 'gpt' command to ready and write GPT style partition
>  	  tables.
>  
> +config CMD_GPT_FLIP
> +	bool "GPT flip-partitions command"
> +	depends on CMD_GPT
> +	help
> +	  Enables the 'gpt' command to write modified GPT partition
> +	  tables via the 'gpt flip' command.
> +
>  config CMD_ARMFLASH
>  	#depends on FLASH_CFI_DRIVER
>  	bool "armflash"
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 5c2651f..f6968de 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -20,6 +20,7 @@
>  #include <div64.h>
>  #include <memalign.h>
>  #include <linux/compat.h>
> +#include <linux/sizes.h>
>  
>  static LIST_HEAD(disk_partitions);
>  
> @@ -190,16 +191,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
>  	return newpart;
>  }
>  
> +static void prettyprint_part_size(char *sizestr, unsigned long partsize,
> +				  unsigned long blksize)
> +{
> +	unsigned long long partbytes;
> +	unsigned long partmegabytes;
> +
> +	partbytes = partsize * blksize;
> +	partmegabytes = lldiv(partbytes, SZ_1M);
> +	snprintf(sizestr, 16, "%luMiB", partmegabytes);
> +}
> +
>  static void print_gpt_info(void)
>  {
>  	struct list_head *pos;
>  	struct disk_part *curr;
> +	char partstartstr[16];
> +	char partsizestr[16];
>  
>  	list_for_each(pos, &disk_partitions) {
>  		curr = list_entry(pos, struct disk_part, list);
> +		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +
>  		printf("Partition %d:\n", curr->partnum);
> -		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> -		       (unsigned)curr->gpt_part_info.size);
> +		printf("Start %s, size %s\n", partstartstr, partsizestr);
>  		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
>  		       curr->gpt_part_info.name);
>  		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> @@ -211,6 +229,85 @@ static void print_gpt_info(void)
>  	}
>  }
>  
> +#ifdef CONFIG_CMD_GPT_FLIP
> +static int calc_parts_list_len(int numparts)
> +{
> +	/*
> +	 * prefatory string:
> +	 * doc/README.GPT, suggests that
> +	 * int partlistlen = UUID_STR_LEN + 1 + strlen("partitions=uuid_disk=");
> +	 * is correct, but extract_val() expects "uuid_disk" first.
> +	 */
> +	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> +	/* for the comma */
> +	partlistlen++;
> +
> +	/* per-partition additions; numparts starts at 1, so this should be correct */
> +	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
> +	/* 17 because partstr in create_gpt_partitions_list() is 16 chars */
>
NO! The size of partstr in create_gpt_partitions_list() is:
|	char partstr[PART_NAME_LEN + 1];
which happens to be defined as:
--- a/include/part.h
+++ b/include/part.h
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
                       ^^
 #define PART_TYPE_LEN 32

> +	partlistlen += numparts * (strlen("start=MiB,") + 17);
> +	partlistlen += numparts * (strlen("size=MiB,") + 17);
>
Never use magic numbers in code, but use appropriate #define's!

> @@ -523,6 +625,86 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
>  	return ret;
>  }
>  
> +#ifdef CONFIG_CMD_GPT_FLIP
> +static int do_flip_gpt_parts(struct blk_desc *dev_desc)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	disk_partition_t *new_partitions = NULL;
> +	char disk_guid[UUID_STR_LEN + 1];
> +	char *partitions_list, *str_disk_guid;
> +	u8 part_count = 0;
> +	int partlistlen, ret, numparts = 0;
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return ret;
AGAIN: You are passing the return value of this function back to the
caller of the CMD handler do_gpt() which expects a return value of
CMD_RET_FAILURE or CMD_RET_SUCCESS, not an arbitrary negative value.

> +
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
> +	printf("Current partition table with %d partitions is:\n", numparts);
> +	print_gpt_info();
> +
> +	partlistlen = calc_parts_list_len(numparts);
> +	partitions_list = (char *)malloc(partlistlen);
> +	memset(partitions_list, '\0', partlistlen);
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
> +					 partitions_list);
> +	if (ret < 0)
> +		return ret;
> +	debug("OLD partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
> +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
> +			   &new_partitions, &part_count);
> +	if (ret < 0)
> +		return ret;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
> +			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
> +		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
> +			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
> +		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
> +			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
> +		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
> +			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
> +	}
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
> +	if (ret < 0)
> +		return ret;
> +	debug("NEW partitions_list is %s with %d chars\n", partitions_list, strlen(partitions_list));
> +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
> +			   &new_partitions, &part_count);
> +	if (ret < 0)
> +		return ret;
> +
> +	debug("Writing new partition table\n");
> +	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
> +	if (ret < 0) {
> +		printf("Writing new partition table failed\n");
> +		return ret;
> +	}
> +
> +	debug("Reading back new partition table\n");
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <  0)
> +		return numparts;
> +	printf("new partition table with %d partitions is:\n", numparts);
> +	print_gpt_info();
> +
> +	del_gpt_info();
> +	free(partitions_list);
> +	free(str_disk_guid);
> +	free(new_partitions);
> +	return ret;
> +}
> +#endif
> +
>  /**
>   * do_gpt(): Perform GPT operations
>   *
> @@ -565,6 +747,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  		return do_disk_guid(blk_dev_desc, argv[4]);
>  	} else if (strcmp(argv[1], "read") == 0) {
>  		return do_get_gpt_info(blk_dev_desc);
> +#ifdef CONFIG_CMD_GPT_FLIP
> +	} else if (strcmp(argv[1], "flip") == 0) {
> +		return do_flip_gpt_parts(blk_dev_desc);
> +#endif
>
See my comment to your patch 1/5.


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-06-06  8:28             ` Lothar Waßmann
  2017-06-10  5:30               ` [U-Boot] [PATCH v5 2/3] " alison at peloton-tech.com
  2017-06-06 10:43             ` [U-Boot] [PATCH v3 3/5] " Lothar Waßmann
  1 sibling, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-06  8:28 UTC (permalink / raw)
  To: u-boot

Hi,

On Fri,  2 Jun 2017 19:22:32 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/part.h |   7 ++++
>  2 files changed, 119 insertions(+)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 4d00a35..5c2651f 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -19,6 +19,9 @@
>  #include <linux/ctype.h>
>  #include <div64.h>
>  #include <memalign.h>
> +#include <linux/compat.h>
> +
> +static LIST_HEAD(disk_partitions);
>  
>  /**
>   * extract_env(): Expand env name from string format '&{env_name}'
> @@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
>  	return result;
>  }
>  
> +static void del_gpt_info(void)
> +{
> +	struct list_head *pos = &disk_partitions;
> +	struct disk_part *curr;
> +	while (!list_empty(pos)) {
> +		curr = list_entry(pos->next, struct disk_part, list);
> +		list_del(pos->next);
> +		free(curr);
> +	}
> +}
> +
> +static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
> +{
> +	struct disk_part *newpart;
> +	newpart = (struct disk_part *)malloc(sizeof(*newpart));
> +	if (!newpart)
> +		return ERR_PTR(-ENOMEM);
> +	memset(newpart, '\0', sizeof(newpart));
> +
> +	newpart->gpt_part_info.start = info->start;
> +	newpart->gpt_part_info.size = info->size;
> +	newpart->gpt_part_info.blksz = info->blksz;
> +	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
> +	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
> +	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
> +	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
> +	newpart->gpt_part_info.bootable = info->bootable;
> +#ifdef CONFIG_PARTITION_UUIDS
> +	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
> +		UUID_STR_LEN);
> +#endif
> +	newpart->partnum = partnum;
> +
> +	return newpart;
> +}
> +
> +static void print_gpt_info(void)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		printf("Partition %d:\n", curr->partnum);
> +		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> +		       (unsigned)curr->gpt_part_info.size);
> +		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
> +		       curr->gpt_part_info.name);
> +		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> +		       curr->gpt_part_info.bootable);
> +#ifdef CONFIG_PARTITION_UUIDS
> +		printf("UUID %s\n", curr->gpt_part_info.uuid);
> +#endif
> +		printf("\n");
> +	}
> +}
> +
> +/*
> + * read partition info into disk_partitions list where
> + * it can be printed or modified
> + */
> +static int get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	/* start partition numbering at 1, as U-Boot does */
> +	int valid_parts = 1, p, ret;
> +	disk_partition_t info;
> +	struct disk_part *new_disk_part;
> +
> +	if (disk_partitions.next == NULL)
> +		INIT_LIST_HEAD(&disk_partitions);
> +
> +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> +		ret = part_get_info(dev_desc, p, &info);
> +		if (ret)
> +			continue;
> +
> +		new_disk_part = allocate_disk_part(&info, valid_parts);
> +		if (IS_ERR(new_disk_part) && valid_parts >= 2)
> +			return -ENODEV;
>
del_gpt_info()? This calls for a common error exit which does the
cleanup.

> +
> +		list_add_tail(&new_disk_part->list, &disk_partitions);
> +		valid_parts++;
> +	}
> +	if (!valid_parts) {
> +		printf("** No valid partitions found **\n");
> +		del_gpt_info();
> +		return -ENODEV;
> +	}
> +	return --valid_parts;
> +}
> +


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure
  2017-06-03  2:22           ` [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
  2017-06-06  8:28             ` Lothar Waßmann
@ 2017-06-06 10:43             ` Lothar Waßmann
  1 sibling, 0 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-06 10:43 UTC (permalink / raw)
  To: u-boot

Hi,

On Fri,  2 Jun 2017 19:22:32 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c      | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/part.h |   7 ++++
>  2 files changed, 119 insertions(+)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 4d00a35..5c2651f 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -19,6 +19,9 @@
>  #include <linux/ctype.h>
>  #include <div64.h>
>  #include <memalign.h>
> +#include <linux/compat.h>
> +
> +static LIST_HEAD(disk_partitions);
>  
>  /**
>   * extract_env(): Expand env name from string format '&{env_name}'
> @@ -151,6 +154,111 @@ static bool found_key(const char *str, const char *key)
>  	return result;
>  }
>  
> +static void del_gpt_info(void)
> +{
> +	struct list_head *pos = &disk_partitions;
> +	struct disk_part *curr;
> +	while (!list_empty(pos)) {
> +		curr = list_entry(pos->next, struct disk_part, list);
> +		list_del(pos->next);
> +		free(curr);
> +	}
> +}
> +
> +static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
> +{
> +	struct disk_part *newpart;
> +	newpart = (struct disk_part *)malloc(sizeof(*newpart));
> +	if (!newpart)
> +		return ERR_PTR(-ENOMEM);
> +	memset(newpart, '\0', sizeof(newpart));
> +
> +	newpart->gpt_part_info.start = info->start;
> +	newpart->gpt_part_info.size = info->size;
> +	newpart->gpt_part_info.blksz = info->blksz;
> +	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name, PART_NAME_LEN);
> +	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
> +	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type, PART_TYPE_LEN);
> +	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
> +	newpart->gpt_part_info.bootable = info->bootable;
> +#ifdef CONFIG_PARTITION_UUIDS
> +	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
> +		UUID_STR_LEN);
> +#endif
> +	newpart->partnum = partnum;
> +
> +	return newpart;
> +}
> +
> +static void print_gpt_info(void)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		printf("Partition %d:\n", curr->partnum);
> +		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> +		       (unsigned)curr->gpt_part_info.size);
> +		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
> +		       curr->gpt_part_info.name);
> +		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> +		       curr->gpt_part_info.bootable);
> +#ifdef CONFIG_PARTITION_UUIDS
> +		printf("UUID %s\n", curr->gpt_part_info.uuid);
> +#endif
> +		printf("\n");
> +	}
> +}
> +
> +/*
> + * read partition info into disk_partitions list where
> + * it can be printed or modified
> + */
> +static int get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	/* start partition numbering at 1, as U-Boot does */
> +	int valid_parts = 1, p, ret;
> +	disk_partition_t info;
> +	struct disk_part *new_disk_part;
> +
> +	if (disk_partitions.next == NULL)
> +		INIT_LIST_HEAD(&disk_partitions);
> +
> +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> +		ret = part_get_info(dev_desc, p, &info);
> +		if (ret)
> +			continue;
> +
> +		new_disk_part = allocate_disk_part(&info, valid_parts);
> +		if (IS_ERR(new_disk_part) && valid_parts >= 2)
> +			return -ENODEV;
> +
> +		list_add_tail(&new_disk_part->list, &disk_partitions);
> +		valid_parts++;
> +	}
> +	if (!valid_parts) {
> +		printf("** No valid partitions found **\n");
> +		del_gpt_info();
> +		return -ENODEV;
> +	}
> +	return --valid_parts;
> +}
> +
> +/* a wrapper to test get_gpt_info */
> +static int do_get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	int ret;
> +
> +	ret = get_gpt_info(dev_desc);
> +	if (ret > 0) {
> +		print_gpt_info();
> +		del_gpt_info();
> +	}
> +	return ret;
> +}
> +
> +
>  /**
>   * set_gpt_info(): Fill partition information from string
>   *		function allocates memory, remember to free!
> @@ -455,6 +563,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  		printf("Verify GPT: ");
>  	} else if (strcmp(argv[1], "guid") == 0) {
>  		return do_disk_guid(blk_dev_desc, argv[4]);
> +	} else if (strcmp(argv[1], "read") == 0) {
> +		return do_get_gpt_info(blk_dev_desc);
>
See my comment to your patch 1/5

>  	} else {
>  		return CMD_RET_USAGE;
>  	}

> @@ -477,6 +587,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt write mmc 0 $partitions\n"
>  	" gpt verify mmc 0 $partitions\n"
> +	" read <interface> <dev>\n"
> +	"    - read GPT into a data structure for manipulation\n"
>  	" guid <interface> <dev>\n"
>  	"    - print disk GUID\n"
>  	" guid <interface> <dev> <varname>\n"
> diff --git a/include/part.h b/include/part.h
> index c41aa6a..0cd803a 100644
> --- a/include/part.h
> +++ b/include/part.h
> @@ -10,6 +10,7 @@
>  #include <blk.h>
>  #include <ide.h>
>  #include <uuid.h>
> +#include <linux/list.h>
>  
>  struct block_drvr {
>  	char *name;
> @@ -69,6 +70,12 @@ typedef struct disk_partition {
>  #endif
>  } disk_partition_t;
>  
> +struct disk_part {
> +	int partnum;
> +	disk_partition_t gpt_part_info;
> +	struct list_head list;
> +};
> +
>  /* Misc _get_dev functions */
>  #ifdef CONFIG_PARTITIONS
>  /**


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation
  2017-06-04 22:11           ` [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation alison at peloton-tech.com
@ 2017-06-09 12:28             ` Simon Glass
  2017-06-15 19:21               ` sjg at google.com
  0 siblings, 1 reply; 116+ messages in thread
From: Simon Glass @ 2017-06-09 12:28 UTC (permalink / raw)
  To: u-boot

On 4 June 2017 at 16:11,  <alison@peloton-tech.com> wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
>
> The instructions for creating a disk image that are presently in
> README.sandbox fail because sfdisk doesn't know about GPT.
>
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  board/sandbox/README.sandbox | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox
> index 02d8ab3..9dc2eb0 100644
> --- a/board/sandbox/README.sandbox
> +++ b/board/sandbox/README.sandbox
> @@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image
>  A disk image can be created using the following commands:
>
>  $> truncate -s 1200M ./disk.raw
> -$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk  ./disk.raw
> +$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk  ./disk.raw
>  $> lodev=`sudo losetup -P -f --show ./disk.raw`
>  $> sudo mkfs.vfat -n EFI -v ${lodev}p1
>  $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2

Reviewed-by: Simon Glass <sjg@chromium.org>
Tested on Ubuntu 14.04 (with tools in /sbin):
Tested-by: Simon Glass <sjg@chromium.org>

> --
> 2.1.4
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 1/3] GPT: add accessor function for disk GUID
  2017-06-06  8:20             ` Lothar Waßmann
@ 2017-06-10  5:27               ` alison at peloton-tech.com
  2017-06-11 13:38                 ` Tom Rini
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-10  5:27 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

In order to read the GPT, modify the partition name strings, and then
write out a new GPT, the disk GUID is needed.  While there is an
existing accessor for the partition UUIDs, there is none yet for the
disk GUID.

Changes since v4:
-- Made do_disk_guid() return 0 upon success so that now, in the
   sandbox, u-boot prints a "success!" exit message.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 3e98821..65fb80b 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +477,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 20d33ef..71c3cb3 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -EINVAL;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = gpt_head->disk_guid.b;
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
diff --git a/doc/README.gpt b/doc/README.gpt
index 3fcd835..c0779a4 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
diff --git a/include/part.h b/include/part.h
index 87b1111..16c4a46 100644
--- a/include/part.h
+++ b/include/part.h
@@ -371,6 +371,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 2/3] GPT: read partition table from device into a data structure
  2017-06-06  8:28             ` Lothar Waßmann
@ 2017-06-10  5:30               ` alison at peloton-tech.com
  2017-06-11 13:38                 ` Tom Rini
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-10  5:30 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Changes since v4:
-- Made do_get_gpt_info() return 0 upon success so that now, in the
   sandbox, u-boot prints a "success!" exit message.
-- Created a single exit point for get_gpt_info(), with the
   result that after an error, del_gpt_info() always removes the
   list.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 127 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 65fb80b..669031f8 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,119 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = (struct disk_part *)malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;
+ out:
+	if (valid_parts >= 2)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +571,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +595,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index c41aa6a..0cd803a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 3/3] rename GPT partitions to detect boot failure
  2017-06-06  8:20             ` Lothar Waßmann
@ 2017-06-10  5:35               ` alison at peloton-tech.com
  2017-06-10  6:51                 ` Wolfgang Denk
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-10  5:35 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@she-devel.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via a new 'gpt flip'
command.

The concept for the bootloader state machine is the following:

-- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
   to boot them.
-- Linux, at boot, will rename ‘candidate’ partitions as
   ‘primary’.
-- If u-boot sees a ‘candidate’ partition after a boot attempt,
   it tries to boot the ‘backup’ partition.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Changes since v4:
-- Changed the erroneous '17' values in calc_parts_list_len() to
   match the definition of struct disk_partition in part.h.
-- Modified do_gpt() so that the 'gpt flip' command prints
   "success!" or "error!" on exit.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   7 +++
 cmd/gpt.c      | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  13 ++++
 3 files changed, 206 insertions(+), 4 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 270cff6..880ca97 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -593,6 +593,13 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_FLIP
+	bool "GPT flip-partitions command"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to write modified GPT partition
+	  tables via the 'gpt flip' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 669031f8..ad7c7ec 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,7 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +195,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +233,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +312,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -302,6 +391,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -531,6 +622,88 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_FLIP
+static int do_flip_gpt_parts(struct blk_desc *dev_desc)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("Current partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_kernel"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_kernel");
+		if (!strcmp((char *)curr->gpt_part_info.name, "backup_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "candidate_rootfs");
+		if (!strcmp((char *)curr->gpt_part_info.name, "primary_rootfs"))
+			strcpy((char *)curr->gpt_part_info.name, "backup_rootfs");
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -573,6 +746,10 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_FLIP
+	} else if (strcmp(argv[1], "flip") == 0) {
+		ret = do_flip_gpt_parts(blk_dev_desc);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -604,4 +781,9 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_FLIP
+	"gpt partition-flip command\n"
+	"gpt flip <interface> <dev>\n"
+	"    - exchange device's 'primary' and 'backup' partition names\n"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index c0779a4..e29b188 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,19 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read' and 'gpt flip' commands facilitate programmatic renaming of
+partitions from bootscripts by generating and modifying the partitions
+layout string.  The code in gpt_flip() illustrates the case of
+swapping 'primary' and 'backup' partitions via:
+
+U-BOOT> gpt flip mmc 0
+
+Choose different partition names by modifying these strings in gpt.c.
 
 Partition type GUID:
 ====================
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 3/3] rename GPT partitions to detect boot failure
  2017-06-10  5:35               ` [U-Boot] [PATCH v5 3/3] " alison at peloton-tech.com
@ 2017-06-10  6:51                 ` Wolfgang Denk
  2017-06-10 23:27                   ` Alison Chaiken
  2017-06-10 23:33                   ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
  0 siblings, 2 replies; 116+ messages in thread
From: Wolfgang Denk @ 2017-06-10  6:51 UTC (permalink / raw)
  To: u-boot

Dear Alison,

In message <1497072917-16614-1-git-send-email-alison@peloton-tech.com> you wrote:
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via a new 'gpt flip'
> command.
> 
> The concept for the bootloader state machine is the following:
> 
> -- u-boot renames ‘primary’ partitions as ‘candidate’ and tries
>    to boot them.
> -- Linux, at boot, will rename ‘candidate’ partitions as
>    ‘primary’.
> -- If u-boot sees a ‘candidate’ partition after a boot attempt,
>    it tries to boot the ‘backup’ partition.

I think you are talking about two parts here, and I strongly feel
these should be kept separate.

The first part is support for renaming GPT partitions.  The idea is
clean, but should it not rather be kept general and let the user
provide the new name as argument, i. e. implement a generic
"gpt rename" command instead of a hard-wired "gpt flip"?

The second part is the flipping of the partition names.  This is in
my opinion policy, and should also not be hardwaired into this
command, but left to the user.  Maybe I do nmot want to fall back to
the ‘backup’ partition after a single boot attempt, but instead try
other things first, like booting another kernel or another device
tree blob?

I feel this should be not so much hardwired, but leave more freedom
for the user's creativity.

What do you think?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
...computer hardware progress is so fast. No other  technology  since
civilization  began  has seen six orders of magnitude in performance-
price gain in 30 years.                             - Fred Brooks, Jr.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 3/3] rename GPT partitions to detect boot failure
  2017-06-10  6:51                 ` Wolfgang Denk
@ 2017-06-10 23:27                   ` Alison Chaiken
  2017-06-10 23:33                   ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
  1 sibling, 0 replies; 116+ messages in thread
From: Alison Chaiken @ 2017-06-10 23:27 UTC (permalink / raw)
  To: u-boot

On Fri, Jun 9, 2017 at 11:51 PM, Wolfgang Denk <wd@denx.de> wrote:

> I think you are talking about two parts here, and I strongly feel
> these should be kept separate.
>
> The first part is support for renaming GPT partitions.  The idea is
> clean, but should it not rather be kept general and let the user
> provide the new name as argument, i. e. implement a generic
> "gpt rename" command instead of a hard-wired "gpt flip"?
>
> The second part is the flipping of the partition names.  This is in
> my opinion policy, and should also not be hardwaired into this
> command, but left to the user.  Maybe I do nmot want to fall back to
> the ‘backup’ partition after a single boot attempt, but instead try
> other things first, like booting another kernel or another device
> tree blob?
>
> I feel this should be not so much hardwired, but leave more freedom
> for the user's creativity.
>

Lukasz has already made similar suggestions.   In the following message is
a new version which attempts to implement them.

Thanks to Lothar and Lukasz for all their help.

Best wishes,
Alison Chaiken
Peloton Technology

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-10  6:51                 ` Wolfgang Denk
  2017-06-10 23:27                   ` Alison Chaiken
@ 2017-06-10 23:33                   ` alison at peloton-tech.com
  2017-06-11 13:38                     ` Tom Rini
  2017-06-12  7:45                     ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
  1 sibling, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-10 23:33 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via new 'gpt swap'
and 'gpt rename' commands.

The 'swap' mode prints a warning if no matching partition names
are found.  If only one matching name of a provided pair is found, it
renames the matching partitions to the new name.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Changes since v5:
-- The former 'gpt flip' is now 'gpt swap', which takes the two
   arbitrary partition names it exchanges as command-line input.
-- A new command, 'gpt rename', now allows renaming of single,
   specified partitions.
-- Updated README.gpt to reflect the changes.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 412bf24..7b262de 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 669031f8..aa3245a 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,9 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+
+extern int atoi(const char *nptr);
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +197,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +235,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +314,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -302,6 +393,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -531,6 +624,126 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	u8 part_count = 0;
+	int partlistlen, ret, numparts = 0, partnum, i = 1, changed = 0;
+
+	if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
+	    (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				changed++;
+			}
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				changed++;
+			}
+
+		}
+		if (changed == 0) {
+			printf("No matching partition names were found.\n");
+			return ret;
+		}
+	} else { /* rename */
+		if (strlen(name2) > PART_NAME_LEN) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+
+		partnum = atoi(name1);
+		if ((partnum < 0) || (partnum > numparts)) {
+			printf("Illegal partition number %s\n", name1);
+			return -EINVAL;
+		}
+		ret = part_get_info(dev_desc, partnum, new_partitions);
+		if (ret < 0)
+			return ret;
+
+		/* U-Boot partition numbering starts@1 */
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -548,7 +761,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
-	if (argc < 4 || argc > 5)
+	if (argc < 4 || argc > 6)
 		return CMD_RET_USAGE;
 
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -573,6 +786,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} 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]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -604,4 +822,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\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"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index 6c5ab78..d3db8bc 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-10 23:33                   ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
@ 2017-06-11 13:38                     ` Tom Rini
  2017-06-11 16:03                       ` [U-Boot] [PATCH v7] " alison at peloton-tech.com
  2017-06-12  7:45                     ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
  1 sibling, 1 reply; 116+ messages in thread
From: Tom Rini @ 2017-06-11 13:38 UTC (permalink / raw)
  To: u-boot

On Sat, Jun 10, 2017 at 04:33:37PM -0700, alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via new 'gpt swap'
> and 'gpt rename' commands.
> 
> The 'swap' mode prints a warning if no matching partition names
> are found.  If only one matching name of a provided pair is found, it
> renames the matching partitions to the new name.

So in the case where 'gpt swap partA partB' is used and partB doesn't
exist, it's the same as 'gpt rename partA partB' ?  That seems like it
might surprise users and I think if we changed:

> +	if (!strcmp(subcomm, "swap")) {
> +		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
> +			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
> +			return -EINVAL;
> +		}
> +		list_for_each(pos, &disk_partitions) {
> +			curr = list_entry(pos, struct disk_part, list);
> +			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
> +				strcpy((char *)curr->gpt_part_info.name, name2);
> +				changed++;
> +			}
> +			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
> +				strcpy((char *)curr->gpt_part_info.name, name1);
> +				changed++;
> +			}
> +
> +		}
> +		if (changed == 0) {
> +			printf("No matching partition names were found.\n");
> +			return ret;
> +		}

We could also test for if changed == 1 and return an error.  I assume
that a GPT with the same name used more than one time is already
invalid, but we could be defensive here and test for != 2 instead.
Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170611/fefff049/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 1/3] GPT: add accessor function for disk GUID
  2017-06-10  5:27               ` [U-Boot] [PATCH v5 1/3] " alison at peloton-tech.com
@ 2017-06-11 13:38                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-06-11 13:38 UTC (permalink / raw)
  To: u-boot

On Fri, Jun 09, 2017 at 10:27:40PM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> In order to read the GPT, modify the partition name strings, and then
> write out a new GPT, the disk GUID is needed.  While there is an
> existing accessor for the partition UUIDs, there is none yet for the
> disk GUID.
> 
> Changes since v4:
> -- Made do_disk_guid() return 0 upon success so that now, in the
>    sandbox, u-boot prints a "success!" exit message.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Reviewed-by: Tom Rini <trini@konsulko.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170611/67a2326e/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v5 2/3] GPT: read partition table from device into a data structure
  2017-06-10  5:30               ` [U-Boot] [PATCH v5 2/3] " alison at peloton-tech.com
@ 2017-06-11 13:38                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-06-11 13:38 UTC (permalink / raw)
  To: u-boot

On Fri, Jun 09, 2017 at 10:30:39PM -0700, alison at peloton-tech.com wrote:

> From: Alison Chaiken <alison@she-devel.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Changes since v4:
> -- Made do_get_gpt_info() return 0 upon success so that now, in the
>    sandbox, u-boot prints a "success!" exit message.
> -- Created a single exit point for get_gpt_info(), with the
>    result that after an error, del_gpt_info() always removes the
>    list.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Reviewed-by: Tom Rini <trini@konsulko.com>

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170611/99ef27ba/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7] GPT: provide commands to selectively rename partitions
  2017-06-11 13:38                     ` Tom Rini
@ 2017-06-11 16:03                       ` alison at peloton-tech.com
  0 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-11 16:03 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via new 'gpt swap'
and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names
are found, or if the number of partitions with one name does not equal
the number with the second name.   The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 258 insertions(+), 6 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 412bf24..7b262de 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 669031f8..b0c9623 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,9 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+
+extern int atoi(const char *nptr);
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +197,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +235,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -1;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +314,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -302,6 +393,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -531,6 +624,123 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	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"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = (char *)malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				ctr1++;
+			}
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				ctr2++;
+			}
+		}
+		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
+			printf("Cannot swap partition names except in pairs.\n");
+			return -EINVAL;
+		}
+	} else { /* rename */
+		if (strlen(name2) > PART_NAME_LEN) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		partnum = atoi(name1);
+		if ((partnum < 0) || (partnum > numparts)) {
+			printf("Illegal partition number %s\n", name1);
+			return -EINVAL;
+		}
+		ret = part_get_info(dev_desc, partnum, new_partitions);
+		if (ret < 0)
+			return ret;
+
+		/* U-Boot partition numbering starts@1 */
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <  0)
+		return numparts;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -548,7 +758,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
-	if (argc < 4 || argc > 5)
+	if (argc < 4 || argc > 6)
 		return CMD_RET_USAGE;
 
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -573,6 +783,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} 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]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -604,4 +819,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\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"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index 6c5ab78..d3db8bc 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-10 23:33                   ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
  2017-06-11 13:38                     ` Tom Rini
@ 2017-06-12  7:45                     ` Wolfgang Denk
  2017-06-12 14:24                       ` Alison Chaiken
  1 sibling, 1 reply; 116+ messages in thread
From: Wolfgang Denk @ 2017-06-12  7:45 UTC (permalink / raw)
  To: u-boot

Dear Alison,

In message <1497137617-772-1-git-send-email-alison@peloton-tech.com> you wrote:
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via new 'gpt swap'
> and 'gpt rename' commands.

Thanks.

One question: can multiple GPT partitions have the same name?

> The 'swap' mode prints a warning if no matching partition names
> are found.  If only one matching name of a provided pair is found, it
> renames the matching partitions to the new name.

I see a problem here...

> +	if (!strcmp(subcomm, "swap")) {
> +		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
> +			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
> +			return -EINVAL;
> +		}
> +		list_for_each(pos, &disk_partitions) {
> +			curr = list_entry(pos, struct disk_part, list);
> +			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
> +				strcpy((char *)curr->gpt_part_info.name, name2);
> +				changed++;
> +			}
> +			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
> +				strcpy((char *)curr->gpt_part_info.name, name1);
> +				changed++;
> +			}
> +
> +		}
> +		if (changed == 0) {
> +			printf("No matching partition names were found.\n");
> +			return ret;
> +		}

You will never know if there really was a pair of names that was
swapped.  Just a single rename of name1->name2 _or_ of name2->name1
will make the user think everything was fine.

[Note: I'm in the process of relocating and will be offline for the
next 2..3. days.  Don't expect more comments from mee soon.
Sorry...]

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"I dislike companies that have a we-are-the-high-priests-of-hardware-
so-you'll-like-what-we-give-you attitude. I like commodity markets in
which iron-and-silicon hawkers know that they exist to  provide  fast
toys for software types like me to play with..."    - Eric S. Raymond

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-12  7:45                     ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
@ 2017-06-12 14:24                       ` Alison Chaiken
  2017-06-12 14:56                         ` Tom Rini
  2017-06-18 11:03                         ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
  0 siblings, 2 replies; 116+ messages in thread
From: Alison Chaiken @ 2017-06-12 14:24 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 12, 2017 at 12:45 AM, Wolfgang Denk <wd@denx.de> wrote:

> Dear Alison,
>
> In message <1497137617-772-1-git-send-email-alison@peloton-tech.com> you
> wrote:
> >
> > This patch provides support in u-boot for renaming GPT
> > partitions.  The renaming is accomplished via new 'gpt swap'
> > and 'gpt rename' commands.
>
> Thanks.
>
> One question: can multiple GPT partitions have the same name?
>


The idea behind the 'swap' mode is that a storage device can have two sets
of partitions, one set all named 'primary' and one set all named 'backup'.
  The software updater in userspace can then simply rename the partitions
with sgdisk in order to pick the new image.   The swap mode changes the
whole set of labels at once, so there's little chance of being interrupted.


>
> > The 'swap' mode prints a warning if no matching partition names
> > are found.  If only one matching name of a provided pair is found, it
> > renames the matching partitions to the new name.
>
> I see a problem here...
>
> > +     if (!strcmp(subcomm, "swap")) {
> > +             if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) >
> PART_NAME_LEN)) {
> > +                     printf("Names longer than %d characters are
> truncated.\n", PART_NAME_LEN);
> > +                     return -EINVAL;
> > +             }
> > +             list_for_each(pos, &disk_partitions) {
> > +                     curr = list_entry(pos, struct disk_part, list);
> > +                     if (!strcmp((char *)curr->gpt_part_info.name,
> name1)) {
> > +                             strcpy((char *)curr->gpt_part_info.name,
> name2);
> > +                             changed++;
> > +                     }
> > +                     else if (!strcmp((char *)curr->gpt_part_info.name,
> name2)) {
> > +                             strcpy((char *)curr->gpt_part_info.name,
> name1);
> > +                             changed++;
> > +                     }
> > +
> > +             }
> > +             if (changed == 0) {
> > +                     printf("No matching partition names were
> found.\n");
> > +                     return ret;
> > +             }
>
> You will never know if there really was a pair of names that was
> swapped.  Just a single rename of name1->name2 _or_ of name2->name1
> will make the user think everything was fine.
>

Point taken.   The last version I posted has two counters instead of just
changed in order to address this problem.



> [Note: I'm in the process of relocating and will be offline for the
> next 2..3. days.  Don't expect more comments from mee soon.
> Sorry...]
> Best regards,
> Wolfgang Denk



One additional note: the last version I posted worked fine for the sandbox,
but wouldn't link for an ARM target with the Linaro toolchain, as the
linker couldn't find atoi().   I guess the libc for the x86 compiler
includes it.   To test on ARM, I copied in simple_atoi() from
lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone have
a better idea to solve this problem?

Thanks,
Alison Chaiken
Peloton Technology

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-12 14:24                       ` Alison Chaiken
@ 2017-06-12 14:56                         ` Tom Rini
  2017-06-18 11:08                           ` Wolfgang Denk
  2017-06-18 11:03                         ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
  1 sibling, 1 reply; 116+ messages in thread
From: Tom Rini @ 2017-06-12 14:56 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 12, 2017 at 07:24:17AM -0700, Alison Chaiken wrote:
> On Mon, Jun 12, 2017 at 12:45 AM, Wolfgang Denk <wd@denx.de> wrote:
> 
> > Dear Alison,
> >
> > In message <1497137617-772-1-git-send-email-alison@peloton-tech.com> you
> > wrote:
> > >
> > > This patch provides support in u-boot for renaming GPT
> > > partitions.  The renaming is accomplished via new 'gpt swap'
> > > and 'gpt rename' commands.
> >
> > Thanks.
> >
> > One question: can multiple GPT partitions have the same name?
> 
> The idea behind the 'swap' mode is that a storage device can have two
> sets of partitions, one set all named 'primary' and one set all named
> 'backup'.  The software updater in userspace can then simply rename
> the partitions with sgdisk in order to pick the new image.   The swap
> mode changes the whole set of labels at once, so there's little chance
> of being interrupted.

I'm a little confused here now then.  Can you provide an example set of
usage, in the cover letter for v8 of the series (see below) that makes
it a bit clearer?  Thanks!

> > > The 'swap' mode prints a warning if no matching partition names
> > > are found.  If only one matching name of a provided pair is found, it
> > > renames the matching partitions to the new name.
> >
> > I see a problem here...
> >
> > > +     if (!strcmp(subcomm, "swap")) {
> > > +             if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) >
> > PART_NAME_LEN)) {
> > > +                     printf("Names longer than %d characters are
> > truncated.\n", PART_NAME_LEN);
> > > +                     return -EINVAL;
> > > +             }
> > > +             list_for_each(pos, &disk_partitions) {
> > > +                     curr = list_entry(pos, struct disk_part, list);
> > > +                     if (!strcmp((char *)curr->gpt_part_info.name,
> > name1)) {
> > > +                             strcpy((char *)curr->gpt_part_info.name,
> > name2);
> > > +                             changed++;
> > > +                     }
> > > +                     else if (!strcmp((char *)curr->gpt_part_info.name,
> > name2)) {
> > > +                             strcpy((char *)curr->gpt_part_info.name,
> > name1);
> > > +                             changed++;
> > > +                     }
> > > +
> > > +             }
> > > +             if (changed == 0) {
> > > +                     printf("No matching partition names were
> > found.\n");
> > > +                     return ret;
> > > +             }
> >
> > You will never know if there really was a pair of names that was
> > swapped.  Just a single rename of name1->name2 _or_ of name2->name1
> > will make the user think everything was fine.
> >
> 
> Point taken.   The last version I posted has two counters instead of just
> changed in order to address this problem.
> 
> 
> 
> > [Note: I'm in the process of relocating and will be offline for the
> > next 2..3. days.  Don't expect more comments from mee soon.
> > Sorry...]
> > Best regards,
> > Wolfgang Denk
> 
> 
> 
> One additional note: the last version I posted worked fine for the sandbox,
> but wouldn't link for an ARM target with the Linaro toolchain, as the
> linker couldn't find atoi().   I guess the libc for the x86 compiler
> includes it.   To test on ARM, I copied in simple_atoi() from
> lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone have
> a better idea to solve this problem?

Looking at the man page for atoi:
The  atoi() function converts the initial portion of the string pointed
to by nptr to int.  The behavior is the same as

	strtol(nptr, NULL, 10);

So we should just re-work to use simple_strtol here.  And since you
brought it up on IRC, I suppose at this point a 'clean' posting of all 5
patches marked as 'v8' might make it easier to see what's what and in
what order.  Thanks again!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170612/a0d7e5bc/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 5/5] cmd gpt: test in sandbox
  2017-06-04 22:11           ` [U-Boot] [PATCH 5/5] cmd gpt: test in sandbox alison at peloton-tech.com
@ 2017-06-15 19:21             ` sjg at google.com
  0 siblings, 0 replies; 116+ messages in thread
From: sjg at google.com @ 2017-06-15 19:21 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make minor changes to README.gpt and sandbox_defconfig to support
testing of the gpt command's functionality in the sandbox.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 doc/README.gpt | 10 ++++++++++
 1 file changed, 10 insertions(+)

Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation
  2017-06-09 12:28             ` Simon Glass
@ 2017-06-15 19:21               ` sjg at google.com
  0 siblings, 0 replies; 116+ messages in thread
From: sjg at google.com @ 2017-06-15 19:21 UTC (permalink / raw)
  To: u-boot

On 4 June 2017 at 16:11,  <alison@peloton-tech.com> wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
>
> The instructions for creating a disk image that are presently in
> README.sandbox fail because sfdisk doesn't know about GPT.
>
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  board/sandbox/README.sandbox | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
Applied to u-boot-dm, thanks!

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-12 14:24                       ` Alison Chaiken
  2017-06-12 14:56                         ` Tom Rini
@ 2017-06-18 11:03                         ` Wolfgang Denk
  2017-06-25 21:54                           ` Alison Chaiken
  1 sibling, 1 reply; 116+ messages in thread
From: Wolfgang Denk @ 2017-06-18 11:03 UTC (permalink / raw)
  To: u-boot

Dear Alison,

In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.gmail.com> you wrote:
>
> The idea behind the 'swap' mode is that a storage device can have two sets
> of partitions, one set all named 'primary' and one set all named 'backup'.
>   The software updater in userspace can then simply rename the partitions
> with sgdisk in order to pick the new image.   The swap mode changes the
> whole set of labels at once, so there's little chance of being interrupted.

It's still a sequential, non-atomic operation, and "little chance"
is exactly the places where Murphy likes to hit you.

> One additional note: the last version I posted worked fine for the sandbox,
> but wouldn't link for an ARM target with the Linaro toolchain, as the
> linker couldn't find atoi().   I guess the libc for the x86 compiler
> includes it.   To test on ARM, I copied in simple_atoi() from
> lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone have
> a better idea to solve this problem?

U-Boot should always be self-contained and not link regular library
code from the tool chain.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Looks clean and obviously correct to me, but then _everything_ I
write always looks obviously correct to me.  - Linus Torvalds in
<Pine.LNX.4.10.10012090054360.791-100000@penguin.transmeta.com>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-12 14:56                         ` Tom Rini
@ 2017-06-18 11:08                           ` Wolfgang Denk
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Wolfgang Denk @ 2017-06-18 11:08 UTC (permalink / raw)
  To: u-boot

Dear Tom,

In message <20170612145646.GY10782@bill-the-cat> you wrote:
> 
> Looking at the man page for atoi:
> The  atoi() function converts the initial portion of the string pointed
> to by nptr to int.  The behavior is the same as
> 
> 	strtol(nptr, NULL, 10);
> 
> So we should just re-work to use simple_strtol here.  And since you
> brought it up on IRC, I suppose at this point a 'clean' posting of all 5
> patches marked as 'v8' might make it easier to see what's what and in
> what order.  Thanks again!

Hm... the claim that the behaviour is the _same_ is not strictly
correct.

atoi() returns "int", while strtol() returns "long int"...

Anyway, you are right that atoi() is not being used anywhere in
active U-Boot code.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
C++ is the best example of second-system effect since OS/360.

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-18 11:03                         ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
@ 2017-06-25 21:54                           ` Alison Chaiken
  2017-06-26 22:47                             ` Tom Rini
  2017-06-27  7:05                             ` Lothar Waßmann
  0 siblings, 2 replies; 116+ messages in thread
From: Alison Chaiken @ 2017-06-25 21:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 18, 2017 at 4:03 AM, Wolfgang Denk <wd@denx.de> wrote:

> Dear Alison,
>
> In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.
> gmail.com> you wrote:
> >
> > The idea behind the 'swap' mode is that a storage device can have two
> sets
> > of partitions, one set all named 'primary' and one set all named
> 'backup'.
> >   The software updater in userspace can then simply rename the partitions
> > with sgdisk in order to pick the new image.   The swap mode changes the
> > whole set of labels at once, so there's little chance of being
> interrupted.
>
> It's still a sequential, non-atomic operation, and "little chance"
> is exactly the places where Murphy likes to hit you.
>
> > One additional note: the last version I posted worked fine for the
> sandbox,
> > but wouldn't link for an ARM target with the Linaro toolchain, as the
> > linker couldn't find atoi().   I guess the libc for the x86 compiler
> > includes it.   To test on ARM, I copied in simple_atoi() from
> > lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone
> have
> > a better idea to solve this problem?
>
> U-Boot should always be self-contained and not link regular library
> code from the tool chain.
>
> Best regards,
>
> Wolfgang Denk
>

I'm about to submit a new version of the patches that adopts Wolfgang's and
Tom's suggestions about replacing atoi().

Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first
modifies the names in an in-memory
data structure, and then uses the existing 'gpt write' functionality to
change the actual partition table stored on the device.  Thus,
interruption of the new command is low-risk, as interruption of the
modification of the new data structure has no persistent effect, and
the risk associated with 'gpt write' is the same as always.

By the way, in the course of testing an earlier version of this patch
series, I noticed that 'gpt write' and 'gpt verify' segv if presented with
a non-null-terminated partitions string.  It's the strlen function in lib
that actually generates an error. I haven't yet quite figured out what the
best solution to the problem is: should strlen() itself be modified, or is
it enough to test in gpt.c?   The right solution is not to present the
commands with poorly formed strings, but it's easy to do so.

Mit freundlichen Grüße,
Alison

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation
  2017-06-18 11:08                           ` Wolfgang Denk
@ 2017-06-25 23:43                             ` alison at peloton-tech.com
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 1/9] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
                                                 ` (8 more replies)
  0 siblings, 9 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Here is a resubmission of the 9-part patch series, the first 8 of
which have already been marked 'applied', 'reviewed', or 'ack'ed' by
Lukasz Majewski, Simon Glass or Tom Rini.  I'm reposting them all as a
set at Tom Rini's suggestion.  Those earlier patches are listed here:

  GPT: read partition table from device into a data structure
  Reviewed-by: Tom Rini, Jun 11 in <20170611133854.GS10782@bill-the-cat>

  GPT: add accessor function for disk GUID
  Reviewed-by: Tom Rini, Jun 11 in <20170611133849.GR10782@bill-the-cat>

  partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  Reviewed-by: Lukasz Majewski, Jun 3 in <20170603135259.6ba67e86@jawa>

  cmd gpt: test in sandbox
  Applied to u-boot-dm by Simon Glass, Jun 15 in <CAPnjgZ0G6QADVFLC0mExQN3HXhLXbgE4neBEtmWAg0YZu-=aNg@mail.gmail.com>

  sandbox: README: fix partition command invocation
  Reviewed-by: Simon Glass, Jun 15, applied to u-boot-dm in <CAPnjgZ1DTzPMJuDXuoQQjgrGrmTq73QqJ3qiegCS6416b1OQfQ@mail.gmail.com>

  GPT: fix error in partitions string doc
  Ack'ed by Lukasz Majewski, May 31, in <0170531132155.33a558e7@jawa>

  disk_partition: introduce macros for description string lengths
  Reviewed-by: Tom Rini, May 31 in <20170531135056.GZ10782@bill-the-cat>
  
  EFI: replace number with UUID_STR_LEN macro
  Acked-by: Lukasz Majewski, May 31 in <20170531093702.736b567f@jawa>

Changes since last version to the last patch in the series:

-- Removed several casts in create_gpt_partitions_list() and
   do_rename_gpt_parts() as suggested by Lothar Waßmann.  The cast of
   gpt_part_info.name to char* is needed to silence a compiler
   warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
   suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
   number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
   string it optionally prints is useful as input to the pre-existing
   'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
   by Tom Rini.

Changes to penultimate patch:
-- Removed a cast in allocate_disk_part() as suggested by Lothar.


Remaining tasks planned for future patches:

-- Create tests for GPT functionality as suggested by Lukasz.

-- Improve support for CONFIG_RANDOM_UUID.

-- Preserve partition type info when rewriting GPT.


Alison Chaiken (9):
  EFI: replace number with UUID_STR_LEN macro
  disk_partition: introduce macros for description string lengths
  GPT: fix error in partitions string doc
  sandbox: README: fix partition command invocation
  cmd gpt: test in sandbox
  partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  GPT: add accessor function for disk GUID
  GPT: read partition table from device into a data structure
  GPT: provide commands to selectively rename partitions

 board/sandbox/README.sandbox |   2 +-
 cmd/Kconfig                  |   8 +
 cmd/gpt.c                    | 376 ++++++++++++++++++++++++++++++++++++++++++-
 disk/part.c                  |   1 -
 disk/part_efi.c              |  33 +++-
 doc/README.gpt               |  39 ++++-
 include/part.h               |  35 +++-
 7 files changed, 481 insertions(+), 13 deletions(-)

-- 
2.1.4

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 1/9] EFI: replace number with UUID_STR_LEN macro
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 2/9] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
                                                 ` (7 subsequent siblings)
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 disk/part_efi.c | 2 +-
 include/part.h  | 5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/disk/part_efi.c b/disk/part_efi.c
index 1b7ba27..20d33ef 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -183,7 +183,7 @@ void part_print_efi(struct blk_desc *dev_desc)
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
 	gpt_entry *gpt_pte = NULL;
 	int i = 0;
-	char uuid[37];
+	char uuid[UUID_STR_LEN + 1];
 	unsigned char *uuid_bin;
 
 	/* This function validates AND fills in the GPT header and PTE */
diff --git a/include/part.h b/include/part.h
index 83bce05..6ace09f 100644
--- a/include/part.h
+++ b/include/part.h
@@ -9,6 +9,7 @@
 
 #include <blk.h>
 #include <ide.h>
+#include <uuid.h>
 
 struct block_drvr {
 	char *name;
@@ -54,10 +55,10 @@ typedef struct disk_partition {
 	uchar	type[32];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
-	char	uuid[37];	/* filesystem UUID as string, if exists	*/
+	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
 #endif
 #ifdef CONFIG_PARTITION_TYPE_GUID
-	char	type_guid[37];	/* type GUID as string, if exists	*/
+	char	type_guid[UUID_STR_LEN + 1];	/* type GUID as string, if exists	*/
 #endif
 #ifdef CONFIG_DOS_PARTITION
 	uchar	sys_ind;	/* partition type 			*/
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 2/9] disk_partition: introduce macros for description string lengths
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 1/9] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 3/9] GPT: fix error in partitions string doc alison at peloton-tech.com
                                                 ` (6 subsequent siblings)
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 include/part.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/part.h b/include/part.h
index 6ace09f..87b1111 100644
--- a/include/part.h
+++ b/include/part.h
@@ -47,12 +47,15 @@ struct block_drvr {
 #define DEV_TYPE_CDROM		0x05	/* CD-ROM */
 #define DEV_TYPE_OPDISK		0x07	/* optical disk */
 
+#define PART_NAME_LEN 32
+#define PART_TYPE_LEN 32
+
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
 	lbaint_t	size;	/* number of blocks in partition	*/
 	ulong	blksz;		/* block size in bytes			*/
-	uchar	name[32];	/* partition name			*/
-	uchar	type[32];	/* string type description		*/
+	uchar	name[PART_NAME_LEN];	/* partition name			*/
+	uchar	type[PART_TYPE_LEN];	/* string type description		*/
 	int	bootable;	/* Active/Bootable flag is set		*/
 #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
 	char	uuid[UUID_STR_LEN + 1];	/* filesystem UUID as string, if exists	*/
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 3/9] GPT: fix error in partitions string doc
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 1/9] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 2/9] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 4/9] sandbox: README: fix partition command invocation alison at peloton-tech.com
                                                 ` (5 subsequent siblings)
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

The existing partitions-list parsing in cmd/gpt.c passes a value
from gpt_default() to set_gpt_info() that README.gpt suggests
should begin with 'partitions='.  Partition-list strings should
in fact begin with 'uuid_disk', as otherwise the call from
set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
Change README.gpt accordingly.

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 doc/README.gpt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/doc/README.gpt b/doc/README.gpt
index 3fcd835..589295b 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -156,10 +156,10 @@ Creating GPT partitions in U-Boot:
 To restore GUID partition table one needs to:
 1. Define partition layout in the environment.
    Format of partitions layout:
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...;"
      or
-     "partitions=uuid_disk=${uuid_gpt_disk};name=${uboot_name},
+     "uuid_disk=${uuid_gpt_disk};name=${uboot_name},
 	size=${uboot_size},uuid=${uboot_uuid};"
 
    The fields 'name' and 'size' are mandatory for every partition.
@@ -219,7 +219,7 @@ PARTITION_BASIC_DATA_GUID (EBD0A0A2-B9E5-4433-87C0-68B6B72699C7).
 If you define 'CONFIG_PARTITION_TYPE_GUID', a optionnal parameter 'type'
 can specify a other partition type guid:
 
-     "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+     "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,
 	type=0FC63DAF-8483-4772-8E79-3D69D8477DE4;"
 
@@ -241,7 +241,7 @@ Some strings can be also used at the place of known GUID :
 	"lvm"    = PARTITION_LINUX_LVM_GUID
 	           (E6D6D379-F507-44C2-A23C-238F2A3DF928)
 
-    "partitions=uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
 	name=kernel,size=60MiB,uuid=...,type=linux;"
 
 They are also used to display the type of partition in "part list" command.
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 4/9] sandbox: README: fix partition command invocation
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
                                                 ` (2 preceding siblings ...)
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 3/9] GPT: fix error in partitions string doc alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 5/9] cmd gpt: test in sandbox alison at peloton-tech.com
                                                 ` (4 subsequent siblings)
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

The instructions for creating a disk image that are presently in
README.sandbox fail because sfdisk doesn't know about GPT.

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 board/sandbox/README.sandbox | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/board/sandbox/README.sandbox b/board/sandbox/README.sandbox
index 02d8ab3..9dc2eb0 100644
--- a/board/sandbox/README.sandbox
+++ b/board/sandbox/README.sandbox
@@ -333,7 +333,7 @@ the contents of the root directory on the second partion of the image
 A disk image can be created using the following commands:
 
 $> truncate -s 1200M ./disk.raw
-$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sfdisk  ./disk.raw
+$> echo -e "label: gpt\n,64M,U\n,,L" | /usr/sbin/sgdisk  ./disk.raw
 $> lodev=`sudo losetup -P -f --show ./disk.raw`
 $> sudo mkfs.vfat -n EFI -v ${lodev}p1
 $> sudo mkfs.ext4 -L ROOT -v ${lodev}p2
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 5/9] cmd gpt: test in sandbox
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
                                                 ` (3 preceding siblings ...)
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 4/9] sandbox: README: fix partition command invocation alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:54                                 ` [U-Boot] [U-Boot,v7,5/9] " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 6/9] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
                                                 ` (3 subsequent siblings)
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make minor changes to README.gpt and sandbox_defconfig to support
testing of the gpt command's functionality in the sandbox.

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 doc/README.gpt | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/doc/README.gpt b/doc/README.gpt
index 589295b..0a3286f 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,16 @@ U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
 
+The GPT functionality may be tested with the 'sandbox' board by
+creating a disk image as described under 'Block Device Emulation' in
+board/sandbox/README.sandbox:
+
+=>host bind 0 ./disk.raw
+=> gpt read host 0
+[ . . . ]
+=> gpt flip host 0
+[ . . . ]
+
 Partition type GUID:
 ====================
 
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 6/9] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
                                                 ` (4 preceding siblings ...)
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 5/9] cmd gpt: test in sandbox alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 7/9] GPT: add accessor function for disk GUID alison at peloton-tech.com
                                                 ` (2 subsequent siblings)
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd
directory can find it.  At the same time, increase the value to
64 since some operating systems use many, and the resources
consumed by a larger value are minimal.

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 disk/part.c    | 1 -
 include/part.h | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/disk/part.c b/disk/part.c
index 491b02d..e640a55 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -388,7 +388,6 @@ cleanup:
 
 #define PART_UNSPECIFIED -2
 #define PART_AUTO -1
-#define MAX_SEARCH_PARTITIONS 16
 int blk_get_device_part_str(const char *ifname, const char *dev_part_str,
 			     struct blk_desc **dev_desc,
 			     disk_partition_t *info, int allow_whole_dev)
diff --git a/include/part.h b/include/part.h
index 87b1111..22da604 100644
--- a/include/part.h
+++ b/include/part.h
@@ -49,6 +49,7 @@ struct block_drvr {
 
 #define PART_NAME_LEN 32
 #define PART_TYPE_LEN 32
+#define MAX_SEARCH_PARTITIONS 64
 
 typedef struct disk_partition {
 	lbaint_t	start;	/* # of first block in partition	*/
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 7/9] GPT: add accessor function for disk GUID
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
                                                 ` (5 preceding siblings ...)
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 6/9] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-08-07 13:55                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 8/9] GPT: read partition table from device into a data structure alison at peloton-tech.com
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

In order to read the GPT, modify the partition name strings, and then
write out a new GPT, the disk GUID is needed.  While there is an
existing accessor for the partition UUIDs, there is none yet for the
disk GUID.

Changes since v6: none.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c       | 26 ++++++++++++++++++++++++++
 disk/part_efi.c | 31 +++++++++++++++++++++++++++++++
 doc/README.gpt  |  3 ++-
 include/part.h  | 15 +++++++++++++++
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 3e98821..65fb80b 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -398,6 +398,23 @@ static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
 	return ret;
 }
 
+static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
+{
+	int ret;
+	char disk_guid[UUID_STR_LEN + 1];
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return CMD_RET_FAILURE;
+
+	if (namestr)
+		setenv(namestr, disk_guid);
+	else
+		printf("%s\n", disk_guid);
+
+	return ret;
+}
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -436,6 +453,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	} else if ((strcmp(argv[1], "verify") == 0)) {
 		ret = gpt_verify(blk_dev_desc, argv[4]);
 		printf("Verify GPT: ");
+	} else if (strcmp(argv[1], "guid") == 0) {
+		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -458,4 +477,11 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" guid <interface> <dev>\n"
+	"    - print disk GUID\n"
+	" guid <interface> <dev> <varname>\n"
+	"    - set environment variable to disk GUID\n"
+	" Example usage:\n"
+	" gpt guid mmc 0\n"
+	" gpt guid mmc 0 varname\n"
 );
diff --git a/disk/part_efi.c b/disk/part_efi.c
index 20d33ef..71c3cb3 100644
--- a/disk/part_efi.c
+++ b/disk/part_efi.c
@@ -178,6 +178,37 @@ static void prepare_backup_gpt_header(gpt_header *gpt_h)
  * Public Functions (include/part.h)
  */
 
+/*
+ * UUID is displayed as 32 hexadecimal digits, in 5 groups,
+ * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
+ */
+int get_disk_guid(struct blk_desc * dev_desc, char *guid)
+{
+	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
+	gpt_entry *gpt_pte = NULL;
+	unsigned char *guid_bin;
+
+	/* This function validates AND fills in the GPT header and PTE */
+	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
+			 gpt_head, &gpt_pte) != 1) {
+		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
+		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
+				 gpt_head, &gpt_pte) != 1) {
+			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
+			       __func__);
+			return -EINVAL;
+		} else {
+			printf("%s: ***        Using Backup GPT ***\n",
+			       __func__);
+		}
+	}
+
+	guid_bin = gpt_head->disk_guid.b;
+	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
+
+	return 0;
+}
+
 void part_print_efi(struct blk_desc *dev_desc)
 {
 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
diff --git a/doc/README.gpt b/doc/README.gpt
index 0a3286f..6c5ab78 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -171,7 +171,8 @@ To restore GUID partition table one needs to:
    The fields 'uuid' and 'uuid_disk' are optional if CONFIG_RANDOM_UUID is
    enabled. A random uuid will be used if omitted or they point to an empty/
    non-existent environment variable. The environment variable will be set to
-   the generated UUID.
+   the generated UUID.  The 'gpt guid' command reads the current value of the
+   uuid_disk from the GPT.
 
    The field 'bootable' is optional, it is used to mark the GPT partition
    bootable (set attribute flags "Legacy BIOS bootable").
diff --git a/include/part.h b/include/part.h
index 22da604..c41aa6a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -372,6 +372,21 @@ int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
 int gpt_verify_partitions(struct blk_desc *dev_desc,
 			  disk_partition_t *partitions, int parts,
 			  gpt_header *gpt_head, gpt_entry **gpt_pte);
+
+
+/**
+ * get_disk_guid() - Function to read the GUID string from a device's GPT
+ *
+ * This function reads the GUID string from a block device whose descriptor
+ * is provided.
+ *
+ * @param dev_desc - block device descriptor
+ * @param guid - pre-allocated string in which to return the GUID
+ *
+ * @return - '0' on success, otherwise error
+ */
+int get_disk_guid(struct blk_desc *dev_desc, char *guid);
+
 #endif
 
 #if CONFIG_IS_ENABLED(DOS_PARTITION)
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 8/9] GPT: read partition table from device into a data structure
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
                                                 ` (6 preceding siblings ...)
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 7/9] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-06-26  7:34                                 ` Lothar Waßmann
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
  8 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Change since v6:
-- Removed a cast in allocate_disk_part() as suggested by Lothar.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 126 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 65fb80b..9934ef4 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,118 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (!valid_parts) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;
+ out:
+	if (valid_parts >= 2)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +570,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +594,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index c41aa6a..0cd803a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions
  2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
                                                 ` (7 preceding siblings ...)
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 8/9] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-06-25 23:43                               ` alison at peloton-tech.com
  2017-06-26  1:52                                 ` Bin Meng
  2017-06-26  7:55                                 ` Lothar Waßmann
  8 siblings, 2 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-25 23:43 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via new 'gpt swap'
and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names
are found, or if the number of partitions with one name does not equal
the number with the second name.   The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Changes since v7:

-- Removed several casts in create_gpt_partitions_list() and
   do_rename_gpt_parts() as suggested by Lothar Waßmann.  The cast of
   gpt_part_info.name to char* is needed to silence a compiler
   warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
   suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
   number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
   string it optionally prints is useful as input to the pre-existing
   'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
   by Tom Rini.


Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 07b0e3b..ae61b96 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 9934ef4..8c0441f 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,8 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+#include <stdlib.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +196,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +234,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -EINVAL;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +313,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -301,6 +391,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -530,6 +622,127 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	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"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts: -ENODEV;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	/*
+	 * Uncomment the following line to print a string that 'gpt write'
+	 * or 'gpt verify' will accept as input.
+	 */
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				ctr1++;
+			}
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				ctr2++;
+			}
+		}
+		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
+			printf("Cannot swap partition names except in pairs.\n");
+			return -EINVAL;
+		}
+	} else { /* rename */
+		if (strlen(name2) > PART_NAME_LEN) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		partnum = (int)simple_strtol(name1, NULL, 10);
+		if ((partnum < 0) || (partnum > numparts)) {
+			printf("Illegal partition number %s\n", name1);
+			return -EINVAL;
+		}
+		ret = part_get_info(dev_desc, partnum, new_partitions);
+		if (ret < 0)
+			return ret;
+
+		/* U-Boot partition numbering starts@1 */
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts : -ENODEV;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -547,7 +760,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
-	if (argc < 4 || argc > 5)
+	if (argc < 4 || argc > 6)
 		return CMD_RET_USAGE;
 
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -572,6 +785,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} 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]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -603,4 +821,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\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"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index 6c5ab78..d3db8bc 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
@ 2017-06-26  1:52                                 ` Bin Meng
  2017-06-26  2:11                                   ` alison at peloton-tech.com
  2017-06-26  7:55                                 ` Lothar Waßmann
  1 sibling, 1 reply; 116+ messages in thread
From: Bin Meng @ 2017-06-26  1:52 UTC (permalink / raw)
  To: u-boot

Hi

On Mon, Jun 26, 2017 at 7:43 AM,  <alison@peloton-tech.com> wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
>
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via new 'gpt swap'
> and 'gpt rename' commands.
>
> The 'swap' mode returns an error if no matching partition names
> are found, or if the number of partitions with one name does not equal
> the number with the second name.   The 'rename' variant always
> succeeds as long as a partition with the provided number exists.
>
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
>
> Changes since v7:
>
> -- Removed several casts in create_gpt_partitions_list() and
>    do_rename_gpt_parts() as suggested by Lothar Waßmann.  The cast of
>    gpt_part_info.name to char* is needed to silence a compiler
>    warning.
>
> -- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
>    suggested by Tom Rini and Wolfgang Denk.
>
> -- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
>    number of partitions with which to continue.
>
> -- Added a comment to do_rename_gpt_parts() noting that the debug()
>    string it optionally prints is useful as input to the pre-existing
>    'gpt write' and 'gpt verify' commands.
>
> -- Changed some -1 return values to -ENODEV and -EINVAL as suggested
>    by Tom Rini.
>

Can you please remove the changelog from the commit message, instead
put it in the commit-notes section below ---?

>
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/Kconfig    |   8 ++
>  cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  doc/README.gpt |  20 ++++-
>  3 files changed, 261 insertions(+), 6 deletions(-)
>

[snip]

Regards,
Bin

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions
  2017-06-26  1:52                                 ` Bin Meng
@ 2017-06-26  2:11                                   ` alison at peloton-tech.com
  0 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-06-26  2:11 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via new 'gpt swap'
and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names
are found, or if the number of partitions with one name does not equal
the number with the second name.   The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 doc/README.gpt |  20 ++++-
 3 files changed, 261 insertions(+), 6 deletions(-)

Changes since v7:

-- Removed several casts in create_gpt_partitions_list() and
   do_rename_gpt_parts() as suggested by Lothar Waßmann.  The cast of
   gpt_part_info.name to char* is needed to silence a compiler
   warning.

-- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
   suggested by Tom Rini and Wolfgang Denk.

-- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
   number of partitions with which to continue.

-- Added a comment to do_rename_gpt_parts() noting that the debug()
   string it optionally prints is useful as input to the pre-existing
   'gpt write' and 'gpt verify' commands.

-- Changed some -1 return values to -ENODEV and -EINVAL as suggested
   by Tom Rini.

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 07b0e3b..ae61b96 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 9934ef4..8c0441f 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,8 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+#include <stdlib.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +196,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, unsigned long partsize,
+				  unsigned long blksize)
+{
+	unsigned long long partbytes;
+	unsigned long partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%luMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +234,74 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -EINVAL;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		/* lbaint_t is unsigned long, per include/ide.h */
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +313,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -301,6 +391,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -530,6 +622,127 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	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"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts: -ENODEV;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = malloc(partlistlen);
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
+					 partitions_list);
+	if (ret < 0)
+		return ret;
+	/*
+	 * Uncomment the following line to print a string that 'gpt write'
+	 * or 'gpt verify' will accept as input.
+	 */
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				ctr1++;
+			}
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				ctr2++;
+			}
+		}
+		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
+			printf("Cannot swap partition names except in pairs.\n");
+			return -EINVAL;
+		}
+	} else { /* rename */
+		if (strlen(name2) > PART_NAME_LEN) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		partnum = (int)simple_strtol(name1, NULL, 10);
+		if ((partnum < 0) || (partnum > numparts)) {
+			printf("Illegal partition number %s\n", name1);
+			return -EINVAL;
+		}
+		ret = part_get_info(dev_desc, partnum, new_partitions);
+		if (ret < 0)
+			return ret;
+
+		/* U-Boot partition numbering starts@1 */
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts : -ENODEV;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -547,7 +760,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
-	if (argc < 4 || argc > 5)
+	if (argc < 4 || argc > 6)
 		return CMD_RET_USAGE;
 
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -572,6 +785,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} 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]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -603,4 +821,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\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"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index 6c5ab78..d3db8bc 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 8/9] GPT: read partition table from device into a data structure
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 8/9] GPT: read partition table from device into a data structure alison at peloton-tech.com
@ 2017-06-26  7:34                                 ` Lothar Waßmann
  2017-07-01 22:42                                   ` [U-Boot] [PATCH v8 8/10] " alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-26  7:34 UTC (permalink / raw)
  To: u-boot

Hi,

On Sun, 25 Jun 2017 16:43:24 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Change since v6:
> -- Removed a cast in allocate_disk_part() as suggested by Lothar.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/part.h |   7 ++++
>  2 files changed, 126 insertions(+)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 65fb80b..9934ef4 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -19,6 +19,9 @@
>  #include <linux/ctype.h>
>  #include <div64.h>
>  #include <memalign.h>
> +#include <linux/compat.h>
> +
> +static LIST_HEAD(disk_partitions);
>  
>  /**
>   * extract_env(): Expand env name from string format '&{env_name}'
> @@ -151,6 +154,118 @@ static bool found_key(const char *str, const char *key)
>  	return result;
>  }
>  
> +static void del_gpt_info(void)
> +{
> +	struct list_head *pos = &disk_partitions;
> +	struct disk_part *curr;
> +	while (!list_empty(pos)) {
> +		curr = list_entry(pos->next, struct disk_part, list);
> +		list_del(pos->next);
> +		free(curr);
> +	}
> +}
> +
> +static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
> +{
> +	struct disk_part *newpart;
> +	newpart = malloc(sizeof(*newpart));
> +	if (!newpart)
> +		return ERR_PTR(-ENOMEM);
> +	memset(newpart, '\0', sizeof(newpart));
> +
> +	newpart->gpt_part_info.start = info->start;
> +	newpart->gpt_part_info.size = info->size;
> +	newpart->gpt_part_info.blksz = info->blksz;
> +	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
> +		PART_NAME_LEN);
> +	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
> +	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
> +		PART_TYPE_LEN);
> +	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
> +	newpart->gpt_part_info.bootable = info->bootable;
> +#ifdef CONFIG_PARTITION_UUIDS
> +	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
> +		UUID_STR_LEN);
> +	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
> +	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
> +#endif
> +	newpart->partnum = partnum;
> +
> +	return newpart;
> +}
> +
> +static void print_gpt_info(void)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		printf("Partition %d:\n", curr->partnum);
> +		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> +		       (unsigned)curr->gpt_part_info.size);
> +		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
> +		       curr->gpt_part_info.name);
> +		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> +		       curr->gpt_part_info.bootable);
> +#ifdef CONFIG_PARTITION_UUIDS
> +		printf("UUID %s\n", curr->gpt_part_info.uuid);
> +#endif
> +		printf("\n");
> +	}
> +}
> +
> +/*
> + * read partition info into disk_partitions list where
> + * it can be printed or modified
> + */
> +static int get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	/* start partition numbering at 1, as U-Boot does */
> +	int valid_parts = 1, p, ret;
> +	disk_partition_t info;
> +	struct disk_part *new_disk_part;
> +
> +	if (disk_partitions.next == NULL)
> +		INIT_LIST_HEAD(&disk_partitions);
> +
> +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> +		ret = part_get_info(dev_desc, p, &info);
> +		if (ret)
> +			continue;
> +
> +		new_disk_part = allocate_disk_part(&info, valid_parts);
> +		if (IS_ERR(new_disk_part))
> +			goto out;
> +
> +		list_add_tail(&new_disk_part->list, &disk_partitions);
> +		valid_parts++;
> +	}
> +	if (!valid_parts) {
>
You initialize valid_parts to '1' and only ever increment it, so it can
never be '0' here.


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
  2017-06-26  1:52                                 ` Bin Meng
@ 2017-06-26  7:55                                 ` Lothar Waßmann
  2017-07-01 22:44                                   ` [U-Boot] [PATCH 09/10] " alison at peloton-tech.com
  1 sibling, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-26  7:55 UTC (permalink / raw)
  To: u-boot

Hi,

On Sun, 25 Jun 2017 16:43:25 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via new 'gpt swap'
> and 'gpt rename' commands.
> 
> The 'swap' mode returns an error if no matching partition names
> are found, or if the number of partitions with one name does not equal
> the number with the second name.   The 'rename' variant always
> succeeds as long as a partition with the provided number exists.
> 
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
> 
> Changes since v7:
> 
> -- Removed several casts in create_gpt_partitions_list() and
>    do_rename_gpt_parts() as suggested by Lothar Waßmann.  The cast of
>    gpt_part_info.name to char* is needed to silence a compiler
>    warning.
> 
> -- Substituted simple_strtol() for atoi() in do_gpt_rename_parts() as
>    suggested by Tom Rini and Wolfgang Denk.
> 
> -- Fixed bug in do_rename_gpt_parts() where 0 was returned as a valid
>    number of partitions with which to continue.
> 
> -- Added a comment to do_rename_gpt_parts() noting that the debug()
>    string it optionally prints is useful as input to the pre-existing
>    'gpt write' and 'gpt verify' commands.
> 
> -- Changed some -1 return values to -ENODEV and -EINVAL as suggested
>    by Tom Rini.
> 
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/Kconfig    |   8 ++
>  cmd/gpt.c      | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  doc/README.gpt |  20 ++++-
>  3 files changed, 261 insertions(+), 6 deletions(-)
> 
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index 07b0e3b..ae61b96 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -595,6 +595,14 @@ config CMD_GPT
>  	  Enable the 'gpt' command to ready and write GPT style partition
>  	  tables.
>  
> +config CMD_GPT_RENAME
> +	bool "GPT partition renaming commands"
> +	depends on CMD_GPT
> +	help
> +	  Enables the 'gpt' command to interchange names on two GPT
> +	  partitions via the 'gpt swap' command or to rename single
> +	  partitions via the 'rename' command.
> +
>  config CMD_ARMFLASH
>  	#depends on FLASH_CFI_DRIVER
>  	bool "armflash"
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 9934ef4..8c0441f 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -20,6 +20,8 @@
>  #include <div64.h>
>  #include <memalign.h>
>  #include <linux/compat.h>
> +#include <linux/sizes.h>
> +#include <stdlib.h>
>  
>  static LIST_HEAD(disk_partitions);
>  
> @@ -194,16 +196,33 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
>  	return newpart;
>  }
>  
> +static void prettyprint_part_size(char *sizestr, unsigned long partsize,
> +				  unsigned long blksize)
> +{
> +	unsigned long long partbytes;
> +	unsigned long partmegabytes;
> +
> +	partbytes = partsize * blksize;
> +	partmegabytes = lldiv(partbytes, SZ_1M);
> +	snprintf(sizestr, 16, "%luMiB", partmegabytes);
> +}
> +
>  static void print_gpt_info(void)
>  {
>  	struct list_head *pos;
>  	struct disk_part *curr;
> +	char partstartstr[16];
> +	char partsizestr[16];
>  
>  	list_for_each(pos, &disk_partitions) {
>  		curr = list_entry(pos, struct disk_part, list);
> +		prettyprint_part_size(partstartstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		prettyprint_part_size(partsizestr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +
>  		printf("Partition %d:\n", curr->partnum);
> -		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
> -		       (unsigned)curr->gpt_part_info.size);
> +		printf("Start %s, size %s\n", partstartstr, partsizestr);
>  		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
>  		       curr->gpt_part_info.name);
>  		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
> @@ -215,6 +234,74 @@ static void print_gpt_info(void)
>  	}
>  }
>  
> +#ifdef CONFIG_CMD_GPT_RENAME
> +static int calc_parts_list_len(int numparts)
> +{
> +	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> +	/* for the comma */
> +	partlistlen++;
> +
> +	/* per-partition additions; numparts starts at 1, so this should be correct */
> +	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
> +	/* 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);
> +	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
> +	/* for the terminating null */
> +	partlistlen++;
> +	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
> +	       numparts);
> +	return partlistlen;
> +}
> +
> +/*
> + * create the string that upstream 'gpt write' command will accept as an
> + * argument
> + *
> + * From doc/README.gpt, Format of partitions layout:
> + *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
> + *	name=kernel,size=60MiB,uuid=...;"
> + * The fields 'name' and 'size' are mandatory for every partition.
> + * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
> + * are optional if CONFIG_RANDOM_UUID is enabled.
> + */
> +static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	char partstr[PART_NAME_LEN + 1];
> +
> +	if (!partitions_list)
> +		return -EINVAL;
> +
> +	strcpy(partitions_list, "uuid_disk=");
> +	strncat(partitions_list, guid, UUID_STR_LEN + 1);
> +	strcat(partitions_list, ";");
> +
> +	list_for_each(pos, &disk_partitions) {
> +		curr = list_entry(pos, struct disk_part, list);
> +		strcat(partitions_list, "name=");
> +		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
> +		strcat(partitions_list, ",start=");
> +		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		/* one extra byte for NULL */
> +		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
> +		strcat(partitions_list, ",size=");
> +		/* lbaint_t is unsigned long, per include/ide.h */
>
AFAICT lbaint_t is declared in include/blk.h and may be uint64_t or
ulong depending on CONFIG_SYS_64BIT_LBA.

> +		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.size,
> +				      (unsigned long) curr->gpt_part_info.blksz);
> +		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
> +
> +		strcat(partitions_list, ",uuid=");
> +		strncat(partitions_list, curr->gpt_part_info.uuid,
> +			UUID_STR_LEN + 1);
> +		strcat(partitions_list, ";");
> +	}
> +	return 0;
> +}
> +#endif
> +
>  /*
>   * read partition info into disk_partitions list where
>   * it can be printed or modified
> @@ -226,8 +313,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
>  	disk_partition_t info;
>  	struct disk_part *new_disk_part;
>  
> -	if (disk_partitions.next == NULL)
> -		INIT_LIST_HEAD(&disk_partitions);
> +	/*
> +	 * Always re-read partition info from device, in case
> +	 * it has changed
> +	 */
> +	INIT_LIST_HEAD(&disk_partitions);
>  
>  	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
>  		ret = part_get_info(dev_desc, p, &info);
> @@ -301,6 +391,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  		return -1;
>  
>  	str = strdup(str_part);
> +	if (str == NULL)
> +		return -ENOMEM;
>  
>  	/* extract disk guid */
>  	s = str;
> @@ -530,6 +622,127 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
>  	return ret;
>  }
>  
> +#ifdef CONFIG_CMD_GPT_RENAME
> +static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
> +			       char *name1, char *name2)
> +{
> +	struct list_head *pos;
> +	struct disk_part *curr;
> +	disk_partition_t *new_partitions = NULL;
> +	char disk_guid[UUID_STR_LEN + 1];
> +	char *partitions_list, *str_disk_guid;
> +	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"))))
> +		return -EINVAL;
> +
> +	ret = get_disk_guid(dev_desc, disk_guid);
> +	if (ret < 0)
> +		return ret;
> +	numparts = get_gpt_info(dev_desc);
> +	if (numparts <=  0)
> +		return numparts ? numparts: -ENODEV;
> +
> +	partlistlen = calc_parts_list_len(numparts);
> +	partitions_list = malloc(partlistlen);
> +	memset(partitions_list, '\0', partlistlen);
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid,
>
unnecessary type cast. A function that takes a 'const' argument may well
be passed a non-'const' value.

> +					 partitions_list);
> +	if (ret < 0)
> +		return ret;
> +	/*
> +	 * Uncomment the following line to print a string that 'gpt write'
> +	 * or 'gpt verify' will accept as input.
> +	 */
> +	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
> +	      (unsigned)strlen(partitions_list));
> +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
>
dto.

[...]
> +		list_for_each(pos, &disk_partitions) {
> +			curr = list_entry(pos, struct disk_part, list);
> +			if (i == partnum) {
> +				strcpy((char *)curr->gpt_part_info.name, name2);
> +				break;
> +			}
> +			i++;
> +		}
> +	}
> +
> +	ret = create_gpt_partitions_list(numparts, (const char *) disk_guid, partitions_list);
>
dto.

> +	if (ret < 0)
> +		return ret;
> +	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
> +	      (unsigned)strlen(partitions_list));
> +
> +	ret = set_gpt_info(dev_desc, (const char *)partitions_list, &str_disk_guid,
dto.

> @@ -547,7 +760,7 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  	char *ep;
>  	struct blk_desc *blk_dev_desc = NULL;
>  
> -	if (argc < 4 || argc > 5)
> +	if (argc < 4 || argc > 6)
>
Other subcommands still accept only 4 parameters, so this check should
possibly be done after checking the subcommand name, or at least made
conditional on CONFIG_CMD_GPT_RENAME which enables the new subcommands.

>  		return CMD_RET_USAGE;
>  
>  	dev = (int)simple_strtoul(argv[3], &ep, 10);
> @@ -572,6 +785,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  		ret = do_disk_guid(blk_dev_desc, argv[4]);
>  	} else if (strcmp(argv[1], "read") == 0) {
>  		ret = do_get_gpt_info(blk_dev_desc);
> +#ifdef CONFIG_CMD_GPT_RENAME
> +	} 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]);
> +#endif
>  	} else {
>  		return CMD_RET_USAGE;
>  	}
> @@ -603,4 +821,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
>  	" Example usage:\n"
>  	" gpt guid mmc 0\n"
>  	" gpt guid mmc 0 varname\n"
> +#ifdef CONFIG_CMD_GPT_RENAME
> +	"gpt partition renaming commands:\n"
> +	"gpt swap <interface> <dev> <name1> <name2>\n"
> +	"    - change all partitions named name1 to name2\n"
> +	"      and vice-versa\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"
> +#endif
>  );
> diff --git a/doc/README.gpt b/doc/README.gpt
> index 6c5ab78..d3db8bc 100644
> --- a/doc/README.gpt
> +++ b/doc/README.gpt
> @@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
>  U-BOOT> gpt verify mmc 0 $partitions
>  U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
>  
> +Renaming GPT partitions from U-Boot:
> +====================================
> +
> +GPT partition names are a mechanism via which userspace and U-Boot can
> +communicate about software updates and boot failure.  The 'gpt guid',
> +'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
> +programmatic renaming of partitions from bootscripts by generating and
> +modifying the partitions layout string.  Here is an illustration of
> +employing 'swap' to exchange 'primary' and 'backup' partition names:
> +
> +U-BOOT> gpt swap mmc 0 primary backup
> +
> +Afterwards, all partitions previously named 'primary' will be named
> +'backup', and vice-versa.  Alternatively, single partitions may be
> +renamed.  In this example, mmc0's first partition will be renamed
> +'primary':
> +
> +U-BOOT> gpt rename mmc 0 1 primary
>  
>  The GPT functionality may be tested with the 'sandbox' board by
>  creating a disk image as described under 'Block Device Emulation' in
> @@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
>  =>host bind 0 ./disk.raw
>  => gpt read host 0
>  [ . . . ]
> -=> gpt flip host 0
> +=> gpt swap host 0 name othername
>  [ . . . ]
>  
>  Partition type GUID:


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-25 21:54                           ` Alison Chaiken
@ 2017-06-26 22:47                             ` Tom Rini
  2017-06-27  7:05                             ` Lothar Waßmann
  1 sibling, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-06-26 22:47 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 02:54:56PM -0700, Alison Chaiken wrote:
> On Sun, Jun 18, 2017 at 4:03 AM, Wolfgang Denk <wd@denx.de> wrote:
> 
> > Dear Alison,
> >
> > In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.
> > gmail.com> you wrote:
> > >
> > > The idea behind the 'swap' mode is that a storage device can have two
> > sets
> > > of partitions, one set all named 'primary' and one set all named
> > 'backup'.
> > >   The software updater in userspace can then simply rename the partitions
> > > with sgdisk in order to pick the new image.   The swap mode changes the
> > > whole set of labels at once, so there's little chance of being
> > interrupted.
> >
> > It's still a sequential, non-atomic operation, and "little chance"
> > is exactly the places where Murphy likes to hit you.
> >
> > > One additional note: the last version I posted worked fine for the
> > sandbox,
> > > but wouldn't link for an ARM target with the Linaro toolchain, as the
> > > linker couldn't find atoi().   I guess the libc for the x86 compiler
> > > includes it.   To test on ARM, I copied in simple_atoi() from
> > > lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone
> > have
> > > a better idea to solve this problem?
> >
> > U-Boot should always be self-contained and not link regular library
> > code from the tool chain.
> >
> > Best regards,
> >
> > Wolfgang Denk
> >
> 
> I'm about to submit a new version of the patches that adopts Wolfgang's and
> Tom's suggestions about replacing atoi().
> 
> Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first
> modifies the names in an in-memory
> data structure, and then uses the existing 'gpt write' functionality to
> change the actual partition table stored on the device.  Thus,
> interruption of the new command is low-risk, as interruption of the
> modification of the new data structure has no persistent effect, and
> the risk associated with 'gpt write' is the same as always.
> 
> By the way, in the course of testing an earlier version of this patch
> series, I noticed that 'gpt write' and 'gpt verify' segv if presented with
> a non-null-terminated partitions string.  It's the strlen function in lib
> that actually generates an error. I haven't yet quite figured out what the
> best solution to the problem is: should strlen() itself be modified, or is
> it enough to test in gpt.c?   The right solution is not to present the
> commands with poorly formed strings, but it's easy to do so.

It is likely this particular bug is one of many in the class of using
strlen when we cannot really be certain of well formatted input /
buffer, sadly.  So a fix to gpt.c and if you're so inclined, a git grep
around for other likely cases.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170626/e271ce2a/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-25 21:54                           ` Alison Chaiken
  2017-06-26 22:47                             ` Tom Rini
@ 2017-06-27  7:05                             ` Lothar Waßmann
  2017-06-27  9:12                               ` Lothar Waßmann
  2017-07-01 22:36                               ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions Alison Chaiken
  1 sibling, 2 replies; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-27  7:05 UTC (permalink / raw)
  To: u-boot

Hi,

On Sun, 25 Jun 2017 14:54:56 -0700 Alison Chaiken wrote:
> On Sun, Jun 18, 2017 at 4:03 AM, Wolfgang Denk <wd@denx.de> wrote:
> 
> > Dear Alison,
> >
> > In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.
> > gmail.com> you wrote:
> > >
> > > The idea behind the 'swap' mode is that a storage device can have two
> > sets
> > > of partitions, one set all named 'primary' and one set all named
> > 'backup'.
> > >   The software updater in userspace can then simply rename the partitions
> > > with sgdisk in order to pick the new image.   The swap mode changes the
> > > whole set of labels at once, so there's little chance of being
> > interrupted.
> >
> > It's still a sequential, non-atomic operation, and "little chance"
> > is exactly the places where Murphy likes to hit you.
> >
> > > One additional note: the last version I posted worked fine for the
> > sandbox,
> > > but wouldn't link for an ARM target with the Linaro toolchain, as the
> > > linker couldn't find atoi().   I guess the libc for the x86 compiler
> > > includes it.   To test on ARM, I copied in simple_atoi() from
> > > lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone
> > have
> > > a better idea to solve this problem?
> >
> > U-Boot should always be self-contained and not link regular library
> > code from the tool chain.
> >
> > Best regards,
> >
> > Wolfgang Denk
> >
> 
> I'm about to submit a new version of the patches that adopts Wolfgang's and
> Tom's suggestions about replacing atoi().
> 
> Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first
> modifies the names in an in-memory
> data structure, and then uses the existing 'gpt write' functionality to
> change the actual partition table stored on the device.  Thus,
> interruption of the new command is low-risk, as interruption of the
> modification of the new data structure has no persistent effect, and
> the risk associated with 'gpt write' is the same as always.
> 
> By the way, in the course of testing an earlier version of this patch
> series, I noticed that 'gpt write' and 'gpt verify' segv if presented with
> a non-null-terminated partitions string.  It's the strlen function in lib
> that actually generates an error. I haven't yet quite figured out what the
> best solution to the problem is: should strlen() itself be modified, or is
> it enough to test in gpt.c?   The right solution is not to present the
> commands with poorly formed strings, but it's easy to do so.
> 
You can use strnlen() if you know the maximum allowed length of the
string.

NB: A quick glance at set_gpt_info() revealed this potential crash
cause:
|	str = strdup(str_part);
|
|	/* extract disk guid */
|	s = str;
|	val = extract_val(str, "uuid_disk");
strdup() may fail (especially if the input string is not zero
terminated) and return a NULL pointer which then will happily be used
by extract_val().



Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-27  7:05                             ` Lothar Waßmann
@ 2017-06-27  9:12                               ` Lothar Waßmann
  2017-07-01 22:44                                 ` [U-Boot] [PATCH 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings alison at peloton-tech.com
  2017-07-01 22:36                               ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions Alison Chaiken
  1 sibling, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-06-27  9:12 UTC (permalink / raw)
  To: u-boot

Hi,

On Tue, 27 Jun 2017 09:05:14 +0200 Lothar Waßmann wrote:
> Hi,
> 
> On Sun, 25 Jun 2017 14:54:56 -0700 Alison Chaiken wrote:
> > On Sun, Jun 18, 2017 at 4:03 AM, Wolfgang Denk <wd@denx.de> wrote:
> > 
> > > Dear Alison,
> > >
> > > In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.
> > > gmail.com> you wrote:
> > > >
> > > > The idea behind the 'swap' mode is that a storage device can have two
> > > sets
> > > > of partitions, one set all named 'primary' and one set all named
> > > 'backup'.
> > > >   The software updater in userspace can then simply rename the partitions
> > > > with sgdisk in order to pick the new image.   The swap mode changes the
> > > > whole set of labels at once, so there's little chance of being
> > > interrupted.
> > >
> > > It's still a sequential, non-atomic operation, and "little chance"
> > > is exactly the places where Murphy likes to hit you.
> > >
> > > > One additional note: the last version I posted worked fine for the
> > > sandbox,
> > > > but wouldn't link for an ARM target with the Linaro toolchain, as the
> > > > linker couldn't find atoi().   I guess the libc for the x86 compiler
> > > > includes it.   To test on ARM, I copied in simple_atoi() from
> > > > lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone
> > > have
> > > > a better idea to solve this problem?
> > >
> > > U-Boot should always be self-contained and not link regular library
> > > code from the tool chain.
> > >
> > > Best regards,
> > >
> > > Wolfgang Denk
> > >
> > 
> > I'm about to submit a new version of the patches that adopts Wolfgang's and
> > Tom's suggestions about replacing atoi().
> > 
> > Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first
> > modifies the names in an in-memory
> > data structure, and then uses the existing 'gpt write' functionality to
> > change the actual partition table stored on the device.  Thus,
> > interruption of the new command is low-risk, as interruption of the
> > modification of the new data structure has no persistent effect, and
> > the risk associated with 'gpt write' is the same as always.
> > 
> > By the way, in the course of testing an earlier version of this patch
> > series, I noticed that 'gpt write' and 'gpt verify' segv if presented with
> > a non-null-terminated partitions string.  It's the strlen function in lib
> > that actually generates an error. I haven't yet quite figured out what the
> > best solution to the problem is: should strlen() itself be modified, or is
> > it enough to test in gpt.c?   The right solution is not to present the
> > commands with poorly formed strings, but it's easy to do so.
> > 
> You can use strnlen() if you know the maximum allowed length of the
> string.
> 
> NB: A quick glance at set_gpt_info() revealed this potential crash
> cause:
> |	str = strdup(str_part);
> |
> |	/* extract disk guid */
> |	s = str;
> |	val = extract_val(str, "uuid_disk");
> strdup() may fail (especially if the input string is not zero
> terminated) and return a NULL pointer which then will happily be used
> by extract_val().
> 

There are some more highlights in this code:
|		*str_disk_guid = malloc(UUID_STR_LEN + 1);
|		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
>
malloc() can fail too.


|		*str_disk_guid = strdup(p);
|		free(val);
|		/* Move s to first partition */
|		strsep(&s, ";");
>
if strdup() fails, *str_disk_guid will be a NULL pointer, but the
function will return success eventually and the NULL pointer will
be passed on to subsequent functions without further checks.


|static bool found_key(const char *str, const char *key)
|{
|	char *k;
|	char *s, *strcopy;
|	bool result = false;
|
|	strcopy = strdup(str);
|	if (!strcopy)
|		return NULL;
>
The function has a bool return type, but returns a pointer type here.
This accidentally works as expected.



Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-06-27  7:05                             ` Lothar Waßmann
  2017-06-27  9:12                               ` Lothar Waßmann
@ 2017-07-01 22:36                               ` Alison Chaiken
  2017-07-03  6:40                                 ` Lothar Waßmann
  1 sibling, 1 reply; 116+ messages in thread
From: Alison Chaiken @ 2017-07-01 22:36 UTC (permalink / raw)
  To: u-boot

On Tue, Jun 27, 2017 at 12:05 AM, Lothar Waßmann <LW@karo-electronics.de> wrote:
>
> Hi,
>
> On Sun, 25 Jun 2017 14:54:56 -0700 Alison Chaiken wrote:
> > On Sun, Jun 18, 2017 at 4:03 AM, Wolfgang Denk <wd@denx.de> wrote:
> >
> > > Dear Alison,
> > >
> > > In message <CAOuSAjdHerD7iWSwv5HQmx07nALRHschnH5=XToNEZDqA9JsvQ@mail.
> > > gmail.com> you wrote:
> > > >
> > > > The idea behind the 'swap' mode is that a storage device can have two
> > > sets
> > > > of partitions, one set all named 'primary' and one set all named
> > > 'backup'.
> > > >   The software updater in userspace can then simply rename the partitions
> > > > with sgdisk in order to pick the new image.   The swap mode changes the
> > > > whole set of labels at once, so there's little chance of being
> > > interrupted.
> > >
> > > It's still a sequential, non-atomic operation, and "little chance"
> > > is exactly the places where Murphy likes to hit you.
> > >
> > > > One additional note: the last version I posted worked fine for the
> > > sandbox,
> > > > but wouldn't link for an ARM target with the Linaro toolchain, as the
> > > > linker couldn't find atoi().   I guess the libc for the x86 compiler
> > > > includes it.   To test on ARM, I copied in simple_atoi() from
> > > > lib/vsprintf.c, but assuredly that is an ugly solution.    Does anyone
> > > have
> > > > a better idea to solve this problem?
> > >
> > > U-Boot should always be self-contained and not link regular library
> > > code from the tool chain.
> > >
> > > Best regards,
> > >
> > > Wolfgang Denk
> > >
> >
> > I'm about to submit a new version of the patches that adopts Wolfgang's and
> > Tom's suggestions about replacing atoi().
> >
> > Regarding the atomicity of 'gpt swap, the point is that 'gpt swap' first
> > modifies the names in an in-memory
> > data structure, and then uses the existing 'gpt write' functionality to
> > change the actual partition table stored on the device.  Thus,
> > interruption of the new command is low-risk, as interruption of the
> > modification of the new data structure has no persistent effect, and
> > the risk associated with 'gpt write' is the same as always.
> >
> > By the way, in the course of testing an earlier version of this patch
> > series, I noticed that 'gpt write' and 'gpt verify' segv if presented with
> > a non-null-terminated partitions string.  It's the strlen function in lib
> > that actually generates an error. I haven't yet quite figured out what the
> > best solution to the problem is: should strlen() itself be modified, or is
> > it enough to test in gpt.c?   The right solution is not to present the
> > commands with poorly formed strings, but it's easy to do so.
> >
> You can use strnlen() if you know the maximum allowed length of the
> string.

Thanks for that tip: I didn't know that strnlen() existed.   That
indeed seems like a good protection against at least the problems
identified here.

>
> NB: A quick glance at set_gpt_info() revealed this potential crash
> cause:
> |       str = strdup(str_part);
> |
> |       /* extract disk guid */
> |       s = str;
> |       val = extract_val(str, "uuid_disk");
> strdup() may fail (especially if the input string is not zero
> terminated) and return a NULL pointer which then will happily be used
> by extract_val().
>
>
>
> Lothar Waßmann

The underlying cause of the problem is that u-boot's implementations
of strlen() and the CLI handle strings differently.   The former
terminates strings only on NULLs, while the latter terminates strings
*either* on NULLs or on semicolons.    Reading the partition table
back from a device's GPT results in a string with a NULL only at the
very end, but with one semicolon per partition.   Running 'gpt verify
mmc 0 $partitions" or 'gpt write mmc 0 $partitions' therefore causes a
crash if the user has previously typed 'setenv partitions 1;2;3;4;5;'
rather than 'setenv partitions "1;2;3;4;5;"'.   In the former case,
the partitions string ends up being '1' without NULL-termination,
resulting in the crash.

U-boot environment parameters often have lots of semi-colon-separated
lists.   I'm not sure what other code paths lead to strlen() or
strdup(), as Lothar alludes to above, but it seems likely to me that
there are other ways to reproduce this bug.   Looking at lib/string.c,
there are other functions like strcpy() that also check "!= '\0'".

--- Alison

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v8 8/10] GPT: read partition table from device into a data structure
  2017-06-26  7:34                                 ` Lothar Waßmann
@ 2017-07-01 22:42                                   ` alison at peloton-tech.com
  2017-07-03  6:52                                     ` Lothar Waßmann
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-07-01 22:42 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---

Changes since v7:
   The failure-handling logic of get_gpt_info() now is triggered
   properly when valid_part=1.

 cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 126 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 65fb80b..dd5f78b 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,118 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 1, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		new_disk_part = allocate_disk_part(&info, valid_parts);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (valid_parts == 1) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return --valid_parts;
+ out:
+	if (valid_parts >= 2)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +570,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +594,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index c41aa6a..0cd803a 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 09/10] GPT: provide commands to selectively rename partitions
  2017-06-26  7:55                                 ` Lothar Waßmann
@ 2017-07-01 22:44                                   ` alison at peloton-tech.com
  0 siblings, 0 replies; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-07-01 22:44 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via new 'gpt swap'
and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names
are found, or if the number of partitions with one name does not equal
the number with the second name.   The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---

Changes since v7:
  This version removes casts to unsigned long where the
  underlying data type is lbaint_t.  I tested this version both
  with and without CONFIG_SYS_64BIT_LBA, and the output is fine
  in either case.  This version also removes unneeded casts to
  const and restores the gpt command's error reporting to its
  earlier state if CONFIG_GPT_RENAME is unset.

  In addition, there is an additional check that a malloc() has
  succeeded.

 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 doc/README.gpt |  20 ++++-
 3 files changed, 263 insertions(+), 5 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 07b0e3b..ae61b96 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index dd5f78b..73bf273 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,8 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+#include <stdlib.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +196,32 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, lbaint_t partsize,
+				  lbaint_t blksize)
+{
+	unsigned long long partbytes, partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%lluMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, curr->gpt_part_info.start,
+				      curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, curr->gpt_part_info.size,
+                                      curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +233,73 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	       numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid, char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -EINVAL;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		prettyprint_part_size(partstr, curr->gpt_part_info.size,
+                                      curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +311,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -301,6 +389,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -530,6 +620,128 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	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"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts: -ENODEV;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = malloc(partlistlen);
+	if (partitions_list == NULL)
+		return -ENOMEM;
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	/*
+	 * Uncomment the following line to print a string that 'gpt write'
+	 * or 'gpt verify' will accept as input.
+	 */
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				ctr1++;
+			}
+			else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				ctr2++;
+			}
+		}
+		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
+			printf("Cannot swap partition names except in pairs.\n");
+			return -EINVAL;
+		}
+	} else { /* rename */
+		if (strlen(name2) > PART_NAME_LEN) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		partnum = (int)simple_strtol(name1, NULL, 10);
+		if ((partnum < 0) || (partnum > numparts)) {
+			printf("Illegal partition number %s\n", name1);
+			return -EINVAL;
+		}
+		ret = part_get_info(dev_desc, partnum, new_partitions);
+		if (ret < 0)
+			return ret;
+
+		/* U-Boot partition numbering starts@1 */
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts : -ENODEV;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -547,7 +759,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
+#ifndef CONFIG_CMD_GPT_RENAME
 	if (argc < 4 || argc > 5)
+#else
+	if (argc < 4 || argc > 6)
+#endif
 		return CMD_RET_USAGE;
 
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -572,6 +788,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} 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]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -603,4 +824,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\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"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index 6c5ab78..d3db8bc 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings
  2017-06-27  9:12                               ` Lothar Waßmann
@ 2017-07-01 22:44                                 ` alison at peloton-tech.com
  2017-07-03  6:37                                   ` Lothar Waßmann
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-07-01 22:44 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Strings read from devices may sometimes fail to be
NULL-terminated.   The functions in lib/string.c are subject to
failure in this case.   Protect against observed failures in
set_gpt_info() by switching to length-checking variants with a length
limit of the maximum possible partition table length.  At the same
time, add a few checks for NULL string pointers.

Here is an example as observed in sandbox under GDB:

    => gpt verify host 0 $partitions
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    267             for (sc = s; *sc != '\0'; ++sc)
    (gdb) bt
    #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
    str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
    parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
    #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
    #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
    at cmd/gpt.c:783
    #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
    cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
    #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
    repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539

Suggested-by: Lothar Waßmann <LW@karo-electronics.de>
Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 73bf273..8bd7bdf 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -233,7 +233,7 @@ static void print_gpt_info(void)
 	}
 }
 
-#ifdef CONFIG_CMD_GPT_RENAME
+
 static int calc_parts_list_len(int numparts)
 {
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
@@ -253,6 +253,7 @@ static int calc_parts_list_len(int numparts)
 	return partlistlen;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
 /*
  * create the string that upstream 'gpt write' command will accept as an
  * argument
@@ -381,6 +382,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	int errno = 0;
 	uint64_t size_ll, start_ll;
 	lbaint_t offset = 0;
+        int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
 
 	debug("%s:  lba num: 0x%x %d\n", __func__,
 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
@@ -398,6 +400,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
+		if (str_disk_guid == NULL)
+			return -ENOMEM;
 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
 #else
 		free(str);
@@ -412,10 +416,14 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		/* Move s to first partition */
 		strsep(&s, ";");
 	}
-	if (strlen(s) == 0)
+	if (s == NULL) {
+                printf("Error: is the partitions string NULL-terminated?\n");
+		return -EINVAL;
+	}
+	if (strnlen(s, max_str_part) == 0)
 		return -3;
 
-	i = strlen(s) - 1;
+	i = strnlen(s, max_str_part) - 1;
 	if (s[i] == ';')
 		s[i] = '\0';
 
@@ -429,6 +437,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 
 	/* allocate memory for partitions */
 	parts = calloc(sizeof(disk_partition_t), p_count);
+	if (parts == NULL)
+		return -ENOMEM;
 
 	/* retrieve partitions data from string */
 	for (i = 0; i < p_count; i++) {
@@ -450,12 +460,12 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		} else {
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].uuid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
 				printf("Wrong uuid format for partition %d\n", i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].uuid, p);
+			strncpy((char *)parts[i].uuid, p, max_str_part);
 			free(val);
 		}
 #ifdef CONFIG_PARTITION_TYPE_GUID
@@ -465,13 +475,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 			/* 'type' is optional */
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].type_guid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
 				printf("Wrong type guid format for partition %d\n",
 				       i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].type_guid, p);
+			strncpy((char *)parts[i].type_guid, p, max_str_part);
 			free(val);
 		}
 #endif
@@ -483,11 +493,11 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		}
 		if (extract_env(val, &p))
 			p = val;
-		if (strlen(p) >= sizeof(parts[i].name)) {
+		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
 			errno = -4;
 			goto err;
 		}
-		strcpy((char *)parts[i].name, p);
+		strncpy((char *)parts[i].name, p, max_str_part);
 		free(val);
 
 		/* size */
-- 
2.1.4

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings
  2017-07-01 22:44                                 ` [U-Boot] [PATCH 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings alison at peloton-tech.com
@ 2017-07-03  6:37                                   ` Lothar Waßmann
  2017-07-04 18:19                                     ` [U-Boot] [PATCH v2 " alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-07-03  6:37 UTC (permalink / raw)
  To: u-boot

Hi,

On Sat,  1 Jul 2017 15:44:44 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Strings read from devices may sometimes fail to be
> NULL-terminated.   The functions in lib/string.c are subject to
> failure in this case.   Protect against observed failures in
> set_gpt_info() by switching to length-checking variants with a length
> limit of the maximum possible partition table length.  At the same
> time, add a few checks for NULL string pointers.
> 
> Here is an example as observed in sandbox under GDB:
> 
>     => gpt verify host 0 $partitions
>     Program received signal SIGSEGV, Segmentation fault.
>     0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
>     267             for (sc = s; *sc != '\0'; ++sc)
>     (gdb) bt
>     #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
>     #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
>     str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
>     parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
>     #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
>     #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
>     at cmd/gpt.c:783
>     #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
>     cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
>     #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
>     repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539
> 
> Suggested-by: Lothar Waßmann <LW@karo-electronics.de>
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
>  cmd/gpt.c | 28 +++++++++++++++++++---------
>  1 file changed, 19 insertions(+), 9 deletions(-)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 73bf273..8bd7bdf 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
> @@ -233,7 +233,7 @@ static void print_gpt_info(void)
>  	}
>  }
>  
> -#ifdef CONFIG_CMD_GPT_RENAME
> +
>  static int calc_parts_list_len(int numparts)
>  {
>  	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
> @@ -253,6 +253,7 @@ static int calc_parts_list_len(int numparts)
>  	return partlistlen;
>  }
>  
> +#ifdef CONFIG_CMD_GPT_RENAME
>  /*
>   * create the string that upstream 'gpt write' command will accept as an
>   * argument
> @@ -381,6 +382,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  	int errno = 0;
>  	uint64_t size_ll, start_ll;
>  	lbaint_t offset = 0;
> +        int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
>
indentation should use tabs not spaces (scripts/checkpatch.pl would tell
you).
  
>  	debug("%s:  lba num: 0x%x %d\n", __func__,
>  	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
> @@ -398,6 +400,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  	if (!val) {
>  #ifdef CONFIG_RANDOM_UUID
>  		*str_disk_guid = malloc(UUID_STR_LEN + 1);
> +		if (str_disk_guid == NULL)
> +			return -ENOMEM;
>  		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
>  #else
>  		free(str);
> @@ -412,10 +416,14 @@ static int set_gpt_info(struct blk_desc *dev_desc,
>  		/* Move s to first partition */
>  		strsep(&s, ";");
>  	}
> -	if (strlen(s) == 0)
> +	if (s == NULL) {
> +                printf("Error: is the partitions string NULL-terminated?\n");
> +		return -EINVAL;
>
dto.



Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions
  2017-07-01 22:36                               ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions Alison Chaiken
@ 2017-07-03  6:40                                 ` Lothar Waßmann
  2017-07-04 18:19                                   ` [U-Boot] [PATCH v8 09/10] " alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-07-03  6:40 UTC (permalink / raw)
  To: u-boot

Hi,

> The underlying cause of the problem is that u-boot's implementations
> of strlen() and the CLI handle strings differently.   The former
>
"u-boot's implementation" is conformant with the standard and well
documented libc implementation that exists since the dawn of C
programming.

> terminates strings only on NULLs, while the latter terminates strings
> *either* on NULLs or on semicolons.    Reading the partition table
> back from a device's GPT results in a string with a NULL only at the
> very end, but with one semicolon per partition.   Running 'gpt verify
> mmc 0 $partitions" or 'gpt write mmc 0 $partitions' therefore causes a
> crash if the user has previously typed 'setenv partitions 1;2;3;4;5;'
> rather than 'setenv partitions "1;2;3;4;5;"'.   In the former case,
> the partitions string ends up being '1' without NULL-termination,
>
That's nonsense. _Every_ string in the environment is NULL terminated.
In the former case of your example the characters after the first
semicolon are interpreted as commands and lead to an error message
Unknown command '2' - try 'help'
...
because the ';' is treated as a command terminator by the parser
unless quoted.


Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v8 8/10] GPT: read partition table from device into a data structure
  2017-07-01 22:42                                   ` [U-Boot] [PATCH v8 8/10] " alison at peloton-tech.com
@ 2017-07-03  6:52                                     ` Lothar Waßmann
  2017-07-04 18:18                                       ` [U-Boot] [PATCH v8 08/10] " alison at peloton-tech.com
  0 siblings, 1 reply; 116+ messages in thread
From: Lothar Waßmann @ 2017-07-03  6:52 UTC (permalink / raw)
  To: u-boot

Hi,

On Sat,  1 Jul 2017 15:42:57 -0700 alison at peloton-tech.com wrote:
> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
> ---
> 
> Changes since v7:
>    The failure-handling logic of get_gpt_info() now is triggered
>    properly when valid_part=1.
> 
>  cmd/gpt.c      | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  include/part.h |   7 ++++
>  2 files changed, 126 insertions(+)
> 
> diff --git a/cmd/gpt.c b/cmd/gpt.c
> index 65fb80b..dd5f78b 100644
> --- a/cmd/gpt.c
> +++ b/cmd/gpt.c
[...]
> +static int get_gpt_info(struct blk_desc *dev_desc)
> +{
> +	/* start partition numbering at 1, as U-Boot does */
> +	int valid_parts = 1, p, ret;
> +	disk_partition_t info;
> +	struct disk_part *new_disk_part;
> +
> +	if (disk_partitions.next == NULL)
> +		INIT_LIST_HEAD(&disk_partitions);
> +
> +	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
> +		ret = part_get_info(dev_desc, p, &info);
> +		if (ret)
> +			continue;
> +
> +		new_disk_part = allocate_disk_part(&info, valid_parts);
> +		if (IS_ERR(new_disk_part))
> +			goto out;
> +
> +		list_add_tail(&new_disk_part->list, &disk_partitions);
> +		valid_parts++;
> +	}
> +	if (valid_parts == 1) {
> +		printf("** No valid partitions found **\n");
> +		goto out;
> +	}
> +	return --valid_parts;
>
I personally find it somewhat strange to initialize a counter to 1 and
then return its value reduced by one, rather than initializing it to 0
and returning the exact counter value.



Lothar Waßmann

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v8 08/10] GPT: read partition table from device into a data structure
  2017-07-03  6:52                                     ` Lothar Waßmann
@ 2017-07-04 18:18                                       ` alison at peloton-tech.com
  2017-08-07 13:55                                         ` [U-Boot] [U-Boot, v8, " Tom Rini
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-07-04 18:18 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Make the partition table available for modification by reading it from
the user-specified device into a linked list.   Provide an accessor
function for command-line testing.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---
 cmd/gpt.c      | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/part.h |   7 ++++
 2 files changed, 128 insertions(+)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index 65fb80b3df..8457b80757 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c

Changes since v7:
  -- Made counter in get_gpt_info() start at 0 rather than 1.
  -- Checkpatch cleanup.

@@ -19,6 +19,9 @@
 #include <linux/ctype.h>
 #include <div64.h>
 #include <memalign.h>
+#include <linux/compat.h>
+
+static LIST_HEAD(disk_partitions);
 
 /**
  * extract_env(): Expand env name from string format '&{env_name}'
@@ -151,6 +154,120 @@ static bool found_key(const char *str, const char *key)
 	return result;
 }
 
+static void del_gpt_info(void)
+{
+	struct list_head *pos = &disk_partitions;
+	struct disk_part *curr;
+	while (!list_empty(pos)) {
+		curr = list_entry(pos->next, struct disk_part, list);
+		list_del(pos->next);
+		free(curr);
+	}
+}
+
+static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
+{
+	struct disk_part *newpart;
+	newpart = malloc(sizeof(*newpart));
+	if (!newpart)
+		return ERR_PTR(-ENOMEM);
+	memset(newpart, '\0', sizeof(newpart));
+
+	newpart->gpt_part_info.start = info->start;
+	newpart->gpt_part_info.size = info->size;
+	newpart->gpt_part_info.blksz = info->blksz;
+	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
+		PART_NAME_LEN);
+	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
+	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
+		PART_TYPE_LEN);
+	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
+	newpart->gpt_part_info.bootable = info->bootable;
+#ifdef CONFIG_PARTITION_UUIDS
+	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
+		UUID_STR_LEN);
+	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
+	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
+#endif
+	newpart->partnum = partnum;
+
+	return newpart;
+}
+
+static void print_gpt_info(void)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		printf("Partition %d:\n", curr->partnum);
+		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
+		       (unsigned)curr->gpt_part_info.size);
+		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
+		       curr->gpt_part_info.name);
+		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
+		       curr->gpt_part_info.bootable);
+#ifdef CONFIG_PARTITION_UUIDS
+		printf("UUID %s\n", curr->gpt_part_info.uuid);
+#endif
+		printf("\n");
+	}
+}
+
+/*
+ * read partition info into disk_partitions list where
+ * it can be printed or modified
+ */
+static int get_gpt_info(struct blk_desc *dev_desc)
+{
+	/* start partition numbering at 1, as U-Boot does */
+	int valid_parts = 0, p, ret;
+	disk_partition_t info;
+	struct disk_part *new_disk_part;
+
+	if (disk_partitions.next == NULL)
+		INIT_LIST_HEAD(&disk_partitions);
+
+	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+		ret = part_get_info(dev_desc, p, &info);
+		if (ret)
+			continue;
+
+		/* Add 1 here because counter is zero-based but p1 is
+		   the first partition */
+		new_disk_part = allocate_disk_part(&info, valid_parts+1);
+		if (IS_ERR(new_disk_part))
+			goto out;
+
+		list_add_tail(&new_disk_part->list, &disk_partitions);
+		valid_parts++;
+	}
+	if (valid_parts == 0) {
+		printf("** No valid partitions found **\n");
+		goto out;
+	}
+	return valid_parts;
+ out:
+	if (valid_parts >= 1)
+		del_gpt_info();
+	return -ENODEV;
+}
+
+/* a wrapper to test get_gpt_info */
+static int do_get_gpt_info(struct blk_desc *dev_desc)
+{
+	int ret;
+
+	ret = get_gpt_info(dev_desc);
+	if (ret > 0) {
+		print_gpt_info();
+		del_gpt_info();
+		return 0;
+	}
+	return ret;
+}
+
 /**
  * set_gpt_info(): Fill partition information from string
  *		function allocates memory, remember to free!
@@ -455,6 +572,8 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		printf("Verify GPT: ");
 	} else if (strcmp(argv[1], "guid") == 0) {
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
+	} else if (strcmp(argv[1], "read") == 0) {
+		ret = do_get_gpt_info(blk_dev_desc);
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -477,6 +596,8 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt write mmc 0 $partitions\n"
 	" gpt verify mmc 0 $partitions\n"
+	" read <interface> <dev>\n"
+	"    - read GPT into a data structure for manipulation\n"
 	" guid <interface> <dev>\n"
 	"    - print disk GUID\n"
 	" guid <interface> <dev> <varname>\n"
diff --git a/include/part.h b/include/part.h
index c41aa6adc2..0cd803a933 100644
--- a/include/part.h
+++ b/include/part.h
@@ -10,6 +10,7 @@
 #include <blk.h>
 #include <ide.h>
 #include <uuid.h>
+#include <linux/list.h>
 
 struct block_drvr {
 	char *name;
@@ -69,6 +70,12 @@ typedef struct disk_partition {
 #endif
 } disk_partition_t;
 
+struct disk_part {
+	int partnum;
+	disk_partition_t gpt_part_info;
+	struct list_head list;
+};
+
 /* Misc _get_dev functions */
 #ifdef CONFIG_PARTITIONS
 /**
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v8 09/10] GPT: provide commands to selectively rename partitions
  2017-07-03  6:40                                 ` Lothar Waßmann
@ 2017-07-04 18:19                                   ` alison at peloton-tech.com
  2017-08-07 13:55                                     ` [U-Boot] [U-Boot, v8, " Tom Rini
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-07-04 18:19 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

This patch provides support in u-boot for renaming GPT
partitions.  The renaming is accomplished via new 'gpt swap'
and 'gpt rename' commands.

The 'swap' mode returns an error if no matching partition names
are found, or if the number of partitions with one name does not equal
the number with the second name.   The 'rename' variant always
succeeds as long as a partition with the provided number exists.

Rewriting the partition table has the side-effect that all partitions
end up with "msftdata" flag set.  The reason is that partition type
PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
function.  This does not appear to cause any harm.

Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---

Changes since v7:
  -- Checkpatch cleanups.

 cmd/Kconfig    |   8 ++
 cmd/gpt.c      | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 doc/README.gpt |  20 ++++-
 3 files changed, 264 insertions(+), 5 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 6758db16f3..8d6fcb576d 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -595,6 +595,14 @@ config CMD_GPT
 	  Enable the 'gpt' command to ready and write GPT style partition
 	  tables.
 
+config CMD_GPT_RENAME
+	bool "GPT partition renaming commands"
+	depends on CMD_GPT
+	help
+	  Enables the 'gpt' command to interchange names on two GPT
+	  partitions via the 'gpt swap' command or to rename single
+	  partitions via the 'rename' command.
+
 config CMD_ARMFLASH
 	#depends on FLASH_CFI_DRIVER
 	bool "armflash"
diff --git a/cmd/gpt.c b/cmd/gpt.c
index 8457b80757..d703385a24 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -20,6 +20,8 @@
 #include <div64.h>
 #include <memalign.h>
 #include <linux/compat.h>
+#include <linux/sizes.h>
+#include <stdlib.h>
 
 static LIST_HEAD(disk_partitions);
 
@@ -194,16 +196,32 @@ static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
 	return newpart;
 }
 
+static void prettyprint_part_size(char *sizestr, lbaint_t partsize,
+				  lbaint_t blksize)
+{
+	unsigned long long partbytes, partmegabytes;
+
+	partbytes = partsize * blksize;
+	partmegabytes = lldiv(partbytes, SZ_1M);
+	snprintf(sizestr, 16, "%lluMiB", partmegabytes);
+}
+
 static void print_gpt_info(void)
 {
 	struct list_head *pos;
 	struct disk_part *curr;
+	char partstartstr[16];
+	char partsizestr[16];
 
 	list_for_each(pos, &disk_partitions) {
 		curr = list_entry(pos, struct disk_part, list);
+		prettyprint_part_size(partstartstr, curr->gpt_part_info.start,
+				      curr->gpt_part_info.blksz);
+		prettyprint_part_size(partsizestr, curr->gpt_part_info.size,
+				      curr->gpt_part_info.blksz);
+
 		printf("Partition %d:\n", curr->partnum);
-		printf("1st block %x, size %x\n", (unsigned)curr->gpt_part_info.start,
-		       (unsigned)curr->gpt_part_info.size);
+		printf("Start %s, size %s\n", partstartstr, partsizestr);
 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
 		       curr->gpt_part_info.name);
 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
@@ -215,6 +233,75 @@ static void print_gpt_info(void)
 	}
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int calc_parts_list_len(int numparts)
+{
+	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
+	/* for the comma */
+	partlistlen++;
+
+	/* per-partition additions; numparts starts at 1, so this should be correct */
+	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
+	/* 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);
+	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
+	/* for the terminating null */
+	partlistlen++;
+	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
+	      numparts);
+	return partlistlen;
+}
+
+/*
+ * create the string that upstream 'gpt write' command will accept as an
+ * argument
+ *
+ * From doc/README.gpt, Format of partitions layout:
+ *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
+ *	name=kernel,size=60MiB,uuid=...;"
+ * The fields 'name' and 'size' are mandatory for every partition.
+ * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
+ * are optional if CONFIG_RANDOM_UUID is enabled.
+ */
+static int create_gpt_partitions_list(int numparts, const char *guid,
+				      char *partitions_list)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	char partstr[PART_NAME_LEN + 1];
+
+	if (!partitions_list)
+		return -EINVAL;
+
+	strcpy(partitions_list, "uuid_disk=");
+	strncat(partitions_list, guid, UUID_STR_LEN + 1);
+	strcat(partitions_list, ";");
+
+	list_for_each(pos, &disk_partitions) {
+		curr = list_entry(pos, struct disk_part, list);
+		strcat(partitions_list, "name=");
+		strncat(partitions_list, (const char *)curr->gpt_part_info.name,
+			PART_NAME_LEN + 1);
+		strcat(partitions_list, ",start=");
+		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
+				      (unsigned long) curr->gpt_part_info.blksz);
+		/* one extra byte for NULL */
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+		strcat(partitions_list, ",size=");
+		prettyprint_part_size(partstr, curr->gpt_part_info.size,
+				      curr->gpt_part_info.blksz);
+		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
+
+		strcat(partitions_list, ",uuid=");
+		strncat(partitions_list, curr->gpt_part_info.uuid,
+			UUID_STR_LEN + 1);
+		strcat(partitions_list, ";");
+	}
+	return 0;
+}
+#endif
+
 /*
  * read partition info into disk_partitions list where
  * it can be printed or modified
@@ -226,8 +313,11 @@ static int get_gpt_info(struct blk_desc *dev_desc)
 	disk_partition_t info;
 	struct disk_part *new_disk_part;
 
-	if (disk_partitions.next == NULL)
-		INIT_LIST_HEAD(&disk_partitions);
+	/*
+	 * Always re-read partition info from device, in case
+	 * it has changed
+	 */
+	INIT_LIST_HEAD(&disk_partitions);
 
 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
 		ret = part_get_info(dev_desc, p, &info);
@@ -303,6 +393,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		return -1;
 
 	str = strdup(str_part);
+	if (str == NULL)
+		return -ENOMEM;
 
 	/* extract disk guid */
 	s = str;
@@ -532,6 +624,127 @@ static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
+static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
+			       char *name1, char *name2)
+{
+	struct list_head *pos;
+	struct disk_part *curr;
+	disk_partition_t *new_partitions = NULL;
+	char disk_guid[UUID_STR_LEN + 1];
+	char *partitions_list, *str_disk_guid;
+	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"))))
+		return -EINVAL;
+
+	ret = get_disk_guid(dev_desc, disk_guid);
+	if (ret < 0)
+		return ret;
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts : -ENODEV;
+
+	partlistlen = calc_parts_list_len(numparts);
+	partitions_list = malloc(partlistlen);
+	if (partitions_list == NULL)
+		return -ENOMEM;
+	memset(partitions_list, '\0', partlistlen);
+
+	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	/*
+	 * Uncomment the following line to print a string that 'gpt write'
+	 * or 'gpt verify' will accept as input.
+	 */
+	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	if (!strcmp(subcomm, "swap")) {
+		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				ctr1++;
+			} else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
+				strcpy((char *)curr->gpt_part_info.name, name1);
+				ctr2++;
+			}
+		}
+		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
+			printf("Cannot swap partition names except in pairs.\n");
+			return -EINVAL;
+		}
+	} else { /* rename */
+		if (strlen(name2) > PART_NAME_LEN) {
+			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
+			return -EINVAL;
+		}
+		partnum = (int)simple_strtol(name1, NULL, 10);
+		if ((partnum < 0) || (partnum > numparts)) {
+			printf("Illegal partition number %s\n", name1);
+			return -EINVAL;
+		}
+		ret = part_get_info(dev_desc, partnum, new_partitions);
+		if (ret < 0)
+			return ret;
+
+		/* U-Boot partition numbering starts@1 */
+		list_for_each(pos, &disk_partitions) {
+			curr = list_entry(pos, struct disk_part, list);
+			if (i == partnum) {
+				strcpy((char *)curr->gpt_part_info.name, name2);
+				break;
+			}
+			i++;
+		}
+	}
+
+	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
+	if (ret < 0)
+		return ret;
+	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
+	      (unsigned)strlen(partitions_list));
+
+	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
+			   &new_partitions, &part_count);
+	if (ret < 0)
+		return ret;
+
+	debug("Writing new partition table\n");
+	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
+	if (ret < 0) {
+		printf("Writing new partition table failed\n");
+		return ret;
+	}
+
+	debug("Reading back new partition table\n");
+	numparts = get_gpt_info(dev_desc);
+	if (numparts <=  0)
+		return numparts ? numparts : -ENODEV;
+	printf("new partition table with %d partitions is:\n", numparts);
+	print_gpt_info();
+
+	del_gpt_info();
+	free(partitions_list);
+	free(str_disk_guid);
+	free(new_partitions);
+	return ret;
+}
+#endif
+
 /**
  * do_gpt(): Perform GPT operations
  *
@@ -549,7 +762,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	char *ep;
 	struct blk_desc *blk_dev_desc = NULL;
 
+#ifndef CONFIG_CMD_GPT_RENAME
 	if (argc < 4 || argc > 5)
+#else
+	if (argc < 4 || argc > 6)
+#endif
 		return CMD_RET_USAGE;
 
 	dev = (int)simple_strtoul(argv[3], &ep, 10);
@@ -574,6 +791,11 @@ static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		ret = do_disk_guid(blk_dev_desc, argv[4]);
 	} else if (strcmp(argv[1], "read") == 0) {
 		ret = do_get_gpt_info(blk_dev_desc);
+#ifdef CONFIG_CMD_GPT_RENAME
+	} 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]);
+#endif
 	} else {
 		return CMD_RET_USAGE;
 	}
@@ -605,4 +827,15 @@ U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
 	" Example usage:\n"
 	" gpt guid mmc 0\n"
 	" gpt guid mmc 0 varname\n"
+#ifdef CONFIG_CMD_GPT_RENAME
+	"gpt partition renaming commands:\n"
+	"gpt swap <interface> <dev> <name1> <name2>\n"
+	"    - change all partitions named name1 to name2\n"
+	"      and vice-versa\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"
+#endif
 );
diff --git a/doc/README.gpt b/doc/README.gpt
index 6c5ab7858a..d3db8bce1c 100644
--- a/doc/README.gpt
+++ b/doc/README.gpt
@@ -210,6 +210,24 @@ Following line can be used to assess if GPT verification has succeed:
 U-BOOT> gpt verify mmc 0 $partitions
 U-BOOT> if test $? = 0; then echo "GPT OK"; else echo "GPT ERR"; fi
 
+Renaming GPT partitions from U-Boot:
+====================================
+
+GPT partition names are a mechanism via which userspace and U-Boot can
+communicate about software updates and boot failure.  The 'gpt guid',
+'gpt read', 'gpt rename' and 'gpt swap' commands facilitate
+programmatic renaming of partitions from bootscripts by generating and
+modifying the partitions layout string.  Here is an illustration of
+employing 'swap' to exchange 'primary' and 'backup' partition names:
+
+U-BOOT> gpt swap mmc 0 primary backup
+
+Afterwards, all partitions previously named 'primary' will be named
+'backup', and vice-versa.  Alternatively, single partitions may be
+renamed.  In this example, mmc0's first partition will be renamed
+'primary':
+
+U-BOOT> gpt rename mmc 0 1 primary
 
 The GPT functionality may be tested with the 'sandbox' board by
 creating a disk image as described under 'Block Device Emulation' in
@@ -218,7 +236,7 @@ board/sandbox/README.sandbox:
 =>host bind 0 ./disk.raw
 => gpt read host 0
 [ . . . ]
-=> gpt flip host 0
+=> gpt swap host 0 name othername
 [ . . . ]
 
 Partition type GUID:
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings
  2017-07-03  6:37                                   ` Lothar Waßmann
@ 2017-07-04 18:19                                     ` alison at peloton-tech.com
  2017-08-07 13:55                                       ` [U-Boot] [U-Boot, v2, " Tom Rini
  0 siblings, 1 reply; 116+ messages in thread
From: alison at peloton-tech.com @ 2017-07-04 18:19 UTC (permalink / raw)
  To: u-boot

From: Alison Chaiken <alison@peloton-tech.com>

Strings read from devices may sometimes fail to be
NULL-terminated.   The functions in lib/string.c are subject to
failure in this case.   Protect against observed failures in
set_gpt_info() by switching to length-checking variants with a length
limit of the maximum possible partition table length.  At the same
time, add a few checks for NULL string pointers.

Here is an example as observed in sandbox under GDB:

    => gpt verify host 0 $partitions
    Program received signal SIGSEGV, Segmentation fault.
    0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    267             for (sc = s; *sc != '\0'; ++sc)
    (gdb) bt
    #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
    #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
    str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
    parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
    #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
    #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
    at cmd/gpt.c:783
    #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
    cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
    #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
    repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539

Suggested-by: Lothar Waßmann <LW@karo-electronics.de>
Signed-off-by: Alison Chaiken <alison@peloton-tech.com>
---

Changes since v1:
  -- Checkpatch cleanups.


 cmd/gpt.c | 28 +++++++++++++++++++---------
 1 file changed, 19 insertions(+), 9 deletions(-)

diff --git a/cmd/gpt.c b/cmd/gpt.c
index d703385a24..f8f35c23e0 100644
--- a/cmd/gpt.c
+++ b/cmd/gpt.c
@@ -233,7 +233,7 @@ static void print_gpt_info(void)
 	}
 }
 
-#ifdef CONFIG_CMD_GPT_RENAME
+
 static int calc_parts_list_len(int numparts)
 {
 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
@@ -253,6 +253,7 @@ static int calc_parts_list_len(int numparts)
 	return partlistlen;
 }
 
+#ifdef CONFIG_CMD_GPT_RENAME
 /*
  * create the string that upstream 'gpt write' command will accept as an
  * argument
@@ -385,6 +386,7 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	int errno = 0;
 	uint64_t size_ll, start_ll;
 	lbaint_t offset = 0;
+	int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
 
 	debug("%s:  lba num: 0x%x %d\n", __func__,
 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
@@ -402,6 +404,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 	if (!val) {
 #ifdef CONFIG_RANDOM_UUID
 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
+		if (str_disk_guid == NULL)
+			return -ENOMEM;
 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
 #else
 		free(str);
@@ -416,10 +420,14 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		/* Move s to first partition */
 		strsep(&s, ";");
 	}
-	if (strlen(s) == 0)
+	if (s == NULL) {
+		printf("Error: is the partitions string NULL-terminated?\n");
+		return -EINVAL;
+	}
+	if (strnlen(s, max_str_part) == 0)
 		return -3;
 
-	i = strlen(s) - 1;
+	i = strnlen(s, max_str_part) - 1;
 	if (s[i] == ';')
 		s[i] = '\0';
 
@@ -433,6 +441,8 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 
 	/* allocate memory for partitions */
 	parts = calloc(sizeof(disk_partition_t), p_count);
+	if (parts == NULL)
+		return -ENOMEM;
 
 	/* retrieve partitions data from string */
 	for (i = 0; i < p_count; i++) {
@@ -454,12 +464,12 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		} else {
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].uuid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
 				printf("Wrong uuid format for partition %d\n", i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].uuid, p);
+			strncpy((char *)parts[i].uuid, p, max_str_part);
 			free(val);
 		}
 #ifdef CONFIG_PARTITION_TYPE_GUID
@@ -469,13 +479,13 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 			/* 'type' is optional */
 			if (extract_env(val, &p))
 				p = val;
-			if (strlen(p) >= sizeof(parts[i].type_guid)) {
+			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
 				printf("Wrong type guid format for partition %d\n",
 				       i);
 				errno = -4;
 				goto err;
 			}
-			strcpy((char *)parts[i].type_guid, p);
+			strncpy((char *)parts[i].type_guid, p, max_str_part);
 			free(val);
 		}
 #endif
@@ -487,11 +497,11 @@ static int set_gpt_info(struct blk_desc *dev_desc,
 		}
 		if (extract_env(val, &p))
 			p = val;
-		if (strlen(p) >= sizeof(parts[i].name)) {
+		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
 			errno = -4;
 			goto err;
 		}
-		strcpy((char *)parts[i].name, p);
+		strncpy((char *)parts[i].name, p, max_str_part);
 		free(val);
 
 		/* size */
-- 
2.13.2

^ permalink raw reply related	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v7, 1/9] EFI: replace number with UUID_STR_LEN macro
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 1/9] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
@ 2017-08-07 13:54                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:17PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/3ecb51ad/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v7, 2/9] disk_partition: introduce macros for description string lengths
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 2/9] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
@ 2017-08-07 13:54                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:18PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/5cc1ee50/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v7, 3/9] GPT: fix error in partitions string doc
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 3/9] GPT: fix error in partitions string doc alison at peloton-tech.com
@ 2017-08-07 13:54                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:19PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> The existing partitions-list parsing in cmd/gpt.c passes a value
> from gpt_default() to set_gpt_info() that README.gpt suggests
> should begin with 'partitions='.  Partition-list strings should
> in fact begin with 'uuid_disk', as otherwise the call from
> set_gpt_info() to extract_val() to find 'uuid_disk' will fail.
> Change README.gpt accordingly.
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/b77ecd23/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v7, 4/9] sandbox: README: fix partition command invocation
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 4/9] sandbox: README: fix partition command invocation alison at peloton-tech.com
@ 2017-08-07 13:54                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:20PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> The instructions for creating a disk image that are presently in
> README.sandbox fail because sfdisk doesn't know about GPT.
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/c10c2e25/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot,v7,5/9] cmd gpt: test in sandbox
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 5/9] cmd gpt: test in sandbox alison at peloton-tech.com
@ 2017-08-07 13:54                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:21PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Make minor changes to README.gpt and sandbox_defconfig to support
> testing of the gpt command's functionality in the sandbox.
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/433e43e0/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v7, 6/9] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 6/9] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
@ 2017-08-07 13:54                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:54 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:22PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Move MAX_SEARCH_PARTITIONS to part.h so that functions in cmd
> directory can find it.  At the same time, increase the value to
> 64 since some operating systems use many, and the resources
> consumed by a larger value are minimal.
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/98a57a06/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v7, 7/9] GPT: add accessor function for disk GUID
  2017-06-25 23:43                               ` [U-Boot] [PATCH v7 7/9] GPT: add accessor function for disk GUID alison at peloton-tech.com
@ 2017-08-07 13:55                                 ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:55 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 25, 2017 at 04:43:23PM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> In order to read the GPT, modify the partition name strings, and then
> write out a new GPT, the disk GUID is needed.  While there is an
> existing accessor for the partition UUIDs, there is none yet for the
> disk GUID.
> 
> Changes since v6: none.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/41b5b6db/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v8, 08/10] GPT: read partition table from device into a data structure
  2017-07-04 18:18                                       ` [U-Boot] [PATCH v8 08/10] " alison at peloton-tech.com
@ 2017-08-07 13:55                                         ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:55 UTC (permalink / raw)
  To: u-boot

On Tue, Jul 04, 2017 at 11:18:50AM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Make the partition table available for modification by reading it from
> the user-specified device into a linked list.   Provide an accessor
> function for command-line testing.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

After changing this to only be adding significant code when
CMD_GPT_RENAME is enabled, applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/43f8eb20/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v8, 09/10] GPT: provide commands to selectively rename partitions
  2017-07-04 18:19                                   ` [U-Boot] [PATCH v8 09/10] " alison at peloton-tech.com
@ 2017-08-07 13:55                                     ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:55 UTC (permalink / raw)
  To: u-boot

On Tue, Jul 04, 2017 at 11:19:18AM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> This patch provides support in u-boot for renaming GPT
> partitions.  The renaming is accomplished via new 'gpt swap'
> and 'gpt rename' commands.
> 
> The 'swap' mode returns an error if no matching partition names
> are found, or if the number of partitions with one name does not equal
> the number with the second name.   The 'rename' variant always
> succeeds as long as a partition with the provided number exists.
> 
> Rewriting the partition table has the side-effect that all partitions
> end up with "msftdata" flag set.  The reason is that partition type
> PARTITION_BASIC_DATA_GUID is hard-coded in the gpt_fill_pte()
> function.  This does not appear to cause any harm.
> 
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/e678c149/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [U-Boot, v2, 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings
  2017-07-04 18:19                                     ` [U-Boot] [PATCH v2 " alison at peloton-tech.com
@ 2017-08-07 13:55                                       ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-07 13:55 UTC (permalink / raw)
  To: u-boot

On Tue, Jul 04, 2017 at 11:19:46AM -0700, Alison Chaiken wrote:

> From: Alison Chaiken <alison@peloton-tech.com>
> 
> Strings read from devices may sometimes fail to be
> NULL-terminated.   The functions in lib/string.c are subject to
> failure in this case.   Protect against observed failures in
> set_gpt_info() by switching to length-checking variants with a length
> limit of the maximum possible partition table length.  At the same
> time, add a few checks for NULL string pointers.
> 
> Here is an example as observed in sandbox under GDB:
> 
>     => gpt verify host 0 $partitions
>     Program received signal SIGSEGV, Segmentation fault.
>     0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
>     267             for (sc = s; *sc != '\0'; ++sc)
>     (gdb) bt
>     #0  0x0000000000477747 in strlen (s=0x0) at lib/string.c:267
>     #1  0x00000000004140b2 in set_gpt_info (str_part=<optimized out>,
>     str_disk_guid=str_disk_guid at entry=0x7fffffffdbe8, partitions=partitions at entry=0x7fffffffdbd8,
>     parts_count=parts_count at entry=0x7fffffffdbcf "", dev_desc=<optimized out>) at cmd/gpt.c:415
>     #2  0x00000000004145b9 in gpt_verify (str_part=<optimized out>, blk_dev_desc=0x7fffef09a9d0) at cmd/gpt.c:580
>     #3  do_gpt (cmdtp=<optimized out>, flag=<optimized out>, argc=<optimized out>, argv=0x7fffef09a8f0)
>     at cmd/gpt.c:783
>     #4  0x00000000004295b0 in cmd_call (argv=0x7fffef09a8f0, argc=0x5, flag=<optimized out>,
>     cmdtp=0x714e20 <_u_boot_list_2_cmd_2_gpt>) at common/command.c:500
>     #5  cmd_process (flag=<optimized out>, argc=0x5, argv=0x7fffef09a8f0,
>     repeatable=repeatable at entry=0x726c04 <flag_repeat>, ticks=ticks at entry=0x0) at common/command.c:539
> 
> Suggested-by: Lothar Waßmann <LW@karo-electronics.de>
> Signed-off-by: Alison Chaiken <alison@peloton-tech.com>

Applied to u-boot/master, thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170807/b9d0644c/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-05-31  8:12       ` Lukasz Majewski
  2017-06-01  7:04         ` Chaiken, Alison
  2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
@ 2017-08-27 23:02         ` Chaiken, Alison
  2017-08-28  7:54           ` Łukasz Majewski
  2 siblings, 1 reply; 116+ messages in thread
From: Chaiken, Alison @ 2017-08-27 23:02 UTC (permalink / raw)
  To: u-boot

On 2017-05-31 01:12, Lukasz Majewski wrote:

[ . . . ]

> And another request -> Could you consider adding tests for those new
> gpt commands to the 'sandbox' (sandbox_defconfig) ?
> 
> Then you can 'mount' some gpt test image ('host' command) and use it
> with:
> gpt <command> host X .....

The GPT functionality really cannot be tested without a block device.   
We could build the disk.raw described in board/sandbox/README.sandbox 
when (CONFIG_UNIT_TEST && CONFIG_CMD_GPT_RENAME) in imitation of the 
file helloworld.efi.   There would be no reason for the size to be as 
large as 1200M, of course.   256KB appears to be the smallest usable 
size for 4 partitions (although trying to partition a 16 KB raw object 
with gdisk produces entertaining results).

To create this object for testing, we could use a subdirectory like 
lib/efi_loader, but maybe doing so in test/ makes more sense?  If the 
build system did create the object, then we could modify 
board/sandbox/README.sandbox to so indicate.   Then the test should go 
in test/py/tests presumably.

Thanks for feedback,
Alison

---
Alison Chaiken                      alison at she-devel.com
http://{ she-devel.com, exerciseforthereader.org }
"We are giving up our privacy, one convenience at a time." -- Evangelos 
Simoudis

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-08-27 23:02         ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure Chaiken, Alison
@ 2017-08-28  7:54           ` Łukasz Majewski
  2017-08-28 11:16             ` Tom Rini
  0 siblings, 1 reply; 116+ messages in thread
From: Łukasz Majewski @ 2017-08-28  7:54 UTC (permalink / raw)
  To: u-boot

On 08/28/2017 01:02 AM, Chaiken, Alison wrote:
> On 2017-05-31 01:12, Lukasz Majewski wrote:
>
> [ . . . ]
>
>> And another request -> Could you consider adding tests for those new
>> gpt commands to the 'sandbox' (sandbox_defconfig) ?
>>
>> Then you can 'mount' some gpt test image ('host' command) and use it
>> with:
>> gpt <command> host X .....
>
> The GPT functionality really cannot be tested without a block device.
> We could build the disk.raw described in board/sandbox/README.sandbox
> when (CONFIG_UNIT_TEST && CONFIG_CMD_GPT_RENAME) in imitation of the
> file helloworld.efi.   There would be no reason for the size to be as
> large as 1200M, of course.   256KB appears to be the smallest usable
> size for 4 partitions (although trying to partition a 16 KB raw object
> with gdisk produces entertaining results).
>
> To create this object for testing, we could use a subdirectory like
> lib/efi_loader, but maybe doing so in test/ makes more sense?  If the
> build system did create the object, then we could modify
> board/sandbox/README.sandbox to so indicate.   Then the test should go
> in test/py/tests presumably.

If you have encountered some issues with adding this test to sandbox 
(and those are difficult to solve), then it would be also correct to add 
this test to test/py and run it on a real HW.

Please also keep in mind to provide some kind of verbose in-code 
description or proper documentation entry.

>
> Thanks for feedback,
> Alison
>
> ---
> Alison Chaiken                      alison at she-devel.com
> http://{ she-devel.com, exerciseforthereader.org }
> "We are giving up our privacy, one convenience at a time." -- Evangelos
> Simoudis
>


-- 
Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply	[flat|nested] 116+ messages in thread

* [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure
  2017-08-28  7:54           ` Łukasz Majewski
@ 2017-08-28 11:16             ` Tom Rini
  0 siblings, 0 replies; 116+ messages in thread
From: Tom Rini @ 2017-08-28 11:16 UTC (permalink / raw)
  To: u-boot

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="windows-1254", Size: 1931 bytes --]

On Mon, Aug 28, 2017 at 09:54:38AM +0200, Łukasz Majewski wrote:
> On 08/28/2017 01:02 AM, Chaiken, Alison wrote:
> >On 2017-05-31 01:12, Lukasz Majewski wrote:
> >
> >[ . . . ]
> >
> >>And another request -> Could you consider adding tests for those new
> >>gpt commands to the 'sandbox' (sandbox_defconfig) ?
> >>
> >>Then you can 'mount' some gpt test image ('host' command) and use it
> >>with:
> >>gpt <command> host X .....
> >
> >The GPT functionality really cannot be tested without a block device.
> >We could build the disk.raw described in board/sandbox/README.sandbox
> >when (CONFIG_UNIT_TEST && CONFIG_CMD_GPT_RENAME) in imitation of the
> >file helloworld.efi.   There would be no reason for the size to be as
> >large as 1200M, of course.   256KB appears to be the smallest usable
> >size for 4 partitions (although trying to partition a 16 KB raw object
> >with gdisk produces entertaining results).
> >
> >To create this object for testing, we could use a subdirectory like
> >lib/efi_loader, but maybe doing so in test/ makes more sense?  If the
> >build system did create the object, then we could modify
> >board/sandbox/README.sandbox to so indicate.   Then the test should go
> >in test/py/tests presumably.
> 
> If you have encountered some issues with adding this test to sandbox
> (and those are difficult to solve), then it would be also correct to
> add this test to test/py and run it on a real HW.

Right.  Everyone can run test.py on sandbox _and_ QEMU, and there are
then some people with labs setup that also run test.py on real hardware.
Between QEMU and real hardware we should be able to add and run tests
for this.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20170828/3b6b97d8/attachment.sig>

^ permalink raw reply	[flat|nested] 116+ messages in thread

end of thread, other threads:[~2017-08-28 11:16 UTC | newest]

Thread overview: 116+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-05-21  2:27 [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation alison at peloton-tech.com
2017-05-21  2:27 ` [U-Boot] [PATCH 1/3] GPT: add accessor function for disk GUID alison at peloton-tech.com
2017-05-26 12:38   ` Tom Rini
2017-05-21  2:27 ` [U-Boot] [PATCH 2/3] GPT: read partition table from device into a data structure alison at peloton-tech.com
2017-05-26 12:39   ` Tom Rini
2017-05-21  2:27 ` [U-Boot] [PATCH 3/3] rename GPT partitions to detect boot failure alison at peloton-tech.com
2017-05-26 12:39   ` Tom Rini
2017-05-29  9:25   ` Lothar Waßmann
2017-05-26 12:38 ` [U-Boot] [PATCH 0/3] add support for GPT partition name manipulation Tom Rini
2017-05-29 16:49   ` [U-Boot] [PATCH v2 0/6] " alison at peloton-tech.com
2017-05-29 16:49     ` [U-Boot] [PATCH v2 1/6] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
2017-05-31  2:07       ` Tom Rini
2017-05-31  7:37       ` Lukasz Majewski
2017-05-29 16:49     ` [U-Boot] [PATCH v2 2/6] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
2017-05-31  7:37       ` Lukasz Majewski
2017-05-31 13:50       ` Tom Rini
2017-05-29 16:49     ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID alison at peloton-tech.com
2017-05-30  6:46       ` Lothar Waßmann
2017-06-03  2:22         ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
2017-06-03  2:22           ` [U-Boot] [PATCH v3 1/5] GPT: add accessor function for disk GUID alison at peloton-tech.com
2017-06-06  8:20             ` Lothar Waßmann
2017-06-10  5:27               ` [U-Boot] [PATCH v5 1/3] " alison at peloton-tech.com
2017-06-11 13:38                 ` Tom Rini
2017-06-03  2:22           ` [U-Boot] [PATCH v3 2/5] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
2017-06-03 11:52             ` Lukasz Majewski
2017-06-03  2:22           ` [U-Boot] [PATCH v3 3/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
2017-06-06  8:28             ` Lothar Waßmann
2017-06-10  5:30               ` [U-Boot] [PATCH v5 2/3] " alison at peloton-tech.com
2017-06-11 13:38                 ` Tom Rini
2017-06-06 10:43             ` [U-Boot] [PATCH v3 3/5] " Lothar Waßmann
2017-06-03  2:22           ` [U-Boot] [PATCH v3 4/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
2017-06-06  8:20             ` Lothar Waßmann
2017-06-10  5:35               ` [U-Boot] [PATCH v5 3/3] " alison at peloton-tech.com
2017-06-10  6:51                 ` Wolfgang Denk
2017-06-10 23:27                   ` Alison Chaiken
2017-06-10 23:33                   ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
2017-06-11 13:38                     ` Tom Rini
2017-06-11 16:03                       ` [U-Boot] [PATCH v7] " alison at peloton-tech.com
2017-06-12  7:45                     ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
2017-06-12 14:24                       ` Alison Chaiken
2017-06-12 14:56                         ` Tom Rini
2017-06-18 11:08                           ` Wolfgang Denk
2017-06-25 23:43                             ` [U-Boot] [PATCH v7 0/9] add support for GPT partition name manipulation alison at peloton-tech.com
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 1/9] EFI: replace number with UUID_STR_LEN macro alison at peloton-tech.com
2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 2/9] disk_partition: introduce macros for description string lengths alison at peloton-tech.com
2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 3/9] GPT: fix error in partitions string doc alison at peloton-tech.com
2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 4/9] sandbox: README: fix partition command invocation alison at peloton-tech.com
2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 5/9] cmd gpt: test in sandbox alison at peloton-tech.com
2017-08-07 13:54                                 ` [U-Boot] [U-Boot,v7,5/9] " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 6/9] partitions: increase MAX_SEARCH_PARTITIONS and move to part.h alison at peloton-tech.com
2017-08-07 13:54                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 7/9] GPT: add accessor function for disk GUID alison at peloton-tech.com
2017-08-07 13:55                                 ` [U-Boot] [U-Boot, v7, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 8/9] GPT: read partition table from device into a data structure alison at peloton-tech.com
2017-06-26  7:34                                 ` Lothar Waßmann
2017-07-01 22:42                                   ` [U-Boot] [PATCH v8 8/10] " alison at peloton-tech.com
2017-07-03  6:52                                     ` Lothar Waßmann
2017-07-04 18:18                                       ` [U-Boot] [PATCH v8 08/10] " alison at peloton-tech.com
2017-08-07 13:55                                         ` [U-Boot] [U-Boot, v8, " Tom Rini
2017-06-25 23:43                               ` [U-Boot] [PATCH v7 9/9] GPT: provide commands to selectively rename partitions alison at peloton-tech.com
2017-06-26  1:52                                 ` Bin Meng
2017-06-26  2:11                                   ` alison at peloton-tech.com
2017-06-26  7:55                                 ` Lothar Waßmann
2017-07-01 22:44                                   ` [U-Boot] [PATCH 09/10] " alison at peloton-tech.com
2017-06-18 11:03                         ` [U-Boot] [PATCH v6 3/3] " Wolfgang Denk
2017-06-25 21:54                           ` Alison Chaiken
2017-06-26 22:47                             ` Tom Rini
2017-06-27  7:05                             ` Lothar Waßmann
2017-06-27  9:12                               ` Lothar Waßmann
2017-07-01 22:44                                 ` [U-Boot] [PATCH 10/10] gpt: harden set_gpt_info() against non NULL-terminated strings alison at peloton-tech.com
2017-07-03  6:37                                   ` Lothar Waßmann
2017-07-04 18:19                                     ` [U-Boot] [PATCH v2 " alison at peloton-tech.com
2017-08-07 13:55                                       ` [U-Boot] [U-Boot, v2, " Tom Rini
2017-07-01 22:36                               ` [U-Boot] [PATCH v6 3/3] GPT: provide commands to selectively rename partitions Alison Chaiken
2017-07-03  6:40                                 ` Lothar Waßmann
2017-07-04 18:19                                   ` [U-Boot] [PATCH v8 09/10] " alison at peloton-tech.com
2017-08-07 13:55                                     ` [U-Boot] [U-Boot, v8, " Tom Rini
2017-06-03  2:22           ` [U-Boot] [PATCH v3 5/5] GPT: fix error in partitions string doc alison at peloton-tech.com
2017-06-03 11:48           ` [U-Boot] [PATCH v3 0/5] add support for GPT partition name manipulation Lukasz Majewski
2017-05-31  7:44       ` [U-Boot] [PATCH v2 3/6] GPT: add accessor function for disk GUID Lukasz Majewski
2017-05-31  8:47         ` Lothar Waßmann
2017-05-29 16:49     ` [U-Boot] [PATCH v2 4/6] GPT: read partition table from device into a data structure alison at peloton-tech.com
2017-05-30  7:37       ` Lothar Waßmann
2017-06-01  6:34         ` Chaiken, Alison
2017-06-01  9:48           ` Lothar Waßmann
2017-05-31  7:48       ` Lukasz Majewski
2017-05-31  8:48         ` Lothar Waßmann
2017-05-31 11:11           ` Lukasz Majewski
2017-05-31 13:42             ` Lothar Waßmann
2017-05-31 14:07         ` Lukasz Majewski
2017-05-29 16:49     ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure alison at peloton-tech.com
2017-05-30  7:38       ` Lothar Waßmann
2017-05-31  8:12       ` Lukasz Majewski
2017-06-01  7:04         ` Chaiken, Alison
2017-06-01  8:21           ` Lukasz Majewski
2017-06-01 15:06             ` Chaiken, Alison
2017-06-01 18:20               ` Lukasz Majewski
2017-06-04 22:11         ` [U-Boot] [PATCH v4 0/5] add support for GPT partition name manipulation alison at peloton-tech.com
2017-06-04 22:11           ` [U-Boot] [PATCH v4 1/5] GPT: read partition table from device into a data structure alison at peloton-tech.com
2017-06-04 22:11           ` [U-Boot] [PATCH v4 2/5] rename GPT partitions to detect boot failure alison at peloton-tech.com
2017-06-04 22:11           ` [U-Boot] [PATCH v4 3/5] GPT: fix error in partitions string doc alison at peloton-tech.com
2017-06-04 22:11           ` [U-Boot] [PATCH 4/5] sandbox: README: fix partition command invocation alison at peloton-tech.com
2017-06-09 12:28             ` Simon Glass
2017-06-15 19:21               ` sjg at google.com
2017-06-04 22:11           ` [U-Boot] [PATCH 5/5] cmd gpt: test in sandbox alison at peloton-tech.com
2017-06-15 19:21             ` sjg at google.com
2017-08-27 23:02         ` [U-Boot] [PATCH v2 5/6] rename GPT partitions to detect boot failure Chaiken, Alison
2017-08-28  7:54           ` Łukasz Majewski
2017-08-28 11:16             ` Tom Rini
2017-05-29 16:49     ` [U-Boot] [PATCH v2 6/6] GPT: fix error in partitions string doc alison at peloton-tech.com
2017-05-31  8:14       ` Lukasz Majewski
2017-05-31 11:21         ` Lukasz Majewski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.