Blame view

cmd/gpt.c 21.8 KB
83d290c56   Tom Rini   SPDX: Convert all...
1
  // SPDX-License-Identifier: GPL-2.0+
8b0962376   Piotr Wilczek   gpt: Support for ...
2
3
4
  /*
   * cmd_gpt.c -- GPT (GUID Partition Table) handling command
   *
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
5
6
7
   * Copyright (C) 2015
   * Lukasz Majewski <l.majewski@majess.pl>
   *
8b0962376   Piotr Wilczek   gpt: Support for ...
8
9
10
   * Copyright (C) 2012 Samsung Electronics
   * author: Lukasz Majewski <l.majewski@samsung.com>
   * author: Piotr Wilczek <p.wilczek@samsung.com>
8b0962376   Piotr Wilczek   gpt: Support for ...
11
12
13
14
15
   */
  
  #include <common.h>
  #include <malloc.h>
  #include <command.h>
8b0962376   Piotr Wilczek   gpt: Support for ...
16
17
18
  #include <part_efi.h>
  #include <exports.h>
  #include <linux/ctype.h>
3e34cf7bf   Piotr Wilczek   gpt: fix partion ...
19
  #include <div64.h>
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
20
  #include <memalign.h>
09a49930e   Alison Chaiken   GPT: read partiti...
21
  #include <linux/compat.h>
203f9b48a   Alison Chaiken   GPT: provide comm...
22
23
  #include <linux/sizes.h>
  #include <stdlib.h>
09a49930e   Alison Chaiken   GPT: read partiti...
24
25
  
  static LIST_HEAD(disk_partitions);
8b0962376   Piotr Wilczek   gpt: Support for ...
26

8b0962376   Piotr Wilczek   gpt: Support for ...
27
28
29
30
31
32
33
34
35
  /**
   * extract_env(): Expand env name from string format '&{env_name}'
   *                and return pointer to the env (if the env is set)
   *
   * @param str - pointer to string
   * @param env - pointer to pointer to extracted env
   *
   * @return - zero on successful expand and env is set
   */
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
36
  static int extract_env(const char *str, char **env)
8b0962376   Piotr Wilczek   gpt: Support for ...
37
  {
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
38
  	int ret = -1;
8b0962376   Piotr Wilczek   gpt: Support for ...
39
  	char *e, *s;
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
40
41
42
  #ifdef CONFIG_RANDOM_UUID
  	char uuid_str[UUID_STR_LEN + 1];
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
43
44
45
  
  	if (!str || strlen(str) < 4)
  		return -1;
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
46
47
48
49
50
51
52
53
54
  	if (!((strncmp(str, "${", 2) == 0) && (str[strlen(str) - 1] == '}')))
  		return -1;
  
  	s = strdup(str);
  	if (s == NULL)
  		return -1;
  
  	memset(s + strlen(s) - 1, '\0', 1);
  	memmove(s, s + 2, strlen(s) - 1);
00caae6d4   Simon Glass   env: Rename geten...
55
  	e = env_get(s);
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
56
57
58
  	if (e == NULL) {
  #ifdef CONFIG_RANDOM_UUID
  		debug("%s unset. ", str);
9da52f8f6   Vincent Tinelli   gpt: Fix uuid str...
59
  		gen_rand_uuid_str(uuid_str, UUID_STR_FORMAT_GUID);
382bee57f   Simon Glass   env: Rename seten...
60
  		env_set(s, uuid_str);
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
61

00caae6d4   Simon Glass   env: Rename geten...
62
  		e = env_get(s);
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
63
64
65
66
67
68
69
  		if (e) {
  			debug("Set to random.
  ");
  			ret = 0;
  		} else {
  			debug("Can't get random UUID.
  ");
8b0962376   Piotr Wilczek   gpt: Support for ...
70
  		}
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
71
72
73
74
75
76
77
78
  #else
  		debug("%s unset.
  ", str);
  #endif
  	} else {
  		debug("%s get from environment.
  ", str);
  		ret = 0;
8b0962376   Piotr Wilczek   gpt: Support for ...
79
  	}
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
80
81
82
83
  	*env = e;
  	free(s);
  
  	return ret;
8b0962376   Piotr Wilczek   gpt: Support for ...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  }
  
  /**
   * extract_val(): Extract value from a key=value pair list (comma separated).
   *                Only value for the given key is returend.
   *                Function allocates memory for the value, remember to free!
   *
   * @param str - pointer to string with key=values pairs
   * @param key - pointer to the key to search for
   *
   * @return - pointer to allocated string with the value
   */
  static char *extract_val(const char *str, const char *key)
  {
  	char *v, *k;
  	char *s, *strcopy;
  	char *new = NULL;
  
  	strcopy = strdup(str);
  	if (strcopy == NULL)
  		return NULL;
  
  	s = strcopy;
  	while (s) {
  		v = strsep(&s, ",");
  		if (!v)
  			break;
  		k = strsep(&v, "=");
  		if (!k)
  			break;
  		if  (strcmp(k, key) == 0) {
  			new = strdup(v);
  			break;
  		}
  	}
  
  	free(strcopy);
  
  	return new;
  }
  
  /**
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
   * found_key(): Found key without value in parameter list (comma separated).
   *
   * @param str - pointer to string with key
   * @param key - pointer to the key to search for
   *
   * @return - true on found key
   */
  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;
  
  	s = strcopy;
  	while (s) {
  		k = strsep(&s, ",");
  		if (!k)
  			break;
  		if  (strcmp(k, key) == 0) {
  			result = true;
  			break;
  		}
  	}
  
  	free(strcopy);
  
  	return result;
  }
2fcaa413b   Alison Chaiken   gpt: harden set_g...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  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
  ", partlistlen,
  	      numparts);
  	return partlistlen;
  }
09a49930e   Alison Chaiken   GPT: read partiti...
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  #ifdef CONFIG_CMD_GPT_RENAME
  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;
f66bc0e0b   Heinrich Schuchardt   GPT: incomplete i...
192
  	newpart = calloc(1, sizeof(struct disk_part));
09a49930e   Alison Chaiken   GPT: read partiti...
193
194
  	if (!newpart)
  		return ERR_PTR(-ENOMEM);
09a49930e   Alison Chaiken   GPT: read partiti...
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
  
  	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;
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
216
217
218
219
220
221
222
223
224
  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);
  }
