part_efi.c 27.1 KB
Newer Older
1 2 3 4
/*
 * Copyright (C) 2008 RuggedCom, Inc.
 * Richard Retanubun <RichardRetanubun@RuggedCom.com>
 *
5
 * SPDX-License-Identifier:	GPL-2.0+
6 7 8
 */

/*
9 10 11
 * NOTE:
 *   when CONFIG_SYS_64BIT_LBA is not defined, lbaint_t is 32 bits; this
 *   limits the maximum size of addressable storage to < 2 Terra Bytes
12
 */
13
#include <asm/unaligned.h>
14 15 16
#include <common.h>
#include <command.h>
#include <ide.h>
17
#include <inttypes.h>
18
#include <malloc.h>
19
#include <memalign.h>
20
#include <part_efi.h>
21
#include <linux/ctype.h>
22

23 24
DECLARE_GLOBAL_DATA_PTR;

25
#ifdef HAVE_BLOCK_DEVICE
26 27 28 29 30 31 32
/**
 * efi_crc32() - EFI version of crc32 function
 * @buf: buffer to calculate crc32 of
 * @len - length of buf
 *
 * Description: Returns EFI-style CRC32 value for @buf
 */
33
static inline u32 efi_crc32(const void *buf, u32 len)
34 35 36 37 38 39 40 41 42 43
{
	return crc32(0, buf, len);
}

/*
 * Private function prototypes
 */

static int pmbr_part_valid(struct partition *part);
static int is_pmbr_valid(legacy_mbr * mbr);
44
static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
45
				gpt_header *pgpt_head, gpt_entry **pgpt_pte);
46 47
static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
					 gpt_header *pgpt_head);
48 49
static int is_pte_valid(gpt_entry * pte);

50 51 52 53 54 55 56 57 58 59 60 61 62 63
static char *print_efiname(gpt_entry *pte)
{
	static char name[PARTNAME_SZ + 1];
	int i;
	for (i = 0; i < PARTNAME_SZ; i++) {
		u8 c;
		c = pte->partition_name[i] & 0xff;
		c = (c && !isprint(c)) ? '.' : c;
		name[i] = c;
	}
	name[PARTNAME_SZ] = 0;
	return name;
}

64 65 66 67 68 69 70 71 72
static efi_guid_t system_guid = PARTITION_SYSTEM_GUID;

static inline int is_bootable(gpt_entry *p)
{
	return p->attributes.fields.legacy_bios_bootable ||
		!memcmp(&(p->partition_type_guid), &system_guid,
			sizeof(efi_guid_t));
}

73 74 75 76 77 78 79 80 81 82 83 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 126 127 128 129 130 131 132 133 134 135
static int validate_gpt_header(gpt_header *gpt_h, lbaint_t lba,
		lbaint_t lastlba)
{
	uint32_t crc32_backup = 0;
	uint32_t calc_crc32;

	/* Check the GPT header signature */
	if (le64_to_cpu(gpt_h->signature) != GPT_HEADER_SIGNATURE) {
		printf("%s signature is wrong: 0x%llX != 0x%llX\n",
		       "GUID Partition Table Header",
		       le64_to_cpu(gpt_h->signature),
		       GPT_HEADER_SIGNATURE);
		return -1;
	}

	/* Check the GUID Partition Table CRC */
	memcpy(&crc32_backup, &gpt_h->header_crc32, sizeof(crc32_backup));
	memset(&gpt_h->header_crc32, 0, sizeof(gpt_h->header_crc32));

	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
		le32_to_cpu(gpt_h->header_size));

	memcpy(&gpt_h->header_crc32, &crc32_backup, sizeof(crc32_backup));

	if (calc_crc32 != le32_to_cpu(crc32_backup)) {
		printf("%s CRC is wrong: 0x%x != 0x%x\n",
		       "GUID Partition Table Header",
		       le32_to_cpu(crc32_backup), calc_crc32);
		return -1;
	}

	/*
	 * Check that the my_lba entry points to the LBA that contains the GPT
	 */
	if (le64_to_cpu(gpt_h->my_lba) != lba) {
		printf("GPT: my_lba incorrect: %llX != " LBAF "\n",
		       le64_to_cpu(gpt_h->my_lba),
		       lba);
		return -1;
	}

	/*
	 * Check that the first_usable_lba and that the last_usable_lba are
	 * within the disk.
	 */
	if (le64_to_cpu(gpt_h->first_usable_lba) > lastlba) {
		printf("GPT: first_usable_lba incorrect: %llX > " LBAF "\n",
		       le64_to_cpu(gpt_h->first_usable_lba), lastlba);
		return -1;
	}
	if (le64_to_cpu(gpt_h->last_usable_lba) > lastlba) {
		printf("GPT: last_usable_lba incorrect: %llX > " LBAF "\n",
		       le64_to_cpu(gpt_h->last_usable_lba), lastlba);
		return -1;
	}

	debug("GPT: first_usable_lba: %llX last_usable_lba: %llX last lba: "
	      LBAF "\n", le64_to_cpu(gpt_h->first_usable_lba),
	      le64_to_cpu(gpt_h->last_usable_lba), lastlba);

	return 0;
}

