
alison@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("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,printf("Start %s, size %s\n", partstartstr, partsizestr);
@@ -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 --valid_parts;return -1;
} @@ -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