09a49930e   Alison Chaiken   GPT: read partiti...
225
226
227
228
  static void print_gpt_info(void)
  {
  	struct list_head *pos;
  	struct disk_part *curr;
203f9b48a   Alison Chaiken   GPT: provide comm...
229
230
  	char partstartstr[16];
  	char partsizestr[16];
09a49930e   Alison Chaiken   GPT: read partiti...
231
232
233
  
  	list_for_each(pos, &disk_partitions) {
  		curr = list_entry(pos, struct disk_part, list);
203f9b48a   Alison Chaiken   GPT: provide comm...
234
235
236
237
  		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);
09a49930e   Alison Chaiken   GPT: read partiti...
238
239
  		printf("Partition %d:
  ", curr->partnum);
203f9b48a   Alison Chaiken   GPT: provide comm...
240
241
  		printf("Start %s, size %s
  ", partstartstr, partsizestr);
09a49930e   Alison Chaiken   GPT: read partiti...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  		printf("Block size %lu, name %s
  ", curr->gpt_part_info.blksz,
  		       curr->gpt_part_info.name);
  		printf("Type %s, bootable %d
  ", curr->gpt_part_info.type,
  		       curr->gpt_part_info.bootable);
  #ifdef CONFIG_PARTITION_UUIDS
  		printf("UUID %s
  ", curr->gpt_part_info.uuid);
  #endif
  		printf("
  ");
  	}
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  /*
   * 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);
3a2605fa8   Patrick Delaunay   cmd: gpt: solve i...
286
287
288
  		sprintf(partstr, ",start=0x%llx",
  			(unsigned long long)curr->gpt_part_info.start *
  					    curr->gpt_part_info.blksz);
203f9b48a   Alison Chaiken   GPT: provide comm...
289
290
  		/* one extra byte for NULL */
  		strncat(partitions_list, partstr, PART_NAME_LEN + 1);
3a2605fa8   Patrick Delaunay   cmd: gpt: solve i...
291
292
293
  		sprintf(partstr, ",size=0x%llx",
  			(unsigned long long)curr->gpt_part_info.size *
  					    curr->gpt_part_info.blksz);
203f9b48a   Alison Chaiken   GPT: provide comm...
294
295
296
297
298
299
300
301
302
  		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;
  }
09a49930e   Alison Chaiken   GPT: read partiti...
303
304
305
306
307
308
309
310
311
312
  /*
   * 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;
203f9b48a   Alison Chaiken   GPT: provide comm...
313
314
315
316
317
  	/*
  	 * Always re-read partition info from device, in case
  	 * it has changed
  	 */
  	INIT_LIST_HEAD(&disk_partitions);
09a49930e   Alison Chaiken   GPT: read partiti...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  
  	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 **
  ");
  		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;
  }
  #endif
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
359
  /**
8b0962376   Piotr Wilczek   gpt: Support for ...
360
361
362
363
364
365
366
367
368
369
370
371
   * set_gpt_info(): Fill partition information from string
   *		function allocates memory, remember to free!
   *
   * @param dev_desc - pointer block device descriptor
   * @param str_part - pointer to string with partition information
   * @param str_disk_guid - pointer to pointer to allocated string with disk guid
   * @param partitions - pointer to pointer to allocated partitions array
   * @param parts_count - number of partitions
   *
   * @return - zero on success, otherwise error
   *
   */
4101f6879   Simon Glass   dm: Drop the bloc...
372
  static int set_gpt_info(struct blk_desc *dev_desc,
8b0962376   Piotr Wilczek   gpt: Support for ...
373
374
375
376
377
378
379
380
381
382
383
  			const char *str_part,
  			char **str_disk_guid,
  			disk_partition_t **partitions,
  			u8 *parts_count)
  {
  	char *tok, *str, *s;
  	int i;
  	char *val, *p;
  	int p_count;
  	disk_partition_t *parts;
  	int errno = 0;
3e34cf7bf   Piotr Wilczek   gpt: fix partion ...
384
  	uint64_t size_ll, start_ll;
666362356   Michael Trimarchi   cmd: gpt: add - p...
385
  	lbaint_t offset = 0;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
386
  	int max_str_part = calc_parts_list_len(MAX_SEARCH_PARTITIONS);
8b0962376   Piotr Wilczek   gpt: Support for ...
387

619f0fdf3   Egbert Eich   cmd/gpt: Support ...
388
389
  	debug("%s:  lba num: 0x%x %d
  ", __func__,
8b0962376   Piotr Wilczek   gpt: Support for ...
390
391
392
393
394
395
  	      (unsigned int)dev_desc->lba, (unsigned int)dev_desc->lba);
  
  	if (str_part == NULL)
  		return -1;
  
  	str = strdup(str_part);
203f9b48a   Alison Chaiken   GPT: provide comm...
396
397
  	if (str == NULL)
  		return -ENOMEM;
8b0962376   Piotr Wilczek   gpt: Support for ...
398
399
400
  
  	/* extract disk guid */
  	s = str;
0c7e8d131   Rob Herring   gpt: support rand...
401
  	val = extract_val(str, "uuid_disk");
8b0962376   Piotr Wilczek   gpt: Support for ...
402
  	if (!val) {
0c7e8d131   Rob Herring   gpt: support rand...
403
404
  #ifdef CONFIG_RANDOM_UUID
  		*str_disk_guid = malloc(UUID_STR_LEN + 1);
bf52fcdef   Tom Rini   cmd/gpt.c, cmd/nv...
405
  		if (*str_disk_guid == NULL)
2fcaa413b   Alison Chaiken   gpt: harden set_g...
406
  			return -ENOMEM;
0c7e8d131   Rob Herring   gpt: support rand...
407
408
  		gen_rand_uuid_str(*str_disk_guid, UUID_STR_FORMAT_STD);
  #else
8b0962376   Piotr Wilczek   gpt: Support for ...
409
410
  		free(str);
  		return -2;
0c7e8d131   Rob Herring   gpt: support rand...
411
412
413
414
415
416
417
418
419
  #endif
  	} else {
  		val = strsep(&val, ";");
  		if (extract_env(val, &p))
  			p = val;
  		*str_disk_guid = strdup(p);
  		free(val);
  		/* Move s to first partition */
  		strsep(&s, ";");
8b0962376   Piotr Wilczek   gpt: Support for ...
420
  	}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
421
422
423
424
425
426
  	if (s == NULL) {
  		printf("Error: is the partitions string NULL-terminated?
  ");
  		return -EINVAL;
  	}
  	if (strnlen(s, max_str_part) == 0)
8b0962376   Piotr Wilczek   gpt: Support for ...
427
  		return -3;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
428
  	i = strnlen(s, max_str_part) - 1;
8b0962376   Piotr Wilczek   gpt: Support for ...
429
430
431
432
433
434
435
436
437
438
439
440
441
  	if (s[i] == ';')
  		s[i] = '\0';
  
  	/* calculate expected number of partitions */
  	p_count = 1;
  	p = s;
  	while (*p) {
  		if (*p++ == ';')
  			p_count++;
  	}
  
  	/* allocate memory for partitions */
  	parts = calloc(sizeof(disk_partition_t), p_count);
2fcaa413b   Alison Chaiken   gpt: harden set_g...
442
443
  	if (parts == NULL)
  		return -ENOMEM;
8b0962376   Piotr Wilczek   gpt: Support for ...
444

1f8b546f9   Robert P. J. Day   Fix some obvious ...
445
  	/* retrieve partitions data from string */
8b0962376   Piotr Wilczek   gpt: Support for ...
446
447
448
449
450
451
452
453
  	for (i = 0; i < p_count; i++) {
  		tok = strsep(&s, ";");
  
  		if (tok == NULL)
  			break;
  
  		/* uuid */
  		val = extract_val(tok, "uuid");
0c7e8d131   Rob Herring   gpt: support rand...
454
455
456
457
458
  		if (!val) {
  			/* 'uuid' is optional if random uuid's are enabled */
  #ifdef CONFIG_RANDOM_UUID
  			gen_rand_uuid_str(parts[i].uuid, UUID_STR_FORMAT_STD);
  #else
8b0962376   Piotr Wilczek   gpt: Support for ...
459
460
  			errno = -4;
  			goto err;
0c7e8d131   Rob Herring   gpt: support rand...
461
462
463
464
  #endif
  		} else {
  			if (extract_env(val, &p))
  				p = val;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
465
  			if (strnlen(p, max_str_part) >= sizeof(parts[i].uuid)) {
0c7e8d131   Rob Herring   gpt: support rand...
466
467
468
469
470
  				printf("Wrong uuid format for partition %d
  ", i);
  				errno = -4;
  				goto err;
  			}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
471
  			strncpy((char *)parts[i].uuid, p, max_str_part);
0c7e8d131   Rob Herring   gpt: support rand...
472
  			free(val);
8b0962376   Piotr Wilczek   gpt: Support for ...
473
  		}
7561b258a   Patrick Delaunay   gpt: add optional...
474
475
476
477
478
479
480
  #ifdef CONFIG_PARTITION_TYPE_GUID
  		/* guid */
  		val = extract_val(tok, "type");
  		if (val) {
  			/* 'type' is optional */
  			if (extract_env(val, &p))
  				p = val;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
481
  			if (strnlen(p, max_str_part) >= sizeof(parts[i].type_guid)) {
7561b258a   Patrick Delaunay   gpt: add optional...
482
483
484
485
486
487
  				printf("Wrong type guid format for partition %d
  ",
  				       i);
  				errno = -4;
  				goto err;
  			}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
488
  			strncpy((char *)parts[i].type_guid, p, max_str_part);
7561b258a   Patrick Delaunay   gpt: add optional...
489
490
491
  			free(val);
  		}
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
492
493
494
495
496
497
498
499
  		/* name */
  		val = extract_val(tok, "name");
  		if (!val) { /* name is mandatory */
  			errno = -4;
  			goto err;
  		}
  		if (extract_env(val, &p))
  			p = val;
2fcaa413b   Alison Chaiken   gpt: harden set_g...
500
  		if (strnlen(p, max_str_part) >= sizeof(parts[i].name)) {
8b0962376   Piotr Wilczek   gpt: Support for ...
501
502
503
  			errno = -4;
  			goto err;
  		}
2fcaa413b   Alison Chaiken   gpt: harden set_g...
504
  		strncpy((char *)parts[i].name, p, max_str_part);
8b0962376   Piotr Wilczek   gpt: Support for ...
505
506
507
508
509
510
511
512
513
514
  		free(val);
  
  		/* size */
  		val = extract_val(tok, "size");
  		if (!val) { /* 'size' is mandatory */
  			errno = -4;
  			goto err;
  		}
  		if (extract_env(val, &p))
  			p = val;
666362356   Michael Trimarchi   cmd: gpt: add - p...
515
  		if ((strcmp(p, "-") == 0)) {
c2fdd3456   Kever Yang   cmd: gpt: fix the...
516
517
  			/* Let part efi module to auto extend the size */
  			parts[i].size = 0;
666362356   Michael Trimarchi   cmd: gpt: add - p...
518
519
520
521
  		} else {
  			size_ll = ustrtoull(p, &p, 0);
  			parts[i].size = lldiv(size_ll, dev_desc->blksz);
  		}
8b0962376   Piotr Wilczek   gpt: Support for ...
522
523
524
525
526
527
528
  		free(val);
  
  		/* start address */
  		val = extract_val(tok, "start");
  		if (val) { /* start address is optional */
  			if (extract_env(val, &p))
  				p = val;
3e34cf7bf   Piotr Wilczek   gpt: fix partion ...
529
530
  			start_ll = ustrtoull(p, &p, 0);
  			parts[i].start = lldiv(start_ll, dev_desc->blksz);
8b0962376   Piotr Wilczek   gpt: Support for ...
531
532
  			free(val);
  		}
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
533

666362356   Michael Trimarchi   cmd: gpt: add - p...
534
  		offset += parts[i].size + parts[i].start;
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
535
536
537
  		/* bootable */
  		if (found_key(tok, "bootable"))
  			parts[i].bootable = 1;
8b0962376   Piotr Wilczek   gpt: Support for ...
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  	}
  
  	*parts_count = p_count;
  	*partitions = parts;
  	free(str);
  
  	return 0;
  err:
  	free(str);
  	free(*str_disk_guid);
  	free(parts);
  
  	return errno;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
552
  static int gpt_default(struct blk_desc *blk_dev_desc, const char *str_part)
8b0962376   Piotr Wilczek   gpt: Support for ...
553
554
555
556
557
  {
  	int ret;
  	char *str_disk_guid;
  	u8 part_count = 0;
  	disk_partition_t *partitions = NULL;
8b0962376   Piotr Wilczek   gpt: Support for ...
558
  	/* fill partitions */
619f0fdf3   Egbert Eich   cmd/gpt: Support ...
559
  	ret = set_gpt_info(blk_dev_desc, str_part,
8b0962376   Piotr Wilczek   gpt: Support for ...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  			&str_disk_guid, &partitions, &part_count);
  	if (ret) {
  		if (ret == -1)
  			printf("No partition list provided
  ");
  		if (ret == -2)
  			printf("Missing disk guid
  ");
  		if ((ret == -3) || (ret == -4))
  			printf("Partition list incomplete
  ");
  		return -1;
  	}
  
  	/* save partitions layout to disk */
a150e6c9d   Rob Herring   gpt: fix error re...
575
  	ret = gpt_restore(blk_dev_desc, str_disk_guid, partitions, part_count);
8b0962376   Piotr Wilczek   gpt: Support for ...
576
577
  	free(str_disk_guid);
  	free(partitions);
a150e6c9d   Rob Herring   gpt: fix error re...
578
  	return ret;
8b0962376   Piotr Wilczek   gpt: Support for ...
579
  }
4101f6879   Simon Glass   dm: Drop the bloc...
580
  static int gpt_verify(struct blk_desc *blk_dev_desc, const char *str_part)
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
  {
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1,
  				     blk_dev_desc->blksz);
  	disk_partition_t *partitions = NULL;
  	gpt_entry *gpt_pte = NULL;
  	char *str_disk_guid;
  	u8 part_count = 0;
  	int ret = 0;
  
  	/* fill partitions */
  	ret = set_gpt_info(blk_dev_desc, str_part,
  			&str_disk_guid, &partitions, &part_count);
  	if (ret) {
  		if (ret == -1) {
  			printf("No partition list provided - only basic check
  ");
  			ret = gpt_verify_headers(blk_dev_desc, gpt_head,
  						 &gpt_pte);
  			goto out;
  		}
  		if (ret == -2)
  			printf("Missing disk guid
  ");
  		if ((ret == -3) || (ret == -4))
  			printf("Partition list incomplete
  ");
  		return -1;
  	}
  
  	/* Check partition layout with provided pattern */
  	ret = gpt_verify_partitions(blk_dev_desc, partitions, part_count,
  				    gpt_head, &gpt_pte);
  	free(str_disk_guid);
  	free(partitions);
   out:
  	free(gpt_pte);
  	return ret;
  }
73d6d18b7   Alison Chaiken   GPT: add accessor...
619
620
621
622
623
624
625
626
627
628
  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)
382bee57f   Simon Glass   env: Rename seten...
629
  		env_set(namestr, disk_guid);
73d6d18b7   Alison Chaiken   GPT: add accessor...
630
631
632
633
634
635
  	else
  		printf("%s
  ", disk_guid);
  
  	return ret;
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
636
  #ifdef CONFIG_CMD_GPT_RENAME
18030d04d   Alison Chaiken   GPT: fix memory l...
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  /*
   * There are 3 malloc() calls in set_gpt_info() and there is no info about which
   * failed.
   */
  static void set_gpt_cleanup(char **str_disk_guid,
  			    disk_partition_t **partitions)
  {
  #ifdef CONFIG_RANDOM_UUID
  	if (str_disk_guid)
  		free(str_disk_guid);
  #endif
  	if (partitions)
  		free(partitions);
  }
203f9b48a   Alison Chaiken   GPT: provide comm...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
  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;
18030d04d   Alison Chaiken   GPT: fix memory l...
669
670
671
672
  	/*
  	 * Allocates disk_partitions, requiring matching call to del_gpt_info()
  	 * if successful.
  	 */
203f9b48a   Alison Chaiken   GPT: provide comm...
673
674
675
676
677
678
  	numparts = get_gpt_info(dev_desc);
  	if (numparts <=  0)
  		return numparts ? numparts : -ENODEV;
  
  	partlistlen = calc_parts_list_len(numparts);
  	partitions_list = malloc(partlistlen);
18030d04d   Alison Chaiken   GPT: fix memory l...
679
680
  	if (!partitions_list) {
  		del_gpt_info();
203f9b48a   Alison Chaiken   GPT: provide comm...
681
  		return -ENOMEM;
18030d04d   Alison Chaiken   GPT: fix memory l...
682
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
683
684
685
  	memset(partitions_list, '\0', partlistlen);
  
  	ret = create_gpt_partitions_list(numparts, disk_guid, partitions_list);
18030d04d   Alison Chaiken   GPT: fix memory l...
686
687
  	if (ret < 0) {
  		free(partitions_list);
203f9b48a   Alison Chaiken   GPT: provide comm...
688
  		return ret;
18030d04d   Alison Chaiken   GPT: fix memory l...
689
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
690
691
692
693
694
695
696
  	/*
  	 * 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
  ", partitions_list,
  	      (unsigned)strlen(partitions_list));
18030d04d   Alison Chaiken   GPT: fix memory l...
697
  	/* set_gpt_info allocates new_partitions and str_disk_guid */
203f9b48a   Alison Chaiken   GPT: provide comm...
698
699
  	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
  			   &new_partitions, &part_count);
18030d04d   Alison Chaiken   GPT: fix memory l...
700
701
702
703
704
705
706
707
  	if (ret < 0) {
  		del_gpt_info();
  		free(partitions_list);
  		if (ret == -ENOMEM)
  			set_gpt_cleanup(&str_disk_guid, &new_partitions);
  		else
  			goto out;
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
708
709
710
711
712
  
  	if (!strcmp(subcomm, "swap")) {
  		if ((strlen(name1) > PART_NAME_LEN) || (strlen(name2) > PART_NAME_LEN)) {
  			printf("Names longer than %d characters are truncated.
  ", PART_NAME_LEN);
18030d04d   Alison Chaiken   GPT: fix memory l...
713
714
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
715
716
717
718
719
720
721
722
723
724
725
726
727
728
  		}
  		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.
  ");
18030d04d   Alison Chaiken   GPT: fix memory l...
729
730
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
731
732
733
734
735
  		}
  	} else { /* rename */
  		if (strlen(name2) > PART_NAME_LEN) {
  			printf("Names longer than %d characters are truncated.
  ", PART_NAME_LEN);
18030d04d   Alison Chaiken   GPT: fix memory l...
736
737
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
738
739
740
741
742
  		}
  		partnum = (int)simple_strtol(name1, NULL, 10);
  		if ((partnum < 0) || (partnum > numparts)) {
  			printf("Illegal partition number %s
  ", name1);
18030d04d   Alison Chaiken   GPT: fix memory l...
743
744
  			ret = -EINVAL;
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
745
746
747
  		}
  		ret = part_get_info(dev_desc, partnum, new_partitions);
  		if (ret < 0)
18030d04d   Alison Chaiken   GPT: fix memory l...
748
  			goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
  
  		/* U-Boot partition numbering starts at 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)
18030d04d   Alison Chaiken   GPT: fix memory l...
763
  		goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
764
765
766
767
768
769
  	debug("NEW partitions_list is %s with %u chars
  ", partitions_list,
  	      (unsigned)strlen(partitions_list));
  
  	ret = set_gpt_info(dev_desc, partitions_list, &str_disk_guid,
  			   &new_partitions, &part_count);
18030d04d   Alison Chaiken   GPT: fix memory l...
770
771
772
773
774
775
776
777
778
779
780
781
  	/*
  	 * Even though valid pointers are here passed into set_gpt_info(),
  	 * it mallocs again, and there's no way to tell which failed.
  	 */
  	if (ret < 0) {
  		del_gpt_info();
  		free(partitions_list);
  		if (ret == -ENOMEM)
  			set_gpt_cleanup(&str_disk_guid, &new_partitions);
  		else
  			goto out;
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
782
783
784
785
786
787
788
  
  	debug("Writing new partition table
  ");
  	ret = gpt_restore(dev_desc, disk_guid, new_partitions, numparts);
  	if (ret < 0) {
  		printf("Writing new partition table failed
  ");
18030d04d   Alison Chaiken   GPT: fix memory l...
789
  		goto out;
203f9b48a   Alison Chaiken   GPT: provide comm...
790
791
792
793
  	}
  
  	debug("Reading back new partition table
  ");
18030d04d   Alison Chaiken   GPT: fix memory l...
794
795
796
797
798
  	/*
  	 * Empty the existing disk_partitions list, as otherwise the memory in
  	 * the original list is unreachable.
  	 */
  	del_gpt_info();
203f9b48a   Alison Chaiken   GPT: provide comm...
799
  	numparts = get_gpt_info(dev_desc);
18030d04d   Alison Chaiken   GPT: fix memory l...
800
801
802
803
  	if (numparts <=  0) {
  		ret = numparts ? numparts : -ENODEV;
  		goto out;
  	}
203f9b48a   Alison Chaiken   GPT: provide comm...
804
805
806
  	printf("new partition table with %d partitions is:
  ", numparts);
  	print_gpt_info();
203f9b48a   Alison Chaiken   GPT: provide comm...
807
  	del_gpt_info();
18030d04d   Alison Chaiken   GPT: fix memory l...
808
   out:
203f9b48a   Alison Chaiken   GPT: provide comm...
809
  	free(new_partitions);
18030d04d   Alison Chaiken   GPT: fix memory l...
810
811
  	free(str_disk_guid);
  	free(partitions_list);
203f9b48a   Alison Chaiken   GPT: provide comm...
812
813
814
  	return ret;
  }
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
  /**
   * do_gpt(): Perform GPT operations
   *
   * @param cmdtp - command name
   * @param flag
   * @param argc
   * @param argv
   *
   * @return zero on success; otherwise error
   */
  static int do_gpt(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  {
  	int ret = CMD_RET_SUCCESS;
  	int dev = 0;
619f0fdf3   Egbert Eich   cmd/gpt: Support ...
829
  	char *ep;
4101f6879   Simon Glass   dm: Drop the bloc...
830
  	struct blk_desc *blk_dev_desc = NULL;
8b0962376   Piotr Wilczek   gpt: Support for ...
831

203f9b48a   Alison Chaiken   GPT: provide comm...
832
  #ifndef CONFIG_CMD_GPT_RENAME
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
833
  	if (argc < 4 || argc > 5)
203f9b48a   Alison Chaiken   GPT: provide comm...
834
835
836
  #else
  	if (argc < 4 || argc > 6)
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
837
  		return CMD_RET_USAGE;
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
838
839
840
841
842
843
  	dev = (int)simple_strtoul(argv[3], &ep, 10);
  	if (!ep || ep[0] != '\0') {
  		printf("'%s' is not a number
  ", argv[3]);
  		return CMD_RET_USAGE;
  	}
db1d9e78e   Simon Glass   dm: blk: Rename g...
844
  	blk_dev_desc = blk_get_dev(argv[2], dev);
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
845
846
847
848
849
850
  	if (!blk_dev_desc) {
  		printf("%s: %s dev %d NOT available
  ",
  		       __func__, argv[2], dev);
  		return CMD_RET_FAILURE;
  	}
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
851

bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
852
853
  	if ((strcmp(argv[1], "write") == 0) && (argc == 5)) {
  		printf("Writing GPT: ");
39206382d   Przemyslaw Marczak   cmd:gpt: randomly...
854
  		ret = gpt_default(blk_dev_desc, argv[4]);
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
855
856
857
  	} else if ((strcmp(argv[1], "verify") == 0)) {
  		ret = gpt_verify(blk_dev_desc, argv[4]);
  		printf("Verify GPT: ");
73d6d18b7   Alison Chaiken   GPT: add accessor...
858
859
  	} else if (strcmp(argv[1], "guid") == 0) {
  		ret = do_disk_guid(blk_dev_desc, argv[4]);
09a49930e   Alison Chaiken   GPT: read partiti...
860
861
862
  #ifdef CONFIG_CMD_GPT_RENAME
  	} else if (strcmp(argv[1], "read") == 0) {
  		ret = do_get_gpt_info(blk_dev_desc);
203f9b48a   Alison Chaiken   GPT: provide comm...
863
864
865
  	} 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]);
09a49930e   Alison Chaiken   GPT: read partiti...
866
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
867
868
869
  	} else {
  		return CMD_RET_USAGE;
  	}
bbb9ffac6   Lukasz Majewski   gpt: command: Ext...
870
871
872
873
874
875
876
877
878
879
  
  	if (ret) {
  		printf("error!
  ");
  		return CMD_RET_FAILURE;
  	}
  
  	printf("success!
  ");
  	return CMD_RET_SUCCESS;
8b0962376   Piotr Wilczek   gpt: Support for ...
880
881
882
883
  }
  
  U_BOOT_CMD(gpt, CONFIG_SYS_MAXARGS, 1, do_gpt,
  	"GUID Partition Table",
1f8b546f9   Robert P. J. Day   Fix some obvious ...
884
885
  	"<command> <interface> <dev> <partitions_list>
  "
74f889b03   Lukasz Majewski   gpt: doc: Update ...
886
887
888
889
  	" - GUID partition table restoration and validity check
  "
  	" Restore or verify GPT information on a device connected
  "
8b0962376   Piotr Wilczek   gpt: Support for ...
890
891
  	" to interface
  "
74f889b03   Lukasz Majewski   gpt: doc: Update ...
892
893
894
895
896
897
  	" Example usage:
  "
  	" gpt write mmc 0 $partitions
  "
  	" gpt verify mmc 0 $partitions
  "
09a49930e   Alison Chaiken   GPT: read partiti...
898
899
900
901
  	" read <interface> <dev>
  "
  	"    - read GPT into a data structure for manipulation
  "
73d6d18b7   Alison Chaiken   GPT: add accessor...
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  	" guid <interface> <dev>
  "
  	"    - print disk GUID
  "
  	" guid <interface> <dev> <varname>
  "
  	"    - set environment variable to disk GUID
  "
  	" Example usage:
  "
  	" gpt guid mmc 0
  "
  	" gpt guid mmc 0 varname
  "
203f9b48a   Alison Chaiken   GPT: provide comm...
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
  #ifdef CONFIG_CMD_GPT_RENAME
  	"gpt partition renaming commands:
  "
  	"gpt swap <interface> <dev> <name1> <name2>
  "
  	"    - change all partitions named name1 to name2
  "
  	"      and vice-versa
  "
  	"gpt rename <interface> <dev> <part> <name>
  "
  	"    - rename the specified partition
  "
  	" Example usage:
  "
  	" gpt swap mmc 0 foo bar
  "
  	" gpt rename mmc 0 3 foo
  "
  #endif
8b0962376   Piotr Wilczek   gpt: Support for ...
936
  );