136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
static void prepare_last_lba_gpt_header(struct blk_desc *dev_desc, gpt_header *gpt_h)
{
	uint32_t calc_crc32;
	uint64_t val;

	/* recalculate the values for the Backup GPT Header */
	val = le64_to_cpu(gpt_h->my_lba);
	gpt_h->my_lba = cpu_to_le64(dev_desc->lba - 1);;
	gpt_h->alternate_lba = cpu_to_le64(val);
	gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
	gpt_h->partition_entry_lba =
			cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1);
	gpt_h->header_crc32 = 0;

	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
			       le32_to_cpu(gpt_h->header_size));
	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
}

155 156 157 158 159 160 161 162 163 164
static int validate_gpt_entries(gpt_header *gpt_h, gpt_entry *gpt_e)
{
	uint32_t calc_crc32;

	/* Check the GUID Partition Table Entry Array CRC */
	calc_crc32 = efi_crc32((const unsigned char *)gpt_e,
		le32_to_cpu(gpt_h->num_partition_entries) *
		le32_to_cpu(gpt_h->sizeof_partition_entry));

	if (calc_crc32 != le32_to_cpu(gpt_h->partition_entry_array_crc32)) {
165
		debug("%s: 0x%x != 0x%x\n",
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
		       "GUID Partition Table Entry Array CRC is wrong",
		       le32_to_cpu(gpt_h->partition_entry_array_crc32),
		       calc_crc32);
		return -1;
	}

	return 0;
}

static void prepare_backup_gpt_header(gpt_header *gpt_h)
{
	uint32_t calc_crc32;
	uint64_t val;

	/* recalculate the values for the Backup GPT Header */
	val = le64_to_cpu(gpt_h->my_lba);
	gpt_h->my_lba = gpt_h->alternate_lba;
	gpt_h->alternate_lba = cpu_to_le64(val);
184 185
	gpt_h->partition_entry_lba =
			cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1);
186 187 188 189 190 191
	gpt_h->header_crc32 = 0;

	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
			       le32_to_cpu(gpt_h->header_size));
	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);
}
192
#if CONFIG_IS_ENABLED(EFI_PARTITION)
193 194 195 196
/*
 * Public Functions (include/part.h)
 */

197
void part_print_efi(struct blk_desc *dev_desc)
198
{
199
	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
200
	gpt_entry *gpt_pte = NULL;
201
	int i = 0;
202
	char uuid[37];
203
	unsigned char *uuid_bin;
204 205 206

	/* This function validates AND fills in the GPT header and PTE */
	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
207
			 gpt_head, &gpt_pte) != 1) {
208
		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
209 210 211 212 213 214 215 216 217
		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
				 gpt_head, &gpt_pte) != 1) {
			printf("%s: *** ERROR: Invalid Backup GPT ***\n",
			       __func__);
			return;
		} else {
			printf("%s: ***        Using Backup GPT ***\n",
			       __func__);
		}
218 219
	}

220
	debug("%s: gpt-entry at %p\n", __func__, gpt_pte);
221

222
	printf("Part\tStart LBA\tEnd LBA\t\tName\n");
223
	printf("\tAttributes\n");
224 225
	printf("\tType GUID\n");
	printf("\tPartition GUID\n");
226

227
	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
228 229 230 231
		/* Stop at the first non valid PTE */
		if (!is_pte_valid(&gpt_pte[i]))
			break;

232
		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
233 234
			le64_to_cpu(gpt_pte[i].starting_lba),
			le64_to_cpu(gpt_pte[i].ending_lba),
235
			print_efiname(&gpt_pte[i]));
236
		printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);
237
		uuid_bin = (unsigned char *)gpt_pte[i].partition_type_guid.b;
