xref: /rk3399_rockchip-uboot/cmd/gpt.c (revision 203f9b48adaf5ad5372ac72d82ab14465c82ee8d)
12e192b24SSimon Glass /*
22e192b24SSimon Glass  * cmd_gpt.c -- GPT (GUID Partition Table) handling command
32e192b24SSimon Glass  *
42e192b24SSimon Glass  * Copyright (C) 2015
52e192b24SSimon Glass  * Lukasz Majewski <l.majewski@majess.pl>
62e192b24SSimon Glass  *
72e192b24SSimon Glass  * Copyright (C) 2012 Samsung Electronics
82e192b24SSimon Glass  * author: Lukasz Majewski <l.majewski@samsung.com>
92e192b24SSimon Glass  * author: Piotr Wilczek <p.wilczek@samsung.com>
102e192b24SSimon Glass  *
112e192b24SSimon Glass  * SPDX-License-Identifier:	GPL-2.0+
122e192b24SSimon Glass  */
132e192b24SSimon Glass 
142e192b24SSimon Glass #include <common.h>
152e192b24SSimon Glass #include <malloc.h>
162e192b24SSimon Glass #include <command.h>
172e192b24SSimon Glass #include <part_efi.h>
182e192b24SSimon Glass #include <exports.h>
192e192b24SSimon Glass #include <linux/ctype.h>
202e192b24SSimon Glass #include <div64.h>
212e192b24SSimon Glass #include <memalign.h>
2209a49930SAlison Chaiken #include <linux/compat.h>
23*203f9b48SAlison Chaiken #include <linux/sizes.h>
24*203f9b48SAlison Chaiken #include <stdlib.h>
2509a49930SAlison Chaiken 
2609a49930SAlison Chaiken static LIST_HEAD(disk_partitions);
272e192b24SSimon Glass 
282e192b24SSimon Glass /**
292e192b24SSimon Glass  * extract_env(): Expand env name from string format '&{env_name}'
302e192b24SSimon Glass  *                and return pointer to the env (if the env is set)
312e192b24SSimon Glass  *
322e192b24SSimon Glass  * @param str - pointer to string
332e192b24SSimon Glass  * @param env - pointer to pointer to extracted env
342e192b24SSimon Glass  *
352e192b24SSimon Glass  * @return - zero on successful expand and env is set
362e192b24SSimon Glass  */
372e192b24SSimon Glass static int extract_env(const char *str, char **env)
382e192b24SSimon Glass {
392e192b24SSimon Glass 	int ret = -1;
402e192b24SSimon Glass 	char *e, *s;
412e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID
422e192b24SSimon Glass 	char uuid_str[UUID_STR_LEN + 1];
432e192b24SSimon Glass #endif
442e192b24SSimon Glass 
452e192b24SSimon Glass 	if (!str || strlen(str) < 4)
462e192b24SSimon Glass 		return -1;
472e192b24SSimon Glass 
482e192b24SSimon Glass 	if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')))
492e192b24SSimon Glass 		return -1;
502e192b24SSimon Glass 
512e192b24SSimon Glass 	s = strdup(str);
522e192b24SSimon Glass 	if (s == NULL)
532e192b24SSimon Glass 		return -1;
542e192b24SSimon Glass 
552e192b24SSimon Glass 	memset(s + strlen(s) - 1, '\0', 1);
562e192b24SSimon Glass 	memmove(s, s + 2, strlen(s) - 1);
572e192b24SSimon Glass 
582e192b24SSimon Glass 	e = getenv(s);
592e192b24SSimon Glass 	if (e == NULL) {
602e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID
612e192b24SSimon Glass 		debug("%s unset. ", str);
629da52f8fSVincent Tinelli 		gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID);
632e192b24SSimon Glass 		setenv(s, uuid_str);
642e192b24SSimon Glass 
652e192b24SSimon Glass 		e = getenv(s);
662e192b24SSimon Glass 		if (e) {
672e192b24SSimon Glass 			debug("Set to random.\n");
682e192b24SSimon Glass 			ret = 0;
692e192b24SSimon Glass 		} else {
702e192b24SSimon Glass 			debug("Can't get random UUID.\n");
712e192b24SSimon Glass 		}
722e192b24SSimon Glass #else
732e192b24SSimon Glass 		debug("%s unset.\n", str);
742e192b24SSimon Glass #endif
752e192b24SSimon Glass 	} else {
762e192b24SSimon Glass 		debug("%s get from environment.\n", str);
772e192b24SSimon Glass 		ret = 0;
782e192b24SSimon Glass 	}
792e192b24SSimon Glass 
802e192b24SSimon Glass 	*env = e;
812e192b24SSimon Glass 	free(s);
822e192b24SSimon Glass 
832e192b24SSimon Glass 	return ret;
842e192b24SSimon Glass }
852e192b24SSimon Glass 
862e192b24SSimon Glass /**
872e192b24SSimon Glass  * extract_val(): Extract value from a key=value pair list (comma separated).
882e192b24SSimon Glass  *                Only value for the given key is returend.
892e192b24SSimon Glass  *                Function allocates memory for the value, remember to free!
902e192b24SSimon Glass  *
912e192b24SSimon Glass  * @param str - pointer to string with key=values pairs
922e192b24SSimon Glass  * @param key - pointer to the key to search for
932e192b24SSimon Glass  *
942e192b24SSimon Glass  * @return - pointer to allocated string with the value
952e192b24SSimon Glass  */
962e192b24SSimon Glass static char *extract_val(const char *str, const char *key)
972e192b24SSimon Glass {
982e192b24SSimon Glass 	char *v, *k;
992e192b24SSimon Glass 	char *s, *strcopy;
1002e192b24SSimon Glass 	char *new = NULL;
1012e192b24SSimon Glass 
1022e192b24SSimon Glass 	strcopy = strdup(str);
1032e192b24SSimon Glass 	if (strcopy == NULL)
1042e192b24SSimon Glass 		return NULL;
1052e192b24SSimon Glass 
1062e192b24SSimon Glass 	s = strcopy;
1072e192b24SSimon Glass 	while (s) {
1082e192b24SSimon Glass 		v = strsep(&s, ",");
1092e192b24SSimon Glass 		if (!v)
1102e192b24SSimon Glass 			break;
1112e192b24SSimon Glass 		k = strsep(&v, "=");
1122e192b24SSimon Glass 		if (!k)
1132e192b24SSimon Glass 			break;
1142e192b24SSimon Glass 		if  (strcmp(k, key) == 0) {
1152e192b24SSimon Glass 			new = strdup(v);
1162e192b24SSimon Glass 			break;
1172e192b24SSimon Glass 		}
1182e192b24SSimon Glass 	}
1192e192b24SSimon Glass 
1202e192b24SSimon Glass 	free(strcopy);
1212e192b24SSimon Glass 
1222e192b24SSimon Glass 	return new;
1232e192b24SSimon Glass }
1242e192b24SSimon Glass 
1252e192b24SSimon Glass /**
1262e192b24SSimon Glass  * found_key(): Found key without value in parameter list (comma separated).
1272e192b24SSimon Glass  *
1282e192b24SSimon Glass  * @param str - pointer to string with key
1292e192b24SSimon Glass  * @param key - pointer to the key to search for
1302e192b24SSimon Glass  *
1312e192b24SSimon Glass  * @return - true on found key
1322e192b24SSimon Glass  */
1332e192b24SSimon Glass static bool found_key(const char *str, const char *key)
1342e192b24SSimon Glass {
1352e192b24SSimon Glass 	char *k;
1362e192b24SSimon Glass 	char *s, *strcopy;
1372e192b24SSimon Glass 	bool result = false;
1382e192b24SSimon Glass 
1392e192b24SSimon Glass 	strcopy = strdup(str);
1402e192b24SSimon Glass 	if (!strcopy)
1412e192b24SSimon Glass 		return NULL;
1422e192b24SSimon Glass 
1432e192b24SSimon Glass 	s = strcopy;
1442e192b24SSimon Glass 	while (s) {
1452e192b24SSimon Glass 		k = strsep(&s, ",");
1462e192b24SSimon Glass 		if (!k)
1472e192b24SSimon Glass 			break;
1482e192b24SSimon Glass 		if  (strcmp(k, key) == 0) {
1492e192b24SSimon Glass 			result = true;
1502e192b24SSimon Glass 			break;
1512e192b24SSimon Glass 		}
1522e192b24SSimon Glass 	}
1532e192b24SSimon Glass 
1542e192b24SSimon Glass 	free(strcopy);
1552e192b24SSimon Glass 
1562e192b24SSimon Glass 	return result;
1572e192b24SSimon Glass }
1582e192b24SSimon Glass 
15909a49930SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME
16009a49930SAlison Chaiken static void del_gpt_info(void)
16109a49930SAlison Chaiken {
16209a49930SAlison Chaiken 	struct list_head *pos = &disk_partitions;
16309a49930SAlison Chaiken 	struct disk_part *curr;
16409a49930SAlison Chaiken 	while (!list_empty(pos)) {
16509a49930SAlison Chaiken 		curr = list_entry(pos->next, struct disk_part, list);
16609a49930SAlison Chaiken 		list_del(pos->next);
16709a49930SAlison Chaiken 		free(curr);
16809a49930SAlison Chaiken 	}
16909a49930SAlison Chaiken }
17009a49930SAlison Chaiken 
17109a49930SAlison Chaiken static struct disk_part *allocate_disk_part(disk_partition_t *info, int partnum)
17209a49930SAlison Chaiken {
17309a49930SAlison Chaiken 	struct disk_part *newpart;
17409a49930SAlison Chaiken 	newpart = malloc(sizeof(*newpart));
17509a49930SAlison Chaiken 	if (!newpart)
17609a49930SAlison Chaiken 		return ERR_PTR(-ENOMEM);
17709a49930SAlison Chaiken 	memset(newpart, '\0', sizeof(newpart));
17809a49930SAlison Chaiken 
17909a49930SAlison Chaiken 	newpart->gpt_part_info.start = info->start;
18009a49930SAlison Chaiken 	newpart->gpt_part_info.size = info->size;
18109a49930SAlison Chaiken 	newpart->gpt_part_info.blksz = info->blksz;
18209a49930SAlison Chaiken 	strncpy((char *)newpart->gpt_part_info.name, (const char *)info->name,
18309a49930SAlison Chaiken 		PART_NAME_LEN);
18409a49930SAlison Chaiken 	newpart->gpt_part_info.name[PART_NAME_LEN - 1] = '\0';
18509a49930SAlison Chaiken 	strncpy((char *)newpart->gpt_part_info.type, (const char *)info->type,
18609a49930SAlison Chaiken 		PART_TYPE_LEN);
18709a49930SAlison Chaiken 	newpart->gpt_part_info.type[PART_TYPE_LEN - 1] = '\0';
18809a49930SAlison Chaiken 	newpart->gpt_part_info.bootable = info->bootable;
18909a49930SAlison Chaiken #ifdef CONFIG_PARTITION_UUIDS
19009a49930SAlison Chaiken 	strncpy(newpart->gpt_part_info.uuid, (const char *)info->uuid,
19109a49930SAlison Chaiken 		UUID_STR_LEN);
19209a49930SAlison Chaiken 	/* UUID_STR_LEN is correct, as uuid[]'s length is UUID_STR_LEN+1 chars */
19309a49930SAlison Chaiken 	newpart->gpt_part_info.uuid[UUID_STR_LEN] = '\0';
19409a49930SAlison Chaiken #endif
19509a49930SAlison Chaiken 	newpart->partnum = partnum;
19609a49930SAlison Chaiken 
19709a49930SAlison Chaiken 	return newpart;
19809a49930SAlison Chaiken }
19909a49930SAlison Chaiken 
200*203f9b48SAlison Chaiken static void prettyprint_part_size(char *sizestr, lbaint_t partsize,
201*203f9b48SAlison Chaiken 				  lbaint_t blksize)
202*203f9b48SAlison Chaiken {
203*203f9b48SAlison Chaiken 	unsigned long long partbytes, partmegabytes;
204*203f9b48SAlison Chaiken 
205*203f9b48SAlison Chaiken 	partbytes = partsize * blksize;
206*203f9b48SAlison Chaiken 	partmegabytes = lldiv(partbytes, SZ_1M);
207*203f9b48SAlison Chaiken 	snprintf(sizestr, 16, "%lluMiB", partmegabytes);
208*203f9b48SAlison Chaiken }
209*203f9b48SAlison Chaiken 
21009a49930SAlison Chaiken static void print_gpt_info(void)
21109a49930SAlison Chaiken {
21209a49930SAlison Chaiken 	struct list_head *pos;
21309a49930SAlison Chaiken 	struct disk_part *curr;
214*203f9b48SAlison Chaiken 	char partstartstr[16];
215*203f9b48SAlison Chaiken 	char partsizestr[16];
21609a49930SAlison Chaiken 
21709a49930SAlison Chaiken 	list_for_each(pos, &disk_partitions) {
21809a49930SAlison Chaiken 		curr = list_entry(pos, struct disk_part, list);
219*203f9b48SAlison Chaiken 		prettyprint_part_size(partstartstr, curr->gpt_part_info.start,
220*203f9b48SAlison Chaiken 				      curr->gpt_part_info.blksz);
221*203f9b48SAlison Chaiken 		prettyprint_part_size(partsizestr, curr->gpt_part_info.size,
222*203f9b48SAlison Chaiken 				      curr->gpt_part_info.blksz);
223*203f9b48SAlison Chaiken 
22409a49930SAlison Chaiken 		printf("Partition %d:\n", curr->partnum);
225*203f9b48SAlison Chaiken 		printf("Start %s, size %s\n", partstartstr, partsizestr);
22609a49930SAlison Chaiken 		printf("Block size %lu, name %s\n", curr->gpt_part_info.blksz,
22709a49930SAlison Chaiken 		       curr->gpt_part_info.name);
22809a49930SAlison Chaiken 		printf("Type %s, bootable %d\n", curr->gpt_part_info.type,
22909a49930SAlison Chaiken 		       curr->gpt_part_info.bootable);
23009a49930SAlison Chaiken #ifdef CONFIG_PARTITION_UUIDS
23109a49930SAlison Chaiken 		printf("UUID %s\n", curr->gpt_part_info.uuid);
23209a49930SAlison Chaiken #endif
23309a49930SAlison Chaiken 		printf("\n");
23409a49930SAlison Chaiken 	}
23509a49930SAlison Chaiken }
23609a49930SAlison Chaiken 
237*203f9b48SAlison Chaiken static int calc_parts_list_len(int numparts)
238*203f9b48SAlison Chaiken {
239*203f9b48SAlison Chaiken 	int partlistlen = UUID_STR_LEN + 1 + strlen("uuid_disk=");
240*203f9b48SAlison Chaiken 	/* for the comma */
241*203f9b48SAlison Chaiken 	partlistlen++;
242*203f9b48SAlison Chaiken 
243*203f9b48SAlison Chaiken 	/* per-partition additions; numparts starts at 1, so this should be correct */
244*203f9b48SAlison Chaiken 	partlistlen += numparts * (strlen("name=,") + PART_NAME_LEN + 1);
245*203f9b48SAlison Chaiken 	/* see part.h for definition of struct disk_partition */
246*203f9b48SAlison Chaiken 	partlistlen += numparts * (strlen("start=MiB,") + sizeof(lbaint_t) + 1);
247*203f9b48SAlison Chaiken 	partlistlen += numparts * (strlen("size=MiB,") + sizeof(lbaint_t) + 1);
248*203f9b48SAlison Chaiken 	partlistlen += numparts * (strlen("uuid=;") + UUID_STR_LEN + 1);
249*203f9b48SAlison Chaiken 	/* for the terminating null */
250*203f9b48SAlison Chaiken 	partlistlen++;
251*203f9b48SAlison Chaiken 	debug("Length of partitions_list is %d for %d partitions\n", partlistlen,
252*203f9b48SAlison Chaiken 	      numparts);
253*203f9b48SAlison Chaiken 	return partlistlen;
254*203f9b48SAlison Chaiken }
255*203f9b48SAlison Chaiken 
256*203f9b48SAlison Chaiken /*
257*203f9b48SAlison Chaiken  * create the string that upstream 'gpt write' command will accept as an
258*203f9b48SAlison Chaiken  * argument
259*203f9b48SAlison Chaiken  *
260*203f9b48SAlison Chaiken  * From doc/README.gpt, Format of partitions layout:
261*203f9b48SAlison Chaiken  *    "uuid_disk=...;name=u-boot,size=60MiB,uuid=...;
262*203f9b48SAlison Chaiken  *	name=kernel,size=60MiB,uuid=...;"
263*203f9b48SAlison Chaiken  * The fields 'name' and 'size' are mandatory for every partition.
264*203f9b48SAlison Chaiken  * The field 'start' is optional. The fields 'uuid' and 'uuid_disk'
265*203f9b48SAlison Chaiken  * are optional if CONFIG_RANDOM_UUID is enabled.
266*203f9b48SAlison Chaiken  */
267*203f9b48SAlison Chaiken static int create_gpt_partitions_list(int numparts, const char *guid,
268*203f9b48SAlison Chaiken 				      char *partitions_list)
269*203f9b48SAlison Chaiken {
270*203f9b48SAlison Chaiken 	struct list_head *pos;
271*203f9b48SAlison Chaiken 	struct disk_part *curr;
272*203f9b48SAlison Chaiken 	char partstr[PART_NAME_LEN + 1];
273*203f9b48SAlison Chaiken 
274*203f9b48SAlison Chaiken 	if (!partitions_list)
275*203f9b48SAlison Chaiken 		return -EINVAL;
276*203f9b48SAlison Chaiken 
277*203f9b48SAlison Chaiken 	strcpy(partitions_list, "uuid_disk=");
278*203f9b48SAlison Chaiken 	strncat(partitions_list, guid, UUID_STR_LEN + 1);
279*203f9b48SAlison Chaiken 	strcat(partitions_list, ";");
280*203f9b48SAlison Chaiken 
281*203f9b48SAlison Chaiken 	list_for_each(pos, &disk_partitions) {
282*203f9b48SAlison Chaiken 		curr = list_entry(pos, struct disk_part, list);
283*203f9b48SAlison Chaiken 		strcat(partitions_list, "name=");
284*203f9b48SAlison Chaiken 		strncat(partitions_list, (const char *)curr->gpt_part_info.name,
285*203f9b48SAlison Chaiken 			PART_NAME_LEN + 1);
286*203f9b48SAlison Chaiken 		strcat(partitions_list, ",start=");
287*203f9b48SAlison Chaiken 		prettyprint_part_size(partstr, (unsigned long)curr->gpt_part_info.start,
288*203f9b48SAlison Chaiken 				      (unsigned long) curr->gpt_part_info.blksz);
289*203f9b48SAlison Chaiken 		/* one extra byte for NULL */
290*203f9b48SAlison Chaiken 		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
291*203f9b48SAlison Chaiken 		strcat(partitions_list, ",size=");
292*203f9b48SAlison Chaiken 		prettyprint_part_size(partstr, curr->gpt_part_info.size,
293*203f9b48SAlison Chaiken 				      curr->gpt_part_info.blksz);
294*203f9b48SAlison Chaiken 		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
295*203f9b48SAlison Chaiken 
296*203f9b48SAlison Chaiken 		strcat(partitions_list, ",uuid=");
297*203f9b48SAlison Chaiken 		strncat(partitions_list, curr->gpt_part_info.uuid,
298*203f9b48SAlison Chaiken 			UUID_STR_LEN + 1);
299*203f9b48SAlison Chaiken 		strcat(partitions_list, ";");
300*203f9b48SAlison Chaiken 	}
301*203f9b48SAlison Chaiken 	return 0;
302*203f9b48SAlison Chaiken }
303*203f9b48SAlison Chaiken 
30409a49930SAlison Chaiken /*
30509a49930SAlison Chaiken  * read partition info into disk_partitions list where
30609a49930SAlison Chaiken  * it can be printed or modified
30709a49930SAlison Chaiken  */
30809a49930SAlison Chaiken static int get_gpt_info(struct blk_desc *dev_desc)
30909a49930SAlison Chaiken {
31009a49930SAlison Chaiken 	/* start partition numbering at 1, as U-Boot does */
31109a49930SAlison Chaiken 	int valid_parts = 0, p, ret;
31209a49930SAlison Chaiken 	disk_partition_t info;
31309a49930SAlison Chaiken 	struct disk_part *new_disk_part;
31409a49930SAlison Chaiken 
315*203f9b48SAlison Chaiken 	/*
316*203f9b48SAlison Chaiken 	 * Always re-read partition info from device, in case
317*203f9b48SAlison Chaiken 	 * it has changed
318*203f9b48SAlison Chaiken 	 */
31909a49930SAlison Chaiken 	INIT_LIST_HEAD(&disk_partitions);
32009a49930SAlison Chaiken 
32109a49930SAlison Chaiken 	for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
32209a49930SAlison Chaiken 		ret = part_get_info(dev_desc, p, &info);
32309a49930SAlison Chaiken 		if (ret)
32409a49930SAlison Chaiken 			continue;
32509a49930SAlison Chaiken 
32609a49930SAlison Chaiken 		/* Add 1 here because counter is zero-based but p1 is
32709a49930SAlison Chaiken 		   the first partition */
32809a49930SAlison Chaiken 		new_disk_part = allocate_disk_part(&info, valid_parts+1);
32909a49930SAlison Chaiken 		if (IS_ERR(new_disk_part))
33009a49930SAlison Chaiken 			goto out;
33109a49930SAlison Chaiken 
33209a49930SAlison Chaiken 		list_add_tail(&new_disk_part->list, &disk_partitions);
33309a49930SAlison Chaiken 		valid_parts++;
33409a49930SAlison Chaiken 	}
33509a49930SAlison Chaiken 	if (valid_parts == 0) {
33609a49930SAlison Chaiken 		printf("** No valid partitions found **\n");
33709a49930SAlison Chaiken 		goto out;
33809a49930SAlison Chaiken 	}
33909a49930SAlison Chaiken 	return valid_parts;
34009a49930SAlison Chaiken  out:
34109a49930SAlison Chaiken 	if (valid_parts >= 1)
34209a49930SAlison Chaiken 		del_gpt_info();
34309a49930SAlison Chaiken 	return -ENODEV;
34409a49930SAlison Chaiken }
34509a49930SAlison Chaiken 
34609a49930SAlison Chaiken /* a wrapper to test get_gpt_info */
34709a49930SAlison Chaiken static int do_get_gpt_info(struct blk_desc *dev_desc)
34809a49930SAlison Chaiken {
34909a49930SAlison Chaiken 	int ret;
35009a49930SAlison Chaiken 
35109a49930SAlison Chaiken 	ret = get_gpt_info(dev_desc);
35209a49930SAlison Chaiken 	if (ret > 0) {
35309a49930SAlison Chaiken 		print_gpt_info();
35409a49930SAlison Chaiken 		del_gpt_info();
35509a49930SAlison Chaiken 		return 0;
35609a49930SAlison Chaiken 	}
35709a49930SAlison Chaiken 	return ret;
35809a49930SAlison Chaiken }
35909a49930SAlison Chaiken #endif
36009a49930SAlison Chaiken 
3612e192b24SSimon Glass /**
3622e192b24SSimon Glass  * set_gpt_info(): Fill partition information from string
3632e192b24SSimon Glass  *		function allocates memory, remember to free!
3642e192b24SSimon Glass  *
3652e192b24SSimon Glass  * @param dev_desc - pointer block device descriptor
3662e192b24SSimon Glass  * @param str_part - pointer to string with partition information
3672e192b24SSimon Glass  * @param str_disk_guid - pointer to pointer to allocated string with disk guid
3682e192b24SSimon Glass  * @param partitions - pointer to pointer to allocated partitions array
3692e192b24SSimon Glass  * @param parts_count - number of partitions
3702e192b24SSimon Glass  *
3712e192b24SSimon Glass  * @return - zero on success, otherwise error
3722e192b24SSimon Glass  *
3732e192b24SSimon Glass  */
3744101f687SSimon Glass static int set_gpt_info(struct blk_desc *dev_desc,
3752e192b24SSimon Glass 			const char *str_part,
3762e192b24SSimon Glass 			char **str_disk_guid,
3772e192b24SSimon Glass 			disk_partition_t **partitions,
3782e192b24SSimon Glass 			u8 *parts_count)
3792e192b24SSimon Glass {
3802e192b24SSimon Glass 	char *tok, *str, *s;
3812e192b24SSimon Glass 	int i;
3822e192b24SSimon Glass 	char *val, *p;
3832e192b24SSimon Glass 	int p_count;
3842e192b24SSimon Glass 	disk_partition_t *parts;
3852e192b24SSimon Glass 	int errno = 0;
3862e192b24SSimon Glass 	uint64_t size_ll, start_ll;
38766636235SMichael Trimarchi 	lbaint_t offset = 0;
3882e192b24SSimon Glass 
3892e192b24SSimon Glass 	debug("%s:  lba num: 0x%x %d\n", __func__,
3902e192b24SSimon Glass 	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
3912e192b24SSimon Glass 
3922e192b24SSimon Glass 	if (str_part == NULL)
3932e192b24SSimon Glass 		return -1;
3942e192b24SSimon Glass 
3952e192b24SSimon Glass 	str = strdup(str_part);
396*203f9b48SAlison Chaiken 	if (str == NULL)
397*203f9b48SAlison Chaiken 		return -ENOMEM;
3982e192b24SSimon Glass 
3992e192b24SSimon Glass 	/* extract disk guid */
4002e192b24SSimon Glass 	s = str;
4012e192b24SSimon Glass 	val = extract_val(str, "uuid_disk");
4022e192b24SSimon Glass 	if (!val) {
4032e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID
4042e192b24SSimon Glass 		*str_disk_guid = malloc(UUID_STR_LEN + 1);
4052e192b24SSimon Glass 		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
4062e192b24SSimon Glass #else
4072e192b24SSimon Glass 		free(str);
4082e192b24SSimon Glass 		return -2;
4092e192b24SSimon Glass #endif
4102e192b24SSimon Glass 	} else {
4112e192b24SSimon Glass 		val = strsep(&val, ";");
4122e192b24SSimon Glass 		if (extract_env(val, &p))
4132e192b24SSimon Glass 			p = val;
4142e192b24SSimon Glass 		*str_disk_guid = strdup(p);
4152e192b24SSimon Glass 		free(val);
4162e192b24SSimon Glass 		/* Move s to first partition */
4172e192b24SSimon Glass 		strsep(&s, ";");
4182e192b24SSimon Glass 	}
4192e192b24SSimon Glass 	if (strlen(s) == 0)
4202e192b24SSimon Glass 		return -3;
4212e192b24SSimon Glass 
4222e192b24SSimon Glass 	i = strlen(s) - 1;
4232e192b24SSimon Glass 	if (s[i] == ';')
4242e192b24SSimon Glass 		s[i] = '\0';
4252e192b24SSimon Glass 
4262e192b24SSimon Glass 	/* calculate expected number of partitions */
4272e192b24SSimon Glass 	p_count = 1;
4282e192b24SSimon Glass 	p = s;
4292e192b24SSimon Glass 	while (*p) {
4302e192b24SSimon Glass 		if (*p++ == ';')
4312e192b24SSimon Glass 			p_count++;
4322e192b24SSimon Glass 	}
4332e192b24SSimon Glass 
4342e192b24SSimon Glass 	/* allocate memory for partitions */
4352e192b24SSimon Glass 	parts = calloc(sizeof(disk_partition_t), p_count);
4362e192b24SSimon Glass 
4372e192b24SSimon Glass 	/* retrieve partitions data from string */
4382e192b24SSimon Glass 	for (i = 0; i < p_count; i++) {
4392e192b24SSimon Glass 		tok = strsep(&s, ";");
4402e192b24SSimon Glass 
4412e192b24SSimon Glass 		if (tok == NULL)
4422e192b24SSimon Glass 			break;
4432e192b24SSimon Glass 
4442e192b24SSimon Glass 		/* uuid */
4452e192b24SSimon Glass 		val = extract_val(tok, "uuid");
4462e192b24SSimon Glass 		if (!val) {
4472e192b24SSimon Glass 			/* 'uuid' is optional if random uuid's are enabled */
4482e192b24SSimon Glass #ifdef CONFIG_RANDOM_UUID
4492e192b24SSimon Glass 			gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
4502e192b24SSimon Glass #else
4512e192b24SSimon Glass 			errno = -4;
4522e192b24SSimon Glass 			goto err;
4532e192b24SSimon Glass #endif
4542e192b24SSimon Glass 		} else {
4552e192b24SSimon Glass 			if (extract_env(val, &p))
4562e192b24SSimon Glass 				p = val;
4572e192b24SSimon Glass 			if (strlen(p) >= sizeof(parts[i].uuid)) {
4582e192b24SSimon Glass 				printf("Wrong uuid format for partition %d\n", i);
4592e192b24SSimon Glass 				errno = -4;
4602e192b24SSimon Glass 				goto err;
4612e192b24SSimon Glass 			}
4622e192b24SSimon Glass 			strcpy((char *)parts[i].uuid, p);
4632e192b24SSimon Glass 			free(val);
4642e192b24SSimon Glass 		}
4652e192b24SSimon Glass #ifdef CONFIG_PARTITION_TYPE_GUID
4662e192b24SSimon Glass 		/* guid */
4672e192b24SSimon Glass 		val = extract_val(tok, "type");
4682e192b24SSimon Glass 		if (val) {
4692e192b24SSimon Glass 			/* 'type' is optional */
4702e192b24SSimon Glass 			if (extract_env(val, &p))
4712e192b24SSimon Glass 				p = val;
4722e192b24SSimon Glass 			if (strlen(p) >= sizeof(parts[i].type_guid)) {
4732e192b24SSimon Glass 				printf("Wrong type guid format for partition %d\n",
4742e192b24SSimon Glass 				       i);
4752e192b24SSimon Glass 				errno = -4;
4762e192b24SSimon Glass 				goto err;
4772e192b24SSimon Glass 			}
4782e192b24SSimon Glass 			strcpy((char *)parts[i].type_guid, p);
4792e192b24SSimon Glass 			free(val);
4802e192b24SSimon Glass 		}
4812e192b24SSimon Glass #endif
4822e192b24SSimon Glass 		/* name */
4832e192b24SSimon Glass 		val = extract_val(tok, "name");
4842e192b24SSimon Glass 		if (!val) { /* name is mandatory */
4852e192b24SSimon Glass 			errno = -4;
4862e192b24SSimon Glass 			goto err;
4872e192b24SSimon Glass 		}
4882e192b24SSimon Glass 		if (extract_env(val, &p))
4892e192b24SSimon Glass 			p = val;
4902e192b24SSimon Glass 		if (strlen(p) >= sizeof(parts[i].name)) {
4912e192b24SSimon Glass 			errno = -4;
4922e192b24SSimon Glass 			goto err;
4932e192b24SSimon Glass 		}
4942e192b24SSimon Glass 		strcpy((char *)parts[i].name, p);
4952e192b24SSimon Glass 		free(val);
4962e192b24SSimon Glass 
4972e192b24SSimon Glass 		/* size */
4982e192b24SSimon Glass 		val = extract_val(tok, "size");
4992e192b24SSimon Glass 		if (!val) { /* 'size' is mandatory */
5002e192b24SSimon Glass 			errno = -4;
5012e192b24SSimon Glass 			goto err;
5022e192b24SSimon Glass 		}
5032e192b24SSimon Glass 		if (extract_env(val, &p))
5042e192b24SSimon Glass 			p = val;
50566636235SMichael Trimarchi 		if ((strcmp(p, "-") == 0)) {
506c2fdd345SKever Yang 			/* Let part efi module to auto extend the size */
507c2fdd345SKever Yang 			parts[i].size = 0;
50866636235SMichael Trimarchi 		} else {
5092e192b24SSimon Glass 			size_ll = ustrtoull(p, &p, 0);
5102e192b24SSimon Glass 			parts[i].size = lldiv(size_ll, dev_desc->blksz);
51166636235SMichael Trimarchi 		}
51266636235SMichael Trimarchi 
5132e192b24SSimon Glass 		free(val);
5142e192b24SSimon Glass 
5152e192b24SSimon Glass 		/* start address */
5162e192b24SSimon Glass 		val = extract_val(tok, "start");
5172e192b24SSimon Glass 		if (val) { /* start address is optional */
5182e192b24SSimon Glass 			if (extract_env(val, &p))
5192e192b24SSimon Glass 				p = val;
5202e192b24SSimon Glass 			start_ll = ustrtoull(p, &p, 0);
5212e192b24SSimon Glass 			parts[i].start = lldiv(start_ll, dev_desc->blksz);
5222e192b24SSimon Glass 			free(val);
5232e192b24SSimon Glass 		}
5242e192b24SSimon Glass 
52566636235SMichael Trimarchi 		offset += parts[i].size + parts[i].start;
52666636235SMichael Trimarchi 
5272e192b24SSimon Glass 		/* bootable */
5282e192b24SSimon Glass 		if (found_key(tok, "bootable"))
5292e192b24SSimon Glass 			parts[i].bootable = 1;
5302e192b24SSimon Glass 	}
5312e192b24SSimon Glass 
5322e192b24SSimon Glass 	*parts_count = p_count;
5332e192b24SSimon Glass 	*partitions = parts;
5342e192b24SSimon Glass 	free(str);
5352e192b24SSimon Glass 
5362e192b24SSimon Glass 	return 0;
5372e192b24SSimon Glass err:
5382e192b24SSimon Glass 	free(str);
5392e192b24SSimon Glass 	free(*str_disk_guid);
5402e192b24SSimon Glass 	free(parts);
5412e192b24SSimon Glass 
5422e192b24SSimon Glass 	return errno;
5432e192b24SSimon Glass }
5442e192b24SSimon Glass 
5454101f687SSimon Glass static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part)
5462e192b24SSimon Glass {
5472e192b24SSimon Glass 	int ret;
5482e192b24SSimon Glass 	char *str_disk_guid;
5492e192b24SSimon Glass 	u8 part_count = 0;
5502e192b24SSimon Glass 	disk_partition_t *partitions = NULL;
5512e192b24SSimon Glass 
5522e192b24SSimon Glass 	/* fill partitions */
5532e192b24SSimon Glass 	ret = set_gpt_info(blk_dev_desc, str_part,
5542e192b24SSimon Glass 			&str_disk_guid, &partitions, &part_count);
5552e192b24SSimon Glass 	if (ret) {
5562e192b24SSimon Glass 		if (ret == -1)
5572e192b24SSimon Glass 			printf("No partition list provided\n");
5582e192b24SSimon Glass 		if (ret == -2)
5592e192b24SSimon Glass 			printf("Missing disk guid\n");
5602e192b24SSimon Glass 		if ((ret == -3) || (ret == -4))
5612e192b24SSimon Glass 			printf("Partition list incomplete\n");
5622e192b24SSimon Glass 		return -1;
5632e192b24SSimon Glass 	}
5642e192b24SSimon Glass 
5652e192b24SSimon Glass 	/* save partitions layout to disk */
5662e192b24SSimon Glass 	ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
5672e192b24SSimon Glass 	free(str_disk_guid);
5682e192b24SSimon Glass 	free(partitions);
5692e192b24SSimon Glass 
5702e192b24SSimon Glass 	return ret;
5712e192b24SSimon Glass }
5722e192b24SSimon Glass 
5734101f687SSimon Glass static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
5742e192b24SSimon Glass {
5752e192b24SSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
5762e192b24SSimon Glass 				     blk_dev_desc->blksz);
5772e192b24SSimon Glass 	disk_partition_t *partitions = NULL;
5782e192b24SSimon Glass 	gpt_entry *gpt_pte = NULL;
5792e192b24SSimon Glass 	char *str_disk_guid;
5802e192b24SSimon Glass 	u8 part_count = 0;
5812e192b24SSimon Glass 	int ret = 0;
5822e192b24SSimon Glass 
5832e192b24SSimon Glass 	/* fill partitions */
5842e192b24SSimon Glass 	ret = set_gpt_info(blk_dev_desc, str_part,
5852e192b24SSimon Glass 			&str_disk_guid, &partitions, &part_count);
5862e192b24SSimon Glass 	if (ret) {
5872e192b24SSimon Glass 		if (ret == -1) {
5882e192b24SSimon Glass 			printf("No partition list provided - only basic check\n");
5892e192b24SSimon Glass 			ret = gpt_verify_headers(blk_dev_desc, gpt_head,
5902e192b24SSimon Glass 						 &gpt_pte);
5912e192b24SSimon Glass 			goto out;
5922e192b24SSimon Glass 		}
5932e192b24SSimon Glass 		if (ret == -2)
5942e192b24SSimon Glass 			printf("Missing disk guid\n");
5952e192b24SSimon Glass 		if ((ret == -3) || (ret == -4))
5962e192b24SSimon Glass 			printf("Partition list incomplete\n");
5972e192b24SSimon Glass 		return -1;
5982e192b24SSimon Glass 	}
5992e192b24SSimon Glass 
6002e192b24SSimon Glass 	/* Check partition layout with provided pattern */
6012e192b24SSimon Glass 	ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count,
6022e192b24SSimon Glass 				    gpt_head, &gpt_pte);
6032e192b24SSimon Glass 	free(str_disk_guid);
6042e192b24SSimon Glass 	free(partitions);
6052e192b24SSimon Glass  out:
6062e192b24SSimon Glass 	free(gpt_pte);
6072e192b24SSimon Glass 	return ret;
6082e192b24SSimon Glass }
6092e192b24SSimon Glass 
61073d6d18bSAlison Chaiken static int do_disk_guid(struct blk_desc *dev_desc, char * const namestr)
61173d6d18bSAlison Chaiken {
61273d6d18bSAlison Chaiken 	int ret;
61373d6d18bSAlison Chaiken 	char disk_guid[UUID_STR_LEN + 1];
61473d6d18bSAlison Chaiken 
61573d6d18bSAlison Chaiken 	ret = get_disk_guid(dev_desc, disk_guid);
61673d6d18bSAlison Chaiken 	if (ret < 0)
61773d6d18bSAlison Chaiken 		return CMD_RET_FAILURE;
61873d6d18bSAlison Chaiken 
61973d6d18bSAlison Chaiken 	if (namestr)
62073d6d18bSAlison Chaiken 		setenv(namestr, disk_guid);
62173d6d18bSAlison Chaiken 	else
62273d6d18bSAlison Chaiken 		printf("%s\n", disk_guid);
62373d6d18bSAlison Chaiken 
62473d6d18bSAlison Chaiken 	return ret;
62573d6d18bSAlison Chaiken }
62673d6d18bSAlison Chaiken 
627*203f9b48SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME
628*203f9b48SAlison Chaiken static int do_rename_gpt_parts(struct blk_desc *dev_desc, char *subcomm,
629*203f9b48SAlison Chaiken 			       char *name1, char *name2)
630*203f9b48SAlison Chaiken {
631*203f9b48SAlison Chaiken 	struct list_head *pos;
632*203f9b48SAlison Chaiken 	struct disk_part *curr;
633*203f9b48SAlison Chaiken 	disk_partition_t *new_partitions = NULL;
634*203f9b48SAlison Chaiken 	char disk_guid[UUID_STR_LEN + 1];
635*203f9b48SAlison Chaiken 	char *partitions_list, *str_disk_guid;
636*203f9b48SAlison Chaiken 	u8 part_count = 0;
637*203f9b48SAlison Chaiken 	int partlistlen, ret, numparts = 0, partnum, i = 1, ctr1 = 0, ctr2 = 0;
638*203f9b48SAlison Chaiken 
639*203f9b48SAlison Chaiken 	if ((subcomm == NULL) || (name1 == NULL) || (name2 == NULL) ||
640*203f9b48SAlison Chaiken 	    (strcmp(subcomm, "swap") && (strcmp(subcomm, "rename"))))
641*203f9b48SAlison Chaiken 		return -EINVAL;
642*203f9b48SAlison Chaiken 
643*203f9b48SAlison Chaiken 	ret = get_disk_guid(dev_desc, disk_guid);
644*203f9b48SAlison Chaiken 	if (ret < 0)
645*203f9b48SAlison Chaiken 		return ret;
646*203f9b48SAlison Chaiken 	numparts = get_gpt_info(dev_desc);
647*203f9b48SAlison Chaiken 	if (numparts <=  0)
648*203f9b48SAlison Chaiken 		return numparts ? numparts : -ENODEV;
649*203f9b48SAlison Chaiken 
650*203f9b48SAlison Chaiken 	partlistlen = calc_parts_list_len(numparts);
651*203f9b48SAlison Chaiken 	partitions_list = malloc(partlistlen);
652*203f9b48SAlison Chaiken 	if (partitions_list == NULL)
653*203f9b48SAlison Chaiken 		return -ENOMEM;
654*203f9b48SAlison Chaiken 	memset(partitions_list, '\0', partlistlen);
655*203f9b48SAlison Chaiken 
656*203f9b48SAlison Chaiken 	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
657*203f9b48SAlison Chaiken 	if (ret < 0)
658*203f9b48SAlison Chaiken 		return ret;
659*203f9b48SAlison Chaiken 	/*
660*203f9b48SAlison Chaiken 	 * Uncomment the following line to print a string that 'gpt write'
661*203f9b48SAlison Chaiken 	 * or 'gpt verify' will accept as input.
662*203f9b48SAlison Chaiken 	 */
663*203f9b48SAlison Chaiken 	debug("OLD partitions_list is %s with %u chars\n", partitions_list,
664*203f9b48SAlison Chaiken 	      (unsigned)strlen(partitions_list));
665*203f9b48SAlison Chaiken 
666*203f9b48SAlison Chaiken 	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
667*203f9b48SAlison Chaiken 			   &new_partitions, &part_count);
668*203f9b48SAlison Chaiken 	if (ret < 0)
669*203f9b48SAlison Chaiken 		return ret;
670*203f9b48SAlison Chaiken 
671*203f9b48SAlison Chaiken 	if (!strcmp(subcomm, "swap")) {
672*203f9b48SAlison Chaiken 		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
673*203f9b48SAlison Chaiken 			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
674*203f9b48SAlison Chaiken 			return -EINVAL;
675*203f9b48SAlison Chaiken 		}
676*203f9b48SAlison Chaiken 		list_for_each(pos, &disk_partitions) {
677*203f9b48SAlison Chaiken 			curr = list_entry(pos, struct disk_part, list);
678*203f9b48SAlison Chaiken 			if (!strcmp((char *)curr->gpt_part_info.name, name1)) {
679*203f9b48SAlison Chaiken 				strcpy((char *)curr->gpt_part_info.name, name2);
680*203f9b48SAlison Chaiken 				ctr1++;
681*203f9b48SAlison Chaiken 			} else if (!strcmp((char *)curr->gpt_part_info.name, name2)) {
682*203f9b48SAlison Chaiken 				strcpy((char *)curr->gpt_part_info.name, name1);
683*203f9b48SAlison Chaiken 				ctr2++;
684*203f9b48SAlison Chaiken 			}
685*203f9b48SAlison Chaiken 		}
686*203f9b48SAlison Chaiken 		if ((ctr1 + ctr2 < 2) || (ctr1 != ctr2)) {
687*203f9b48SAlison Chaiken 			printf("Cannot swap partition names except in pairs.\n");
688*203f9b48SAlison Chaiken 			return -EINVAL;
689*203f9b48SAlison Chaiken 		}
690*203f9b48SAlison Chaiken 	} else { /* rename */
691*203f9b48SAlison Chaiken 		if (strlen(name2) > PART_NAME_LEN) {
692*203f9b48SAlison Chaiken 			printf("Names longer than %d characters are truncated.\n", PART_NAME_LEN);
693*203f9b48SAlison Chaiken 			return -EINVAL;
694*203f9b48SAlison Chaiken 		}
695*203f9b48SAlison Chaiken 		partnum = (int)simple_strtol(name1, NULL, 10);
696*203f9b48SAlison Chaiken 		if ((partnum < 0) || (partnum > numparts)) {
697*203f9b48SAlison Chaiken 			printf("Illegal partition number %s\n", name1);
698*203f9b48SAlison Chaiken 			return -EINVAL;
699*203f9b48SAlison Chaiken 		}
700*203f9b48SAlison Chaiken 		ret = part_get_info(dev_desc, partnum, new_partitions);
701*203f9b48SAlison Chaiken 		if (ret < 0)
702*203f9b48SAlison Chaiken 			return ret;
703*203f9b48SAlison Chaiken 
704*203f9b48SAlison Chaiken 		/* U-Boot partition numbering starts at 1 */
705*203f9b48SAlison Chaiken 		list_for_each(pos, &disk_partitions) {
706*203f9b48SAlison Chaiken 			curr = list_entry(pos, struct disk_part, list);
707*203f9b48SAlison Chaiken 			if (i == partnum) {
708*203f9b48SAlison Chaiken 				strcpy((char *)curr->gpt_part_info.name, name2);
709*203f9b48SAlison Chaiken 				break;
710*203f9b48SAlison Chaiken 			}
711*203f9b48SAlison Chaiken 			i++;
712*203f9b48SAlison Chaiken 		}
713*203f9b48SAlison Chaiken 	}
714*203f9b48SAlison Chaiken 
715*203f9b48SAlison Chaiken 	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
716*203f9b48SAlison Chaiken 	if (ret < 0)
717*203f9b48SAlison Chaiken 		return ret;
718*203f9b48SAlison Chaiken 	debug("NEW partitions_list is %s with %u chars\n", partitions_list,
719*203f9b48SAlison Chaiken 	      (unsigned)strlen(partitions_list));
720*203f9b48SAlison Chaiken 
721*203f9b48SAlison Chaiken 	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
722*203f9b48SAlison Chaiken 			   &new_partitions, &part_count);
723*203f9b48SAlison Chaiken 	if (ret < 0)
724*203f9b48SAlison Chaiken 		return ret;
725*203f9b48SAlison Chaiken 
726*203f9b48SAlison Chaiken 	debug("Writing new partition table\n");
727*203f9b48SAlison Chaiken 	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
728*203f9b48SAlison Chaiken 	if (ret < 0) {
729*203f9b48SAlison Chaiken 		printf("Writing new partition table failed\n");
730*203f9b48SAlison Chaiken 		return ret;
731*203f9b48SAlison Chaiken 	}
732*203f9b48SAlison Chaiken 
733*203f9b48SAlison Chaiken 	debug("Reading back new partition table\n");
734*203f9b48SAlison Chaiken 	numparts = get_gpt_info(dev_desc);
735*203f9b48SAlison Chaiken 	if (numparts <=  0)
736*203f9b48SAlison Chaiken 		return numparts ? numparts : -ENODEV;
737*203f9b48SAlison Chaiken 	printf("new partition table with %d partitions is:\n", numparts);
738*203f9b48SAlison Chaiken 	print_gpt_info();
739*203f9b48SAlison Chaiken 
740*203f9b48SAlison Chaiken 	del_gpt_info();
741*203f9b48SAlison Chaiken 	free(partitions_list);
742*203f9b48SAlison Chaiken 	free(str_disk_guid);
743*203f9b48SAlison Chaiken 	free(new_partitions);
744*203f9b48SAlison Chaiken 	return ret;
745*203f9b48SAlison Chaiken }
746*203f9b48SAlison Chaiken #endif
747*203f9b48SAlison Chaiken 
7482e192b24SSimon Glass /**
7492e192b24SSimon Glass  * do_gpt(): Perform GPT operations
7502e192b24SSimon Glass  *
7512e192b24SSimon Glass  * @param cmdtp - command name
7522e192b24SSimon Glass  * @param flag
7532e192b24SSimon Glass  * @param argc
7542e192b24SSimon Glass  * @param argv
7552e192b24SSimon Glass  *
7562e192b24SSimon Glass  * @return zero on success; otherwise error
7572e192b24SSimon Glass  */
7582e192b24SSimon Glass static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
7592e192b24SSimon Glass {
7602e192b24SSimon Glass 	int ret = CMD_RET_SUCCESS;
7612e192b24SSimon Glass 	int dev = 0;
7622e192b24SSimon Glass 	char *ep;
7634101f687SSimon Glass 	struct blk_desc *blk_dev_desc = NULL;
7642e192b24SSimon Glass 
765*203f9b48SAlison Chaiken #ifndef CONFIG_CMD_GPT_RENAME
7662e192b24SSimon Glass 	if (argc < 4 || argc > 5)
767*203f9b48SAlison Chaiken #else
768*203f9b48SAlison Chaiken 	if (argc < 4 || argc > 6)
769*203f9b48SAlison Chaiken #endif
7702e192b24SSimon Glass 		return CMD_RET_USAGE;
7712e192b24SSimon Glass 
7722e192b24SSimon Glass 	dev = (int)simple_strtoul(argv[3], &ep, 10);
7732e192b24SSimon Glass 	if (!ep || ep[0] != '\0') {
7742e192b24SSimon Glass 		printf("'%s' is not a number\n", argv[3]);
7752e192b24SSimon Glass 		return CMD_RET_USAGE;
7762e192b24SSimon Glass 	}
777db1d9e78SSimon Glass 	blk_dev_desc = blk_get_dev(argv[2], dev);
7782e192b24SSimon Glass 	if (!blk_dev_desc) {
7792e192b24SSimon Glass 		printf("%s: %s dev %d NOT available\n",
7802e192b24SSimon Glass 		       __func__, argv[2], dev);
7812e192b24SSimon Glass 		return CMD_RET_FAILURE;
7822e192b24SSimon Glass 	}
7832e192b24SSimon Glass 
7842e192b24SSimon Glass 	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
7852e192b24SSimon Glass 		printf("Writing GPT: ");
7862e192b24SSimon Glass 		ret = gpt_default(blk_dev_desc, argv[4]);
7872e192b24SSimon Glass 	} else if ((strcmp(argv[1], "verify") == 0)) {
7882e192b24SSimon Glass 		ret = gpt_verify(blk_dev_desc, argv[4]);
7892e192b24SSimon Glass 		printf("Verify GPT: ");
79073d6d18bSAlison Chaiken 	} else if (strcmp(argv[1], "guid") == 0) {
79173d6d18bSAlison Chaiken 		ret = do_disk_guid(blk_dev_desc, argv[4]);
79209a49930SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME
79309a49930SAlison Chaiken 	} else if (strcmp(argv[1], "read") == 0) {
79409a49930SAlison Chaiken 		ret = do_get_gpt_info(blk_dev_desc);
795*203f9b48SAlison Chaiken 	} else if ((strcmp(argv[1], "swap") == 0) ||
796*203f9b48SAlison Chaiken 		   (strcmp(argv[1], "rename") == 0)) {
797*203f9b48SAlison Chaiken 		ret = do_rename_gpt_parts(blk_dev_desc, argv[1], argv[4], argv[5]);
79809a49930SAlison Chaiken #endif
7992e192b24SSimon Glass 	} else {
8002e192b24SSimon Glass 		return CMD_RET_USAGE;
8012e192b24SSimon Glass 	}
8022e192b24SSimon Glass 
8032e192b24SSimon Glass 	if (ret) {
8042e192b24SSimon Glass 		printf("error!\n");
8052e192b24SSimon Glass 		return CMD_RET_FAILURE;
8062e192b24SSimon Glass 	}
8072e192b24SSimon Glass 
8082e192b24SSimon Glass 	printf("success!\n");
8092e192b24SSimon Glass 	return CMD_RET_SUCCESS;
8102e192b24SSimon Glass }
8112e192b24SSimon Glass 
8122e192b24SSimon Glass U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
8132e192b24SSimon Glass 	"GUID Partition Table",
8142e192b24SSimon Glass 	"<command> <interface> <dev> <partitions_list>\n"
8152e192b24SSimon Glass 	" - GUID partition table restoration and validity check\n"
8162e192b24SSimon Glass 	" Restore or verify GPT information on a device connected\n"
8172e192b24SSimon Glass 	" to interface\n"
8182e192b24SSimon Glass 	" Example usage:\n"
8192e192b24SSimon Glass 	" gpt write mmc 0 $partitions\n"
8202e192b24SSimon Glass 	" gpt verify mmc 0 $partitions\n"
82109a49930SAlison Chaiken 	" read <interface> <dev>\n"
82209a49930SAlison Chaiken 	"    - read GPT into a data structure for manipulation\n"
82373d6d18bSAlison Chaiken 	" guid <interface> <dev>\n"
82473d6d18bSAlison Chaiken 	"    - print disk GUID\n"
82573d6d18bSAlison Chaiken 	" guid <interface> <dev> <varname>\n"
82673d6d18bSAlison Chaiken 	"    - set environment variable to disk GUID\n"
82773d6d18bSAlison Chaiken 	" Example usage:\n"
82873d6d18bSAlison Chaiken 	" gpt guid mmc 0\n"
82973d6d18bSAlison Chaiken 	" gpt guid mmc 0 varname\n"
830*203f9b48SAlison Chaiken #ifdef CONFIG_CMD_GPT_RENAME
831*203f9b48SAlison Chaiken 	"gpt partition renaming commands:\n"
832*203f9b48SAlison Chaiken 	"gpt swap <interface> <dev> <name1> <name2>\n"
833*203f9b48SAlison Chaiken 	"    - change all partitions named name1 to name2\n"
834*203f9b48SAlison Chaiken 	"      and vice-versa\n"
835*203f9b48SAlison Chaiken 	"gpt rename <interface> <dev> <part> <name>\n"
836*203f9b48SAlison Chaiken 	"    - rename the specified partition\n"
837*203f9b48SAlison Chaiken 	" Example usage:\n"
838*203f9b48SAlison Chaiken 	" gpt swap mmc 0 foo bar\n"
839*203f9b48SAlison Chaiken 	" gpt rename mmc 0 3 foo\n"
840*203f9b48SAlison Chaiken #endif
8412e192b24SSimon Glass );
842