238
		uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
239
		printf("\ttype:\t%s\n", uuid);
240 241 242 243
#ifdef CONFIG_PARTITION_TYPE_GUID
		if (!uuid_guid_get_str(uuid_bin, uuid))
			printf("\ttype:\t%s\n", uuid);
#endif
244
		uuid_bin = (unsigned char *)gpt_pte[i].unique_partition_guid.b;
245 246
		uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
		printf("\tguid:\t%s\n", uuid);
247 248 249
	}

	/* Remember to free pte */
250
	free(gpt_pte);
251 252 253
	return;
}

254 255
int part_get_info_efi(struct blk_desc *dev_desc, int part,
		      disk_partition_t *info)
256
{
257
	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
258
	gpt_entry *gpt_pte = NULL;
259 260

	/* "part" argument must be at least 1 */
261
	if (part < 1) {
262
		printf("%s: Invalid Argument(s)\n", __func__);
263 264 265 266 267
		return -1;
	}

	/* This function validates AND fills in the GPT header and PTE */
	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
268
			gpt_head, &gpt_pte) != 1) {
269
		debug("%s: *** ERROR: Invalid GPT ***\n", __func__);
270 271 272 273 274 275
		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 {
276
			debug("%s: ***        Using Backup GPT ***\n",
277 278
			       __func__);
		}
279 280
	}

281
	if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
282
	    !is_pte_valid(&gpt_pte[part - 1])) {
283
		debug("%s: *** ERROR: Invalid partition number %d ***\n",
284
			__func__, part);
285
		free(gpt_pte);
286 287 288
		return -1;
	}

289 290
	/* The 'lbaint_t' casting may limit the maximum disk size to 2 TB */
	info->start = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].starting_lba);
291
	/* The ending LBA is inclusive, to calculate size, add 1 to it */
292
	info->size = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1
293
		     - info->start;
294
	info->blksz = dev_desc->blksz;
295

296
	sprintf((char *)info->name, "%s",
297
			print_efiname(&gpt_pte[part - 1]));
298
	strcpy((char *)info->type, "U-Boot");
299
	info->bootable = is_bootable(&gpt_pte[part - 1]);
300
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
301 302
	uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b, info->uuid,
			UUID_STR_FORMAT_GUID);
303
#endif
304 305 306 307
#ifdef CONFIG_PARTITION_TYPE_GUID
	uuid_bin_to_str(gpt_pte[part - 1].partition_type_guid.b,
			info->type_guid, UUID_STR_FORMAT_GUID);
#endif
308

309
	debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s\n", __func__,
310
	      info->start, info->size, info->name);
311 312

	/* Remember to free pte */
313
	free(gpt_pte);
314 315 316
	return 0;
}

317
static int part_test_efi(struct blk_desc *dev_desc)
318
{
319
	ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, legacymbr, 1, dev_desc->blksz);
320 321

	/* Read legacy MBR from block 0 and validate it */
322
	if ((blk_dread(dev_desc, 0, 1, (ulong *)legacymbr) != 1)
323
		|| (is_pmbr_valid(legacymbr) != 1)) {
324 325 326 327 328
		return -1;
	}
	return 0;
}

329 330 331 332 333 334
/**
 * set_protective_mbr(): Set the EFI protective MBR
 * @param dev_desc - block device descriptor
 *
 * @return - zero on success, otherwise error
 */
335
static int set_protective_mbr(struct blk_desc *dev_desc)
336 337
{
	/* Setup the Protective MBR */
338 339 340
	ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, p_mbr, 1);
	memset(p_mbr, 0, sizeof(*p_mbr));

341 342 343 344
	if (p_mbr == NULL) {
		printf("%s: calloc failed!\n", __func__);
		return -1;
	}
345 346 347 348 349 350 351

	/* Read MBR to backup boot code if it exists */
	if (blk_dread(dev_desc, 0, 1, p_mbr) != 1) {
		error("** Can't read from device %d **\n", dev_desc->devnum);
		return -1;
	}

352 353 354 355
	/* Append signature */
	p_mbr->signature = MSDOS_MBR_SIGNATURE;
	p_mbr->partition_record[0].sys_ind = EFI_PMBR_OSTYPE_EFI_GPT;
	p_mbr->partition_record[0].start_sect = 1;
356
	p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba - 1;
357 358

	/* Write MBR sector to the MMC device */
359
	if (blk_dwrite(dev_desc, 0, 1, p_mbr) != 1) {
360
		printf("** Can't write to device %d **\n",
361
			dev_desc->devnum);
362 363 364 365 366 367
		return -1;
	}

	return 0;
}

368
int write_gpt_table(struct blk_desc *dev_desc,
369 370
		gpt_header *gpt_h, gpt_entry *gpt_e)
{
371 372
	const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries
					   * sizeof(gpt_entry)), dev_desc);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	u32 calc_crc32;

	debug("max lba: %x\n", (u32) dev_desc->lba);
	/* Setup the Protective MBR */
	if (set_protective_mbr(dev_desc) < 0)
		goto err;

	/* Generate CRC for the Primary GPT Header */
	calc_crc32 = efi_crc32((const unsigned char *)gpt_e,
			      le32_to_cpu(gpt_h->num_partition_entries) *
			      le32_to_cpu(gpt_h->sizeof_partition_entry));
	gpt_h->partition_entry_array_crc32 = cpu_to_le32(calc_crc32);

	calc_crc32 = efi_crc32((const unsigned char *)gpt_h,
			      le32_to_cpu(gpt_h->header_size));
	gpt_h->header_crc32 = cpu_to_le32(calc_crc32);

	/* Write the First GPT to the block right after the Legacy MBR */
391
	if (blk_dwrite(dev_desc, 1, 1, gpt_h) != 1)
392 393
		goto err;

394
	if (blk_dwrite(dev_desc, 2, pte_blk_cnt, gpt_e)
395
	    != pte_blk_cnt)
396 397
		goto err;

398
	prepare_backup_gpt_header(gpt_h);
399

400 401
	if (blk_dwrite(dev_desc, (lbaint_t)le64_to_cpu(gpt_h->last_usable_lba)
		       + 1, pte_blk_cnt, gpt_e) != pte_blk_cnt)
402 403
		goto err;

404 405
	if (blk_dwrite(dev_desc, (lbaint_t)le64_to_cpu(gpt_h->my_lba), 1,
		       gpt_h) != 1)
406 407 408 409 410 411
		goto err;

	debug("GPT successfully written to block device!\n");
	return 0;

 err:
412
	printf("** Can't write to device %d **\n", dev_desc->devnum);
413 414 415 416 417 418
	return -1;
}

int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e,
		disk_partition_t *partitions, int parts)
{
419 420 421 422
	lbaint_t offset = (lbaint_t)le64_to_cpu(gpt_h->first_usable_lba);
	lbaint_t start;
	lbaint_t last_usable_lba = (lbaint_t)
			le64_to_cpu(gpt_h->last_usable_lba);
423
	int i, k;
424
	size_t efiname_len, dosname_len;
425
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
426
	char *str_uuid;
427
	unsigned char *bin_uuid;
428
#endif
429 430 431 432
#ifdef CONFIG_PARTITION_TYPE_GUID
	char *str_type_guid;
	unsigned char *bin_type_guid;
#endif
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

	for (i = 0; i < parts; i++) {
		/* partition starting lba */
		start = partitions[i].start;
		if (start && (start < offset)) {
			printf("Partition overlap\n");
			return -1;
		}
		if (start) {
			gpt_e[i].starting_lba = cpu_to_le64(start);
			offset = start + partitions[i].size;
		} else {
			gpt_e[i].starting_lba = cpu_to_le64(offset);
			offset += partitions[i].size;
		}
448
		if (offset > (last_usable_lba + 1)) {
449 450 451 452 453 454 455 456 457 458
			printf("Partitions layout exceds disk size\n");
			return -1;
		}
		/* partition ending lba */
		if ((i == parts - 1) && (partitions[i].size == 0))
			/* extend the last partition to maximuim */
			gpt_e[i].ending_lba = gpt_h->last_usable_lba;
		else
			gpt_e[i].ending_lba = cpu_to_le64(offset - 1);

459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
#ifdef CONFIG_PARTITION_TYPE_GUID
		str_type_guid = partitions[i].type_guid;
		bin_type_guid = gpt_e[i].partition_type_guid.b;
		if (strlen(str_type_guid)) {
			if (uuid_str_to_bin(str_type_guid, bin_type_guid,
					    UUID_STR_FORMAT_GUID)) {
				printf("Partition no. %d: invalid type guid: %s\n",
				       i, str_type_guid);
				return -1;
			}
		} else {
			/* default partition type GUID */
			memcpy(bin_type_guid,
			       &PARTITION_BASIC_DATA_GUID, 16);
		}
#else
475 476 477
		/* partition type GUID */
		memcpy(gpt_e[i].partition_type_guid.b,
			&PARTITION_BASIC_DATA_GUID, 16);
478
#endif
479

480
#if CONFIG_IS_ENABLED(PARTITION_UUIDS)
481
		str_uuid = partitions[i].uuid;
482 483
		bin_uuid = gpt_e[i].unique_partition_guid.b;

484
		if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_STD)) {
485 486 487 488 489 490 491 492 493 494
			printf("Partition no. %d: invalid guid: %s\n",
				i, str_uuid);
			return -1;
		}
#endif

		/* partition attributes */
		memset(&gpt_e[i].attributes, 0,
		       sizeof(gpt_entry_attributes));

495 496 497
		if (partitions[i].bootable)
			gpt_e[i].attributes.fields.legacy_bios_bootable = 1;

498
		/* partition name */
499
		efiname_len = sizeof(gpt_e[i].partition_name)
500
			/ sizeof(efi_char16_t);
501 502 503 504 505 506
		dosname_len = sizeof(partitions[i].name);

		memset(gpt_e[i].partition_name, 0,
		       sizeof(gpt_e[i].partition_name));

		for (k = 0; k < min(dosname_len, efiname_len); k++)
507 508 509
			gpt_e[i].partition_name[k] =
				(efi_char16_t)(partitions[i].name[k]);

510 511
		debug("%s: name: %s offset[%d]: 0x" LBAF
		      " size[%d]: 0x" LBAF "\n",
512 513 514 515 516 517 518
		      __func__, partitions[i].name, i,
		      offset, i, partitions[i].size);
	}

	return 0;
}

519
int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h,
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
		char *str_guid, int parts_count)
{
	gpt_h->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
	gpt_h->revision = cpu_to_le32(GPT_HEADER_REVISION_V1);
	gpt_h->header_size = cpu_to_le32(sizeof(gpt_header));
	gpt_h->my_lba = cpu_to_le64(1);
	gpt_h->alternate_lba = cpu_to_le64(dev_desc->lba - 1);
	gpt_h->first_usable_lba = cpu_to_le64(34);
	gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
	gpt_h->partition_entry_lba = cpu_to_le64(2);
	gpt_h->num_partition_entries = cpu_to_le32(GPT_ENTRY_NUMBERS);
	gpt_h->sizeof_partition_entry = cpu_to_le32(sizeof(gpt_entry));
	gpt_h->header_crc32 = 0;
	gpt_h->partition_entry_array_crc32 = 0;

535
	if (uuid_str_to_bin(str_guid, gpt_h->disk_guid.b, UUID_STR_FORMAT_GUID))
536 537 538 539 540
		return -1;

	return 0;
}

541
int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
542 543 544 545
		disk_partition_t *partitions, int parts_count)
{
	int ret;

546 547 548 549
	gpt_header *gpt_h = calloc(1, PAD_TO_BLOCKSIZE(sizeof(gpt_header),
						       dev_desc));
	gpt_entry *gpt_e;

550 551 552 553 554
	if (gpt_h == NULL) {
		printf("%s: calloc failed!\n", __func__);
		return -1;
	}

555 556 557
	gpt_e = calloc(1, PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS
					       * sizeof(gpt_entry),
					       dev_desc));
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
	if (gpt_e == NULL) {
		printf("%s: calloc failed!\n", __func__);
		free(gpt_h);
		return -1;
	}

	/* Generate Primary GPT header (LBA1) */
	ret = gpt_fill_header(dev_desc, gpt_h, str_disk_guid, parts_count);
	if (ret)
		goto err;

	/* Generate partition entries */
	ret = gpt_fill_pte(gpt_h, gpt_e, partitions, parts_count);
	if (ret)
		goto err;

	/* Write GPT partition table */
	ret = write_gpt_table(dev_desc, gpt_h, gpt_e);

err:
	free(gpt_e);
	free(gpt_h);
	return ret;
}
582

583 584 585 586 587 588 589 590 591 592 593 594 595 596
static void gpt_convert_efi_name_to_char(char *s, efi_char16_t *es, int n)
{
	char *ess = (char *)es;
	int i, j;

	memset(s, '\0', n);

	for (i = 0, j = 0; j < n; i += 2, j++) {
		s[j] = ess[i];
		if (!ess[i])
			return;
	}
}

597
int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
		       gpt_entry **gpt_pte)
{
	/*
	 * 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__);
		return -1;
	}
	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;
	}

	return 0;
}

621
int gpt_verify_partitions(struct blk_desc *dev_desc,
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
			  disk_partition_t *partitions, int parts,
			  gpt_header *gpt_head, gpt_entry **gpt_pte)
{
	char efi_str[PARTNAME_SZ + 1];
	u64 gpt_part_size;
	gpt_entry *gpt_e;
	int ret, i;

	ret = gpt_verify_headers(dev_desc, gpt_head, gpt_pte);
	if (ret)
		return ret;

	gpt_e = *gpt_pte;

	for (i = 0; i < parts; i++) {
		if (i == gpt_head->num_partition_entries) {
			error("More partitions than allowed!\n");
			return -1;
		}

		/* Check if GPT and ENV partition names match */
		gpt_convert_efi_name_to_char(efi_str, gpt_e[i].partition_name,
					     PARTNAME_SZ + 1);

		debug("%s: part: %2d name - GPT: %16s, ENV: %16s ",
		      __func__, i, efi_str, partitions[i].name);

		if (strncmp(efi_str, (char *)partitions[i].name,
			    sizeof(partitions->name))) {
			error("Partition name: %s does not match %s!\n",
			      efi_str, (char *)partitions[i].name);
			return -1;
		}

		/* Check if GPT and ENV sizes match */
		gpt_part_size = le64_to_cpu(gpt_e[i].ending_lba) -
			le64_to_cpu(gpt_e[i].starting_lba) + 1;
		debug("size(LBA) - GPT: %8llu, ENV: %8llu ",
660 661
		      (unsigned long long)gpt_part_size,
		      (unsigned long long)partitions[i].size);
662 663

		if (le64_to_cpu(gpt_part_size) != partitions[i].size) {
664 665 666 667
			/* We do not check the extend partition size */
			if ((i == parts - 1) && (partitions[i].size == 0))
				continue;

668
			error("Partition %s size: %llu does not match %llu!\n",
669 670
			      efi_str, (unsigned long long)gpt_part_size,
			      (unsigned long long)partitions[i].size);
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
			return -1;
		}

		/*
		 * Start address is optional - check only if provided
		 * in '$partition' variable
		 */
		if (!partitions[i].start) {
			debug("\n");
			continue;
		}

		/* Check if GPT and ENV start LBAs match */
		debug("start LBA - GPT: %8llu, ENV: %8llu\n",
		      le64_to_cpu(gpt_e[i].starting_lba),
686
		      (unsigned long long)partitions[i].start);
687 688 689 690

		if (le64_to_cpu(gpt_e[i].starting_lba) != partitions[i].start) {
			error("Partition %s start: %llu does not match %llu!\n",
			      efi_str, le64_to_cpu(gpt_e[i].starting_lba),
691
			      (unsigned long long)partitions[i].start);
692 693 694 695 696 697 698
			return -1;
		}
	}

	return 0;
}

699
int is_valid_gpt_buf(struct blk_desc *dev_desc, void *buf)
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
{
	gpt_header *gpt_h;
	gpt_entry *gpt_e;

	/* determine start of GPT Header in the buffer */
	gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
		       dev_desc->blksz);
	if (validate_gpt_header(gpt_h, GPT_PRIMARY_PARTITION_TABLE_LBA,
				dev_desc->lba))
		return -1;

	/* determine start of GPT Entries in the buffer */
	gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
		       dev_desc->blksz);
	if (validate_gpt_entries(gpt_h, gpt_e))
		return -1;

	return 0;
}

720
int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744
{
	gpt_header *gpt_h;
	gpt_entry *gpt_e;
	int gpt_e_blk_cnt;
	lbaint_t lba;
	int cnt;

	if (is_valid_gpt_buf(dev_desc, buf))
		return -1;

	/* determine start of GPT Header in the buffer */
	gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
		       dev_desc->blksz);

	/* determine start of GPT Entries in the buffer */
	gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
		       dev_desc->blksz);
	gpt_e_blk_cnt = BLOCK_CNT((le32_to_cpu(gpt_h->num_partition_entries) *
				   le32_to_cpu(gpt_h->sizeof_partition_entry)),
				  dev_desc);

	/* write MBR */
	lba = 0;	/* MBR is always at 0 */
	cnt = 1;	/* MBR (1 block) */
745
	if (blk_dwrite(dev_desc, lba, cnt, buf) != cnt) {
746 747 748 749 750 751 752 753
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "MBR", cnt, lba);
		return 1;
	}

	/* write Primary GPT */
	lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
	cnt = 1;	/* GPT Header (1 block) */
754
	if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
755 756 757 758 759 760 761
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "Primary GPT Header", cnt, lba);
		return 1;
	}

	lba = le64_to_cpu(gpt_h->partition_entry_lba);
	cnt = gpt_e_blk_cnt;
762
	if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
763 764 765 766 767 768 769 770 771 772
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "Primary GPT Entries", cnt, lba);
		return 1;
	}

	prepare_backup_gpt_header(gpt_h);

	/* write Backup GPT */
	lba = le64_to_cpu(gpt_h->partition_entry_lba);
	cnt = gpt_e_blk_cnt;
773
	if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
774 775 776 777 778 779 780
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "Backup GPT Entries", cnt, lba);
		return 1;
	}

	lba = le64_to_cpu(gpt_h->my_lba);
	cnt = 1;	/* GPT Header (1 block) */
781
	if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
782 783 784 785 786 787 788
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "Backup GPT Header", cnt, lba);
		return 1;
	}

	return 0;
}
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
int write_backup_gpt_partitions(struct blk_desc *dev_desc, void *buf)
{
	gpt_header *gpt_h;
	gpt_entry *gpt_e;
	int gpt_e_blk_cnt;
	lbaint_t lba;
	int cnt;

	if (is_valid_gpt_buf(dev_desc, buf))
		return -1;

	/* determine start of GPT Header in the buffer */
	gpt_h = buf + (GPT_PRIMARY_PARTITION_TABLE_LBA *
		       dev_desc->blksz);

	/* determine start of GPT Entries in the buffer */
	gpt_e = buf + (le64_to_cpu(gpt_h->partition_entry_lba) *
		       dev_desc->blksz);
	gpt_e_blk_cnt = BLOCK_CNT((le32_to_cpu(gpt_h->num_partition_entries) *
				   le32_to_cpu(gpt_h->sizeof_partition_entry)),
				  dev_desc);

	/* write MBR */
	lba = 0;	/* MBR is always at 0 */
	cnt = 1;	/* MBR (1 block) */
	if (blk_dwrite(dev_desc, lba, cnt, buf) != cnt) {
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "MBR", cnt, lba);
		return 1;
	}

	prepare_last_lba_gpt_header(dev_desc, gpt_h);

	/* write Backup GPT */
	lba = le64_to_cpu(gpt_h->partition_entry_lba);
	cnt = gpt_e_blk_cnt;
	if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "Backup GPT Entries", cnt, lba);
		return 1;
	}

	lba = le64_to_cpu(gpt_h->my_lba);
	cnt = 1;	/* GPT Header (1 block) */
	if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")\n",
		       __func__, "Backup GPT Header", cnt, lba);
		return 1;
	}

	return 0;
}
841 842
#endif

843 844 845 846 847 848 849 850 851 852 853
/*
 * Private functions
 */
/*
 * pmbr_part_valid(): Check for EFI partition signature
 *
 * Returns: 1 if EFI GPT partition type is found.
 */
static int pmbr_part_valid(struct partition *part)
{
	if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
854
		get_unaligned_le32(&part->start_sect) == 1UL) {
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
		return 1;
	}

	return 0;
}

/*
 * is_pmbr_valid(): test Protective MBR for validity
 *
 * Returns: 1 if PMBR is valid, 0 otherwise.
 * Validity depends on two things:
 *  1) MSDOS signature is in the last two bytes of the MBR
 *  2) One partition of type 0xEE is found, checked by pmbr_part_valid()
 */
static int is_pmbr_valid(legacy_mbr * mbr)
{
	int i = 0;

873
	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
		return 0;

	for (i = 0; i < 4; i++) {
		if (pmbr_part_valid(&mbr->partition_record[i])) {
			return 1;
		}
	}
	return 0;
}

/**
 * is_gpt_valid() - tests one GPT header and PTEs for validity
 *
 * lba is the logical block address of the GPT header to test
 * gpt is a GPT header ptr, filled on return.
 * ptes is a PTEs ptr, filled on return.
 *
 * Description: returns 1 if valid,  0 on error.
 * If valid, returns pointers to PTEs.
 */
894
static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
895
			gpt_header *pgpt_head, gpt_entry **pgpt_pte)
896 897
{
	if (!dev_desc || !pgpt_head) {
898
		printf("%s: Invalid Argument(s)\n", __func__);
899 900 901 902
		return 0;
	}

	/* Read GPT Header from device */
903
	if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) {
904 905 906 907
		printf("*** ERROR: Can't read GPT header ***\n");
		return 0;
	}

908
	if (validate_gpt_header(pgpt_head, (lbaint_t)lba, dev_desc->lba))
909 910 911 912 913 914 915 916 917
		return 0;

	/* Read and allocate Partition Table Entries */
	*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
	if (*pgpt_pte == NULL) {
		printf("GPT: Failed to allocate memory for PTE\n");
		return 0;
	}

918
	if (validate_gpt_entries(pgpt_head, *pgpt_pte)) {
919
		free(*pgpt_pte);
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
		return 0;
	}

	/* We're done, all's well */
	return 1;
}

/**
 * alloc_read_gpt_entries(): reads partition entries from disk
 * @dev_desc
 * @gpt - GPT header
 *
 * Description: Returns ptes on success,  NULL on error.
 * Allocates space for PTEs based on information found in @gpt.
 * Notes: remember to free pte when you're done!
 */
936 937
static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
					 gpt_header *pgpt_head)
938
{
939
	size_t count = 0, blk_cnt;
940
	lbaint_t blk;
941 942 943
	gpt_entry *pte = NULL;

	if (!dev_desc || !pgpt_head) {
944
		printf("%s: Invalid Argument(s)\n", __func__);
945 946 947
		return NULL;
	}

948 949
	count = le32_to_cpu(pgpt_head->num_partition_entries) *
		le32_to_cpu(pgpt_head->sizeof_partition_entry);
950

951
	debug("%s: count = %u * %u = %lu\n", __func__,
952
	      (u32) le32_to_cpu(pgpt_head->num_partition_entries),
953 954
	      (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry),
	      (ulong)count);
955 956 957

	/* Allocate memory for PTE, remember to FREE */
	if (count != 0) {
958 959
		pte = memalign(ARCH_DMA_MINALIGN,
			       PAD_TO_BLOCKSIZE(count, dev_desc));
960 961 962
	}

	if (count == 0 || pte == NULL) {
963 964
		printf("%s: ERROR: Can't allocate %#lX bytes for GPT Entries\n",
		       __func__, (ulong)count);
965 966 967 968
		return NULL;
	}

	/* Read GPT Entries from device */
969
	blk = le64_to_cpu(pgpt_head->partition_entry_lba);
970
	blk_cnt = BLOCK_CNT(count, dev_desc);
971
	if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
		printf("*** ERROR: Can't read GPT Entries ***\n");
		free(pte);
		return NULL;
	}
	return pte;
}

/**
 * is_pte_valid(): validates a single Partition Table Entry
 * @gpt_entry - Pointer to a single Partition Table Entry
 *
 * Description: returns 1 if valid,  0 on error.
 */
static int is_pte_valid(gpt_entry * pte)
{
	efi_guid_t unused_guid;

	if (!pte) {
990
		printf("%s: Invalid Argument(s)\n", __func__);
991 992 993 994 995 996 997 998 999 1000 1001
		return 0;
	}

	/* Only one validation for now:
	 * The GUID Partition Type != Unused Entry (ALL-ZERO)
	 */
	memset(unused_guid.b, 0, sizeof(unused_guid.b));

	if (memcmp(pte->partition_type_guid.b, unused_guid.b,
		sizeof(unused_guid.b)) == 0) {

1002
		debug("%s: Found an unused PTE GUID at 0x%08X\n", __func__,
1003
		      (unsigned int)(uintptr_t)pte);
1004 1005 1006 1007 1008 1009

		return 0;
	} else {
		return 1;
	}
}
1010 1011 1012 1013 1014 1015 1016 1017 1018

/*
 * Add an 'a_' prefix so it comes before 'dos' in the linker list. We need to
 * check EFI first, since a DOS partition is often used as a 'protective MBR'
 * with EFI.
 */
U_BOOT_PART_TYPE(a_efi) = {
	.name		= "EFI",
	.part_type	= PART_TYPE_EFI,
1019
	.max_entries	= GPT_ENTRY_NUMBERS,
1020
	.get_info	= part_get_info_ptr(part_get_info_efi),
1021 1022
	.print		= part_print_ptr(part_print_efi),
	.test		= part_test_efi,
1023
};
1024
#endif