Blame view

disk/part_efi.c 31.9 KB
07f3d789b   richardretanubun   Add support for C...
1
2
3
4
  /*
   * Copyright (C) 2008 RuggedCom, Inc.
   * Richard Retanubun <RichardRetanubun@RuggedCom.com>
   *
1a4596601   Wolfgang Denk   Add GPL-2.0+ SPDX...
5
   * SPDX-License-Identifier:	GPL-2.0+
07f3d789b   richardretanubun   Add support for C...
6
7
8
   */
  
  /*
e04350d29   Steve Rae   disk: part_efi: c...
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
07f3d789b   richardretanubun   Add support for C...
12
   */
8faefadb7   Marc Dietrich   disk: fix unalign...
13
  #include <asm/unaligned.h>
07f3d789b   richardretanubun   Add support for C...
14
15
  #include <common.h>
  #include <command.h>
02e43537b   Philipp Tomsich   part_efi: support...
16
  #include <fdtdec.h>
07f3d789b   richardretanubun   Add support for C...
17
  #include <ide.h>
e48f3741c   Simon Glass   sandbox: Fix warn...
18
  #include <inttypes.h>
07f3d789b   richardretanubun   Add support for C...
19
  #include <malloc.h>
cf92e05c0   Simon Glass   Move ALLOC_CACHE_...
20
  #include <memalign.h>
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
21
  #include <part_efi.h>
02e43537b   Philipp Tomsich   part_efi: support...
22
  #include <linux/compiler.h>
6eecc0307   Lei Wen   part: show efi pa...
23
  #include <linux/ctype.h>
07f3d789b   richardretanubun   Add support for C...
24

40684ddb8   Lukasz Majewski   gpt: Support for ...
25
  DECLARE_GLOBAL_DATA_PTR;
1811a928c   Adam Ford   Move most CONFIG_...
26
  #ifdef CONFIG_HAVE_BLOCK_DEVICE
07f3d789b   richardretanubun   Add support for C...
27
28
29
30
31
32
33
  /**
   * 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
   */
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
34
  static inline u32 efi_crc32(const void *buf, u32 len)
07f3d789b   richardretanubun   Add support for C...
35
36
37
38
39
40
41
42
43
44
  {
  	return crc32(0, buf, len);
  }
  
  /*
   * Private function prototypes
   */
  
  static int pmbr_part_valid(struct partition *part);
  static int is_pmbr_valid(legacy_mbr * mbr);
4101f6879   Simon Glass   dm: Drop the bloc...
45
  static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
e04350d29   Steve Rae   disk: part_efi: c...
46
  				gpt_header *pgpt_head, gpt_entry **pgpt_pte);
4101f6879   Simon Glass   dm: Drop the bloc...
47
48
  static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
  					 gpt_header *pgpt_head);
07f3d789b   richardretanubun   Add support for C...
49
  static int is_pte_valid(gpt_entry * pte);
6eecc0307   Lei Wen   part: show efi pa...
50
51
52
53
54
55
56
57
58
59
60
61
62
  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;
  }
b4414f4a4   Stephen Warren   disk: part_efi: s...
63
64
65
66
67
68
69
70
  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));
  }
e1f6b0a02   Steve Rae   disk: part_efi: m...
71
72
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
136
137
138
  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
  ",
  		       "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
  ",
  		       "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 "
  ",
  		       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 "
  ",
  		       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 "
  ",
  		       le64_to_cpu(gpt_h->last_usable_lba), lastlba);
  		return -1;
  	}
  
  	debug("GPT: first_usable_lba: %llX last_usable_lba: %llX last lba: "
  	      LBAF "
  ", le64_to_cpu(gpt_h->first_usable_lba),
  	      le64_to_cpu(gpt_h->last_usable_lba), lastlba);
  
  	return 0;
  }
2c840c82b   Ye Li   MLK-18591-3 andro...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
  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);
  }
e1f6b0a02   Steve Rae   disk: part_efi: m...
157
158
159
160
161
162
163
164
165
166
  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)) {
2c840c82b   Ye Li   MLK-18591-3 andro...
167
168
  		debug("%s: 0x%x != 0x%x
  ",
e1f6b0a02   Steve Rae   disk: part_efi: m...
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  		       "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);
0ff7e585d   Steve Rae   fastboot: handle ...
187
188
  	gpt_h->partition_entry_lba =
  			cpu_to_le64(le64_to_cpu(gpt_h->last_usable_lba) + 1);
e1f6b0a02   Steve Rae   disk: part_efi: m...
189
190
191
192
193
194
  	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);
  }
bd42a9426   Patrick Delaunay   disk: convert CON...
195
  #if CONFIG_IS_ENABLED(EFI_PARTITION)
07f3d789b   richardretanubun   Add support for C...
196
197
198
  /*
   * Public Functions (include/part.h)
   */
73d6d18b7   Alison Chaiken   GPT: add accessor...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  /*
   * UUID is displayed as 32 hexadecimal digits, in 5 groups,
   * separated by hyphens, in the form 8-4-4-4-12 for a total of 36 characters
   */
  int get_disk_guid(struct blk_desc * dev_desc, char *guid)
  {
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
  	gpt_entry *gpt_pte = NULL;
  	unsigned char *guid_bin;
  
  	/* This function validates AND fills in the GPT header and PTE */
  	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
  			 gpt_head, &gpt_pte) != 1) {
  		printf("%s: *** ERROR: Invalid GPT ***
  ", __func__);
  		if (is_gpt_valid(dev_desc, dev_desc->lba - 1,
  				 gpt_head, &gpt_pte) != 1) {
  			printf("%s: *** ERROR: Invalid Backup GPT ***
  ",
  			       __func__);
  			return -EINVAL;
  		} else {
  			printf("%s: ***        Using Backup GPT ***
  ",
  			       __func__);
  		}
  	}
  
  	guid_bin = gpt_head->disk_guid.b;
  	uuid_bin_to_str(guid_bin, guid, UUID_STR_FORMAT_GUID);
  
  	return 0;
  }
084bf4c24   Simon Glass   part: Rename test...
232
  void part_print_efi(struct blk_desc *dev_desc)
07f3d789b   richardretanubun   Add support for C...
233
  {
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
234
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
deb5ca802   Doug Anderson   disk: part_efi: f...
235
  	gpt_entry *gpt_pte = NULL;
07f3d789b   richardretanubun   Add support for C...
236
  	int i = 0;
db9b6200a   Alison Chaiken   EFI: replace numb...
237
  	char uuid[UUID_STR_LEN + 1];
a96a0e615   Przemyslaw Marczak   part_efi: move uu...
238
  	unsigned char *uuid_bin;
07f3d789b   richardretanubun   Add support for C...
239

07f3d789b   richardretanubun   Add support for C...
240
241
  	/* This function validates AND fills in the GPT header and PTE */
  	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
4715a8113   Stephen Warren   disk: part_efi: f...
242
  			 gpt_head, &gpt_pte) != 1) {
df70b1c2e   Doug Anderson   cosmetic: Replace...
243
244
  		printf("%s: *** ERROR: Invalid GPT ***
  ", __func__);
ae95fad5a   Steve Rae   disk: part_efi: a...
245
246
247
248
249
250
251
252
253
254
255
  		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
  				 gpt_head, &gpt_pte) != 1) {
  			printf("%s: *** ERROR: Invalid Backup GPT ***
  ",
  			       __func__);
  			return;
  		} else {
  			printf("%s: ***        Using Backup GPT ***
  ",
  			       __func__);
  		}
07f3d789b   richardretanubun   Add support for C...
256
  	}
deb5ca802   Doug Anderson   disk: part_efi: f...
257
258
  	debug("%s: gpt-entry at %p
  ", __func__, gpt_pte);
07f3d789b   richardretanubun   Add support for C...
259

788a8c1fc   Stephen Warren   disk: part_efi: r...
260
261
  	printf("Part\tStart LBA\tEnd LBA\t\tName
  ");
13bf2f55d   Stephen Warren   disk: part_efi: p...
262
263
  	printf("\tAttributes
  ");
d718ded05   Przemyslaw Marczak   lib: uuid: code r...
264
265
266
267
  	printf("\tType GUID
  ");
  	printf("\tPartition GUID
  ");
f07cd2c4c   Stephen Warren   disk: part_efi: p...
268

fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
269
  	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
38a3021ed   Stephen Warren   disk: part_efi: r...
270
271
272
  		/* Stop at the first non valid PTE */
  		if (!is_pte_valid(&gpt_pte[i]))
  			break;
788a8c1fc   Stephen Warren   disk: part_efi: r...
273
274
  		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"
  ", (i + 1),
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
275
276
  			le64_to_cpu(gpt_pte[i].starting_lba),
  			le64_to_cpu(gpt_pte[i].ending_lba),
788a8c1fc   Stephen Warren   disk: part_efi: r...
277
  			print_efiname(&gpt_pte[i]));
13bf2f55d   Stephen Warren   disk: part_efi: p...
278
279
  		printf("\tattrs:\t0x%016llx
  ", gpt_pte[i].attributes.raw);
a96a0e615   Przemyslaw Marczak   part_efi: move uu...
280
  		uuid_bin = (unsigned char *)gpt_pte[i].partition_type_guid.b;
d718ded05   Przemyslaw Marczak   lib: uuid: code r...
281
  		uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
f07cd2c4c   Stephen Warren   disk: part_efi: p...
282
283
  		printf("\ttype:\t%s
  ", uuid);
bcb41dcae   Patrick Delaunay   uuid: add selecti...
284
285
286
287
288
  #ifdef CONFIG_PARTITION_TYPE_GUID
  		if (!uuid_guid_get_str(uuid_bin, uuid))
  			printf("\ttype:\t%s
  ", uuid);
  #endif
a96a0e615   Przemyslaw Marczak   part_efi: move uu...
289
  		uuid_bin = (unsigned char *)gpt_pte[i].unique_partition_guid.b;
d718ded05   Przemyslaw Marczak   lib: uuid: code r...
290
291
292
  		uuid_bin_to_str(uuid_bin, uuid, UUID_STR_FORMAT_GUID);
  		printf("\tguid:\t%s
  ", uuid);
07f3d789b   richardretanubun   Add support for C...
293
  	}
dbcf1e3cc   Luo Ji   [iot] Support dua...
294
  #if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
07f3d789b   richardretanubun   Add support for C...
295
  	/* Remember to free pte */
deb5ca802   Doug Anderson   disk: part_efi: f...
296
  	free(gpt_pte);
dbcf1e3cc   Luo Ji   [iot] Support dua...
297
  #endif
07f3d789b   richardretanubun   Add support for C...
298
299
  	return;
  }
3e8bd4695   Simon Glass   dm: part: Rename ...
300
301
  int part_get_info_efi(struct blk_desc *dev_desc, int part,
  		      disk_partition_t *info)
07f3d789b   richardretanubun   Add support for C...
302
  {
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
303
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(gpt_header, gpt_head, 1, dev_desc->blksz);
deb5ca802   Doug Anderson   disk: part_efi: f...
304
  	gpt_entry *gpt_pte = NULL;
07f3d789b   richardretanubun   Add support for C...
305
306
  
  	/* "part" argument must be at least 1 */
4708a07c7   Simon Glass   part_efi: Drop NU...
307
  	if (part < 1) {
df70b1c2e   Doug Anderson   cosmetic: Replace...
308
309
  		printf("%s: Invalid Argument(s)
  ", __func__);
07f3d789b   richardretanubun   Add support for C...
310
311
312
313
314
  		return -1;
  	}
  
  	/* This function validates AND fills in the GPT header and PTE */
  	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
4715a8113   Stephen Warren   disk: part_efi: f...
315
  			gpt_head, &gpt_pte) != 1) {
2c840c82b   Ye Li   MLK-18591-3 andro...
316
317
  		debug("%s: *** ERROR: Invalid GPT ***
  ", __func__);
ae95fad5a   Steve Rae   disk: part_efi: a...
318
319
320
321
322
323
324
  		if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
  				 gpt_head, &gpt_pte) != 1) {
  			printf("%s: *** ERROR: Invalid Backup GPT ***
  ",
  			       __func__);
  			return -1;
  		} else {
2c840c82b   Ye Li   MLK-18591-3 andro...
325
326
  			debug("%s: ***        Using Backup GPT ***
  ",
ae95fad5a   Steve Rae   disk: part_efi: a...
327
328
  			       __func__);
  		}
07f3d789b   richardretanubun   Add support for C...
329
  	}
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
330
  	if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
c04d68c69   Stephen Warren   disk: part_efi: r...
331
  	    !is_pte_valid(&gpt_pte[part - 1])) {
6d2ee5a33   Mark Langsdorf   part_efi: make su...
332
333
  		debug("%s: *** ERROR: Invalid partition number %d ***
  ",
c04d68c69   Stephen Warren   disk: part_efi: r...
334
  			__func__, part);
dbcf1e3cc   Luo Ji   [iot] Support dua...
335
  #if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
6d2ee5a33   Mark Langsdorf   part_efi: make su...
336
  		free(gpt_pte);
dbcf1e3cc   Luo Ji   [iot] Support dua...
337
  #endif
c04d68c69   Stephen Warren   disk: part_efi: r...
338
339
  		return -1;
  	}
e04350d29   Steve Rae   disk: part_efi: c...
340
341
  	/* 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);
509708397   Richard Retanubun   part_efi: Fix par...
342
  	/* The ending LBA is inclusive, to calculate size, add 1 to it */
e04350d29   Steve Rae   disk: part_efi: c...
343
  	info->size = (lbaint_t)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1
509708397   Richard Retanubun   part_efi: Fix par...
344
  		     - info->start;
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
345
  	info->blksz = dev_desc->blksz;
07f3d789b   richardretanubun   Add support for C...
346

6eecc0307   Lei Wen   part: show efi pa...
347
  	sprintf((char *)info->name, "%s",
deb5ca802   Doug Anderson   disk: part_efi: f...
348
  			print_efiname(&gpt_pte[part - 1]));
192bc6948   Ben Whitten   Fix GCC format-se...
349
  	strcpy((char *)info->type, "U-Boot");
b4414f4a4   Stephen Warren   disk: part_efi: s...
350
  	info->bootable = is_bootable(&gpt_pte[part - 1]);
b331cd620   Patrick Delaunay   cmd, disk: conver...
351
  #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
d718ded05   Przemyslaw Marczak   lib: uuid: code r...
352
353
  	uuid_bin_to_str(gpt_pte[part - 1].unique_partition_guid.b, info->uuid,
  			UUID_STR_FORMAT_GUID);
894bfbbfb   Stephen Warren   disk: part_efi: p...
354
  #endif
7561b258a   Patrick Delaunay   gpt: add optional...
355
356
357
358
  #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
07f3d789b   richardretanubun   Add support for C...
359

60bf94169   Steve Rae   disk: part_efi: a...
360
361
  	debug("%s: start 0x" LBAF ", size 0x" LBAF ", name %s
  ", __func__,
04735e9c5   Frederic Leroy   Fix ext2/ext4 fil...
362
  	      info->start, info->size, info->name);
07f3d789b   richardretanubun   Add support for C...
363

dbcf1e3cc   Luo Ji   [iot] Support dua...
364
365
366
367
368
369
  #if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
  	/* Heap memory is very limited in SPL, if the dual bootloader is
  	 * enabled, just load pte to dram instead of oc-ram. In such case,
  	 * this part of  memory shouldn't be freed. But in common routine,
  	 * don't forget to free the memory after use.
  	 */
deb5ca802   Doug Anderson   disk: part_efi: f...
370
  	free(gpt_pte);
dbcf1e3cc   Luo Ji   [iot] Support dua...
371
  #endif
07f3d789b   richardretanubun   Add support for C...
372
373
  	return 0;
  }
084bf4c24   Simon Glass   part: Rename test...
374
  static int part_test_efi(struct blk_desc *dev_desc)
07f3d789b   richardretanubun   Add support for C...
375
  {
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
376
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, legacymbr, 1, dev_desc->blksz);
07f3d789b   richardretanubun   Add support for C...
377
378
  
  	/* Read legacy MBR from block 0 and validate it */
2a981dc2c   Simon Glass   dm: block: Adjust...
379
  	if ((blk_dread(dev_desc, 0, 1, (ulong *)legacymbr) != 1)
f75dd584c   Anton staaf   part_efi: dcache:...
380
  		|| (is_pmbr_valid(legacymbr) != 1)) {
07f3d789b   richardretanubun   Add support for C...
381
382
383
384
  		return -1;
  	}
  	return 0;
  }
40684ddb8   Lukasz Majewski   gpt: Support for ...
385
386
387
388
389
390
  /**
   * set_protective_mbr(): Set the EFI protective MBR
   * @param dev_desc - block device descriptor
   *
   * @return - zero on success, otherwise error
   */
4101f6879   Simon Glass   dm: Drop the bloc...
391
  static int set_protective_mbr(struct blk_desc *dev_desc)
40684ddb8   Lukasz Majewski   gpt: Support for ...
392
  {
40684ddb8   Lukasz Majewski   gpt: Support for ...
393
  	/* Setup the Protective MBR */
3cc566117   Patrick Delaunay   disk: efi: correc...
394
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, p_mbr, 1, dev_desc->blksz);
61fcc7d27   Hector Palacios   part_efi: fix pro...
395
  	memset(p_mbr, 0, sizeof(*p_mbr));
40684ddb8   Lukasz Majewski   gpt: Support for ...
396
397
398
399
400
  	if (p_mbr == NULL) {
  		printf("%s: calloc failed!
  ", __func__);
  		return -1;
  	}
e163a931a   Vincent Tinelli   cmd: gpt: backup ...
401
402
403
  
  	/* Read MBR to backup boot code if it exists */
  	if (blk_dread(dev_desc, 0, 1, p_mbr) != 1) {
9b643e312   Masahiro Yamada   treewide: replace...
404
405
  		pr_err("** Can't read from device %d **
  ", dev_desc->devnum);
e163a931a   Vincent Tinelli   cmd: gpt: backup ...
406
407
  		return -1;
  	}
40684ddb8   Lukasz Majewski   gpt: Support for ...
408
409
410
411
  	/* 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;
b349abbfe   Maxime Ripard   gpt: Fix the prot...
412
  	p_mbr->partition_record[0].nr_sects = (u32) dev_desc->lba - 1;
40684ddb8   Lukasz Majewski   gpt: Support for ...
413
414
  
  	/* Write MBR sector to the MMC device */
2a981dc2c   Simon Glass   dm: block: Adjust...
415
  	if (blk_dwrite(dev_desc, 0, 1, p_mbr) != 1) {
40684ddb8   Lukasz Majewski   gpt: Support for ...
416
417
  		printf("** Can't write to device %d **
  ",
bcce53d04   Simon Glass   dm: block: Rename...
418
  			dev_desc->devnum);
40684ddb8   Lukasz Majewski   gpt: Support for ...
419
420
  		return -1;
  	}
40684ddb8   Lukasz Majewski   gpt: Support for ...
421
422
  	return 0;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
423
  int write_gpt_table(struct blk_desc *dev_desc,
40684ddb8   Lukasz Majewski   gpt: Support for ...
424
425
  		gpt_header *gpt_h, gpt_entry *gpt_e)
  {
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
426
427
  	const int pte_blk_cnt = BLOCK_CNT((gpt_h->num_partition_entries
  					   * sizeof(gpt_entry)), dev_desc);
40684ddb8   Lukasz Majewski   gpt: Support for ...
428
  	u32 calc_crc32;
40684ddb8   Lukasz Majewski   gpt: Support for ...
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
  
  	debug("max lba: %x
  ", (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 */
2a981dc2c   Simon Glass   dm: block: Adjust...
447
  	if (blk_dwrite(dev_desc, 1, 1, gpt_h) != 1)
40684ddb8   Lukasz Majewski   gpt: Support for ...
448
  		goto err;
02e43537b   Philipp Tomsich   part_efi: support...
449
450
  	if (blk_dwrite(dev_desc, le64_to_cpu(gpt_h->partition_entry_lba),
  		       pte_blk_cnt, gpt_e) != pte_blk_cnt)
40684ddb8   Lukasz Majewski   gpt: Support for ...
451
  		goto err;
e1f6b0a02   Steve Rae   disk: part_efi: m...
452
  	prepare_backup_gpt_header(gpt_h);
40684ddb8   Lukasz Majewski   gpt: Support for ...
453

2a981dc2c   Simon Glass   dm: block: Adjust...
454
455
  	if (blk_dwrite(dev_desc, (lbaint_t)le64_to_cpu(gpt_h->last_usable_lba)
  		       + 1, pte_blk_cnt, gpt_e) != pte_blk_cnt)
40684ddb8   Lukasz Majewski   gpt: Support for ...
456
  		goto err;
2a981dc2c   Simon Glass   dm: block: Adjust...
457
458
  	if (blk_dwrite(dev_desc, (lbaint_t)le64_to_cpu(gpt_h->my_lba), 1,
  		       gpt_h) != 1)
40684ddb8   Lukasz Majewski   gpt: Support for ...
459
460
461
462
463
464
465
  		goto err;
  
  	debug("GPT successfully written to block device!
  ");
  	return 0;
  
   err:
bcce53d04   Simon Glass   dm: block: Rename...
466
467
  	printf("** Can't write to device %d **
  ", dev_desc->devnum);
40684ddb8   Lukasz Majewski   gpt: Support for ...
468
469
  	return -1;
  }
47d7ee47b   Maxime Ripard   part: efi: make g...
470
471
472
  int gpt_fill_pte(struct blk_desc *dev_desc,
  		 gpt_header *gpt_h, gpt_entry *gpt_e,
  		 disk_partition_t *partitions, int parts)
40684ddb8   Lukasz Majewski   gpt: Support for ...
473
  {
e04350d29   Steve Rae   disk: part_efi: c...
474
  	lbaint_t offset = (lbaint_t)le64_to_cpu(gpt_h->first_usable_lba);
e04350d29   Steve Rae   disk: part_efi: c...
475
476
  	lbaint_t last_usable_lba = (lbaint_t)
  			le64_to_cpu(gpt_h->last_usable_lba);
40684ddb8   Lukasz Majewski   gpt: Support for ...
477
  	int i, k;
67cd4a634   Marek Vasut   disk: Fix possibl...
478
  	size_t efiname_len, dosname_len;
b331cd620   Patrick Delaunay   cmd, disk: conver...
479
  #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
40684ddb8   Lukasz Majewski   gpt: Support for ...
480
  	char *str_uuid;
a96a0e615   Przemyslaw Marczak   part_efi: move uu...
481
  	unsigned char *bin_uuid;
40684ddb8   Lukasz Majewski   gpt: Support for ...
482
  #endif
7561b258a   Patrick Delaunay   gpt: add optional...
483
484
485
486
  #ifdef CONFIG_PARTITION_TYPE_GUID
  	char *str_type_guid;
  	unsigned char *bin_type_guid;
  #endif
79c5912e8   Maxime Ripard   part: efi: Disabl...
487
488
489
490
491
492
493
  	size_t hdr_start = gpt_h->my_lba;
  	size_t hdr_end = hdr_start + 1;
  
  	size_t pte_start = gpt_h->partition_entry_lba;
  	size_t pte_end = pte_start +
  		gpt_h->num_partition_entries * gpt_h->sizeof_partition_entry /
  		dev_desc->blksz;
40684ddb8   Lukasz Majewski   gpt: Support for ...
494
495
496
  
  	for (i = 0; i < parts; i++) {
  		/* partition starting lba */
5276e8b62   Maxime Ripard   part: efi: rework...
497
498
  		lbaint_t start = partitions[i].start;
  		lbaint_t size = partitions[i].size;
40684ddb8   Lukasz Majewski   gpt: Support for ...
499
  		if (start) {
5276e8b62   Maxime Ripard   part: efi: rework...
500
  			offset = start + size;
40684ddb8   Lukasz Majewski   gpt: Support for ...
501
  		} else {
79c5912e8   Maxime Ripard   part: efi: Disabl...
502
  			start = offset;
5276e8b62   Maxime Ripard   part: efi: rework...
503
  			offset += size;
40684ddb8   Lukasz Majewski   gpt: Support for ...
504
  		}
79c5912e8   Maxime Ripard   part: efi: Disabl...
505
506
507
508
509
  
  		/*
  		 * If our partition overlaps with either the GPT
  		 * header, or the partition entry, reject it.
  		 */
ae0e0228e   Patrick Delaunay   disk: efi: correc...
510
511
  		if (((start < hdr_end && hdr_start < (start + size)) ||
  		     (start < pte_end && pte_start < (start + size)))) {
79c5912e8   Maxime Ripard   part: efi: Disabl...
512
513
514
515
516
517
  			printf("Partition overlap
  ");
  			return -1;
  		}
  
  		gpt_e[i].starting_lba = cpu_to_le64(start);
a56538676   Patrick Delaunay   disk: part_efi: f...
518
  		if (offset > (last_usable_lba + 1)) {
40684ddb8   Lukasz Majewski   gpt: Support for ...
519
520
521
522
523
  			printf("Partitions layout exceds disk size
  ");
  			return -1;
  		}
  		/* partition ending lba */
5276e8b62   Maxime Ripard   part: efi: rework...
524
  		if ((i == parts - 1) && (size == 0))
40684ddb8   Lukasz Majewski   gpt: Support for ...
525
526
527
528
  			/* 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);
7561b258a   Patrick Delaunay   gpt: add optional...
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
  #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
  ",
  				       i, str_type_guid);
  				return -1;
  			}
  		} else {
  			/* default partition type GUID */
  			memcpy(bin_type_guid,
  			       &PARTITION_BASIC_DATA_GUID, 16);
  		}
  #else
40684ddb8   Lukasz Majewski   gpt: Support for ...
546
547
548
  		/* partition type GUID */
  		memcpy(gpt_e[i].partition_type_guid.b,
  			&PARTITION_BASIC_DATA_GUID, 16);
7561b258a   Patrick Delaunay   gpt: add optional...
549
  #endif
40684ddb8   Lukasz Majewski   gpt: Support for ...
550

b331cd620   Patrick Delaunay   cmd, disk: conver...
551
  #if CONFIG_IS_ENABLED(PARTITION_UUIDS)
40684ddb8   Lukasz Majewski   gpt: Support for ...
552
  		str_uuid = partitions[i].uuid;
a96a0e615   Przemyslaw Marczak   part_efi: move uu...
553
  		bin_uuid = gpt_e[i].unique_partition_guid.b;
9da52f8f6   Vincent Tinelli   gpt: Fix uuid str...
554
  		if (uuid_str_to_bin(str_uuid, bin_uuid, UUID_STR_FORMAT_GUID)) {
40684ddb8   Lukasz Majewski   gpt: Support for ...
555
556
557
558
559
560
561
562
563
564
  			printf("Partition no. %d: invalid guid: %s
  ",
  				i, str_uuid);
  			return -1;
  		}
  #endif
  
  		/* partition attributes */
  		memset(&gpt_e[i].attributes, 0,
  		       sizeof(gpt_entry_attributes));
cfdaf4caa   Patrick Delaunay   part:efi: add boo...
565
566
  		if (partitions[i].bootable)
  			gpt_e[i].attributes.fields.legacy_bios_bootable = 1;
40684ddb8   Lukasz Majewski   gpt: Support for ...
567
  		/* partition name */
67cd4a634   Marek Vasut   disk: Fix possibl...
568
  		efiname_len = sizeof(gpt_e[i].partition_name)
40684ddb8   Lukasz Majewski   gpt: Support for ...
569
  			/ sizeof(efi_char16_t);
67cd4a634   Marek Vasut   disk: Fix possibl...
570
571
572
573
574
575
  		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++)
40684ddb8   Lukasz Majewski   gpt: Support for ...
576
577
  			gpt_e[i].partition_name[k] =
  				(efi_char16_t)(partitions[i].name[k]);
e04350d29   Steve Rae   disk: part_efi: c...
578
579
580
  		debug("%s: name: %s offset[%d]: 0x" LBAF
  		      " size[%d]: 0x" LBAF "
  ",
40684ddb8   Lukasz Majewski   gpt: Support for ...
581
  		      __func__, partitions[i].name, i,
5276e8b62   Maxime Ripard   part: efi: rework...
582
  		      offset, i, size);
40684ddb8   Lukasz Majewski   gpt: Support for ...
583
584
585
586
  	}
  
  	return 0;
  }
02e43537b   Philipp Tomsich   part_efi: support...
587
588
589
  static uint32_t partition_entries_offset(struct blk_desc *dev_desc)
  {
  	uint32_t offset_blks = 2;
89d33a2c0   Maxime Ripard   part: efi: Fix of...
590
  	uint32_t __maybe_unused offset_bytes;
02e43537b   Philipp Tomsich   part_efi: support...
591
592
593
594
595
596
597
598
599
600
601
  	int __maybe_unused config_offset;
  
  #if defined(CONFIG_EFI_PARTITION_ENTRIES_OFF)
  	/*
  	 * Some architectures require their SPL loader at a fixed
  	 * address within the first 16KB of the disk.  To avoid an
  	 * overlap with the partition entries of the EFI partition
  	 * table, the first safe offset (in bytes, from the start of
  	 * the disk) for the entries can be set in
  	 * CONFIG_EFI_PARTITION_ENTRIES_OFF.
  	 */
89d33a2c0   Maxime Ripard   part: efi: Fix of...
602
  	offset_bytes =
02e43537b   Philipp Tomsich   part_efi: support...
603
  		PAD_TO_BLOCKSIZE(CONFIG_EFI_PARTITION_ENTRIES_OFF, dev_desc);
89d33a2c0   Maxime Ripard   part: efi: Fix of...
604
  	offset_blks = offset_bytes / dev_desc->blksz;
02e43537b   Philipp Tomsich   part_efi: support...
605
606
607
608
609
610
611
612
613
614
615
  #endif
  
  #if defined(CONFIG_OF_CONTROL)
  	/*
  	 * Allow the offset of the first partition entires (in bytes
  	 * from the start of the device) to be specified as a property
  	 * of the device tree '/config' node.
  	 */
  	config_offset = fdtdec_get_config_int(gd->fdt_blob,
  					      "u-boot,efi-partition-entries-offset",
  					      -EINVAL);
89d33a2c0   Maxime Ripard   part: efi: Fix of...
616
617
618
619
  	if (config_offset != -EINVAL) {
  		offset_bytes = PAD_TO_BLOCKSIZE(config_offset, dev_desc);
  		offset_blks = offset_bytes / dev_desc->blksz;
  	}
02e43537b   Philipp Tomsich   part_efi: support...
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  #endif
  
  	debug("efi: partition entries offset (in blocks): %d
  ", offset_blks);
  
  	/*
  	 * The earliest LBA this can be at is LBA#2 (i.e. right behind
  	 * the (protective) MBR and the GPT header.
  	 */
  	if (offset_blks < 2)
  		offset_blks = 2;
  
  	return offset_blks;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
634
  int gpt_fill_header(struct blk_desc *dev_desc, gpt_header *gpt_h,
40684ddb8   Lukasz Majewski   gpt: Support for ...
635
636
637
638
639
640
641
  		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);
40684ddb8   Lukasz Majewski   gpt: Support for ...
642
  	gpt_h->last_usable_lba = cpu_to_le64(dev_desc->lba - 34);
02e43537b   Philipp Tomsich   part_efi: support...
643
644
645
646
  	gpt_h->partition_entry_lba =
  		cpu_to_le64(partition_entries_offset(dev_desc));
  	gpt_h->first_usable_lba =
  		cpu_to_le64(le64_to_cpu(gpt_h->partition_entry_lba) + 32);
40684ddb8   Lukasz Majewski   gpt: Support for ...
647
648
649
650
  	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;
d718ded05   Przemyslaw Marczak   lib: uuid: code r...
651
  	if (uuid_str_to_bin(str_guid, gpt_h->disk_guid.b, UUID_STR_FORMAT_GUID))
40684ddb8   Lukasz Majewski   gpt: Support for ...
652
653
654
655
  		return -1;
  
  	return 0;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
656
  int gpt_restore(struct blk_desc *dev_desc, char *str_disk_guid,
40684ddb8   Lukasz Majewski   gpt: Support for ...
657
658
  		disk_partition_t *partitions, int parts_count)
  {
bb021013b   Lukasz Majewski   gpt: Use cache al...
659
  	gpt_header *gpt_h;
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
660
  	gpt_entry *gpt_e;
bb021013b   Lukasz Majewski   gpt: Use cache al...
661
  	int ret, size;
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
662

bb021013b   Lukasz Majewski   gpt: Use cache al...
663
664
  	size = PAD_TO_BLOCKSIZE(sizeof(gpt_header), dev_desc);
  	gpt_h = malloc_cache_aligned(size);
40684ddb8   Lukasz Majewski   gpt: Support for ...
665
666
667
668
669
  	if (gpt_h == NULL) {
  		printf("%s: calloc failed!
  ", __func__);
  		return -1;
  	}
bb021013b   Lukasz Majewski   gpt: Use cache al...
670
  	memset(gpt_h, 0, size);
40684ddb8   Lukasz Majewski   gpt: Support for ...
671

bb021013b   Lukasz Majewski   gpt: Use cache al...
672
673
674
  	size = PAD_TO_BLOCKSIZE(GPT_ENTRY_NUMBERS * sizeof(gpt_entry),
  				dev_desc);
  	gpt_e = malloc_cache_aligned(size);
40684ddb8   Lukasz Majewski   gpt: Support for ...
675
676
677
678
679
680
  	if (gpt_e == NULL) {
  		printf("%s: calloc failed!
  ", __func__);
  		free(gpt_h);
  		return -1;
  	}
bb021013b   Lukasz Majewski   gpt: Use cache al...
681
  	memset(gpt_e, 0, size);
40684ddb8   Lukasz Majewski   gpt: Support for ...
682
683
684
685
686
687
688
  
  	/* 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 */
47d7ee47b   Maxime Ripard   part: efi: make g...
689
  	ret = gpt_fill_pte(dev_desc, gpt_h, gpt_e, partitions, parts_count);
40684ddb8   Lukasz Majewski   gpt: Support for ...
690
691
692
693
694
695
696
697
698
699
700
  	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;
  }
0ff7e585d   Steve Rae   fastboot: handle ...
701

cef68bf90   Lukasz Majewski   gpt: part: Defini...
702
703
704
705
706
707
708
709
710
711
712
713
714
  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;
  	}
  }
4101f6879   Simon Glass   dm: Drop the bloc...
715
  int gpt_verify_headers(struct blk_desc *dev_desc, gpt_header *gpt_head,
cef68bf90   Lukasz Majewski   gpt: part: Defini...
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
  		       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 ***
  ",
  		       __func__);
  		return -1;
  	}
  	if (is_gpt_valid(dev_desc, (dev_desc->lba - 1),
  			 gpt_head, gpt_pte) != 1) {
  		printf("%s: *** ERROR: Invalid Backup GPT ***
  ",
  		       __func__);
  		return -1;
  	}
  
  	return 0;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
740
  int gpt_verify_partitions(struct blk_desc *dev_desc,
cef68bf90   Lukasz Majewski   gpt: part: Defini...
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
  			  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) {
9b643e312   Masahiro Yamada   treewide: replace...
757
758
  			pr_err("More partitions than allowed!
  ");
cef68bf90   Lukasz Majewski   gpt: part: Defini...
759
760
761
762
763
764
765
766
767
768
769
770
  			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))) {
9b643e312   Masahiro Yamada   treewide: replace...
771
772
  			pr_err("Partition name: %s does not match %s!
  ",
cef68bf90   Lukasz Majewski   gpt: part: Defini...
773
774
775
776
777
778
779
780
  			      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 ",
f8d6165d4   Simon Glass   dm: part: Correct...
781
782
  		      (unsigned long long)gpt_part_size,
  		      (unsigned long long)partitions[i].size);
cef68bf90   Lukasz Majewski   gpt: part: Defini...
783
784
  
  		if (le64_to_cpu(gpt_part_size) != partitions[i].size) {
c2fdd3456   Kever Yang   cmd: gpt: fix the...
785
786
787
  			/* We do not check the extend partition size */
  			if ((i == parts - 1) && (partitions[i].size == 0))
  				continue;
9b643e312   Masahiro Yamada   treewide: replace...
788
789
  			pr_err("Partition %s size: %llu does not match %llu!
  ",
f8d6165d4   Simon Glass   dm: part: Correct...
790
791
  			      efi_str, (unsigned long long)gpt_part_size,
  			      (unsigned long long)partitions[i].size);
cef68bf90   Lukasz Majewski   gpt: part: Defini...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
  			return -1;
  		}
  
  		/*
  		 * Start address is optional - check only if provided
  		 * in '$partition' variable
  		 */
  		if (!partitions[i].start) {
  			debug("
  ");
  			continue;
  		}
  
  		/* Check if GPT and ENV start LBAs match */
  		debug("start LBA - GPT: %8llu, ENV: %8llu
  ",
  		      le64_to_cpu(gpt_e[i].starting_lba),
f8d6165d4   Simon Glass   dm: part: Correct...
809
  		      (unsigned long long)partitions[i].start);
cef68bf90   Lukasz Majewski   gpt: part: Defini...
810
811
  
  		if (le64_to_cpu(gpt_e[i].starting_lba) != partitions[i].start) {
9b643e312   Masahiro Yamada   treewide: replace...
812
813
  			pr_err("Partition %s start: %llu does not match %llu!
  ",
cef68bf90   Lukasz Majewski   gpt: part: Defini...
814
  			      efi_str, le64_to_cpu(gpt_e[i].starting_lba),
f8d6165d4   Simon Glass   dm: part: Correct...
815
  			      (unsigned long long)partitions[i].start);
cef68bf90   Lukasz Majewski   gpt: part: Defini...
816
817
818
819
820
821
  			return -1;
  		}
  	}
  
  	return 0;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
822
  int is_valid_gpt_buf(struct blk_desc *dev_desc, void *buf)
0ff7e585d   Steve Rae   fastboot: handle ...
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  {
  	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;
  }
4101f6879   Simon Glass   dm: Drop the bloc...
842
  int write_mbr_and_gpt_partitions(struct blk_desc *dev_desc, void *buf)
0ff7e585d   Steve Rae   fastboot: handle ...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
  {
  	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) */
2a981dc2c   Simon Glass   dm: block: Adjust...
867
  	if (blk_dwrite(dev_desc, lba, cnt, buf) != cnt) {
0ff7e585d   Steve Rae   fastboot: handle ...
868
869
870
871
872
873
874
875
876
  		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")
  ",
  		       __func__, "MBR", cnt, lba);
  		return 1;
  	}
  
  	/* write Primary GPT */
  	lba = GPT_PRIMARY_PARTITION_TABLE_LBA;
  	cnt = 1;	/* GPT Header (1 block) */
2a981dc2c   Simon Glass   dm: block: Adjust...
877
  	if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
0ff7e585d   Steve Rae   fastboot: handle ...
878
879
880
881
882
883
884
885
  		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")
  ",
  		       __func__, "Primary GPT Header", cnt, lba);
  		return 1;
  	}
  
  	lba = le64_to_cpu(gpt_h->partition_entry_lba);
  	cnt = gpt_e_blk_cnt;
2a981dc2c   Simon Glass   dm: block: Adjust...
886
  	if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
0ff7e585d   Steve Rae   fastboot: handle ...
887
888
889
890
891
892
893
894
895
896
897
  		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")
  ",
  		       __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;
2a981dc2c   Simon Glass   dm: block: Adjust...
898
  	if (blk_dwrite(dev_desc, lba, cnt, gpt_e) != cnt) {
0ff7e585d   Steve Rae   fastboot: handle ...
899
900
901
902
903
904
905
906
  		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")
  ",
  		       __func__, "Backup GPT Entries", cnt, lba);
  		return 1;
  	}
  
  	lba = le64_to_cpu(gpt_h->my_lba);
  	cnt = 1;	/* GPT Header (1 block) */
2a981dc2c   Simon Glass   dm: block: Adjust...
907
  	if (blk_dwrite(dev_desc, lba, cnt, gpt_h) != cnt) {
0ff7e585d   Steve Rae   fastboot: handle ...
908
909
910
911
912
913
914
915
  		printf("%s: failed writing '%s' (%d blks at 0x" LBAF ")
  ",
  		       __func__, "Backup GPT Header", cnt, lba);
  		return 1;
  	}
  
  	return 0;
  }
2c840c82b   Ye Li   MLK-18591-3 andro...
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
  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 ")
  ",
  		       __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 ")
  ",
  		       __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 ")
  ",
  		       __func__, "Backup GPT Header", cnt, lba);
  		return 1;
  	}
  
  	return 0;
  }
40684ddb8   Lukasz Majewski   gpt: Support for ...
971
  #endif
07f3d789b   richardretanubun   Add support for C...
972
973
974
975
976
977
978
979
980
981
982
  /*
   * 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 &&
8faefadb7   Marc Dietrich   disk: fix unalign...
983
  		get_unaligned_le32(&part->start_sect) == 1UL) {
07f3d789b   richardretanubun   Add support for C...
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
  		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;
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
1001
  	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
07f3d789b   richardretanubun   Add support for C...
1002
  		return 0;
07f3d789b   richardretanubun   Add support for C...
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
  
  	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.
   */
4101f6879   Simon Glass   dm: Drop the bloc...
1022
  static int is_gpt_valid(struct blk_desc *dev_desc, u64 lba,
e04350d29   Steve Rae   disk: part_efi: c...
1023
  			gpt_header *pgpt_head, gpt_entry **pgpt_pte)
07f3d789b   richardretanubun   Add support for C...
1024
  {
b351ccf11   Tom Rini   part_efi: In is_g...
1025
  	/* Confirm valid arguments prior to allocation. */
07f3d789b   richardretanubun   Add support for C...
1026
  	if (!dev_desc || !pgpt_head) {
df70b1c2e   Doug Anderson   cosmetic: Replace...
1027
1028
  		printf("%s: Invalid Argument(s)
  ", __func__);
07f3d789b   richardretanubun   Add support for C...
1029
1030
  		return 0;
  	}
3cc566117   Patrick Delaunay   disk: efi: correc...
1031
  	ALLOC_CACHE_ALIGN_BUFFER_PAD(legacy_mbr, mbr, 1, dev_desc->blksz);
b351ccf11   Tom Rini   part_efi: In is_g...
1032

ff98cb905   Peter Jones   part: extract MBR...
1033
1034
1035
1036
1037
1038
  	/* Read MBR Header from device */
  	if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1) {
  		printf("*** ERROR: Can't read MBR header ***
  ");
  		return 0;
  	}
07f3d789b   richardretanubun   Add support for C...
1039
  	/* Read GPT Header from device */
2a981dc2c   Simon Glass   dm: block: Adjust...
1040
  	if (blk_dread(dev_desc, (lbaint_t)lba, 1, pgpt_head) != 1) {
07f3d789b   richardretanubun   Add support for C...
1041
1042
1043
1044
  		printf("*** ERROR: Can't read GPT header ***
  ");
  		return 0;
  	}
e1f6b0a02   Steve Rae   disk: part_efi: m...
1045
  	if (validate_gpt_header(pgpt_head, (lbaint_t)lba, dev_desc->lba))
07f3d789b   richardretanubun   Add support for C...
1046
  		return 0;
07f3d789b   richardretanubun   Add support for C...
1047

ff98cb905   Peter Jones   part: extract MBR...
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
  	if (dev_desc->sig_type == SIG_TYPE_NONE) {
  		efi_guid_t empty = {};
  		if (memcmp(&pgpt_head->disk_guid, &empty, sizeof(empty))) {
  			dev_desc->sig_type = SIG_TYPE_GUID;
  			memcpy(&dev_desc->guid_sig, &pgpt_head->disk_guid,
  			      sizeof(empty));
  		} else if (mbr->unique_mbr_signature != 0) {
  			dev_desc->sig_type = SIG_TYPE_MBR;
  			dev_desc->mbr_sig = mbr->unique_mbr_signature;
  		}
  	}
07f3d789b   richardretanubun   Add support for C...
1059
1060
1061
1062
1063
1064
1065
  	/* 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
  ");
  		return 0;
  	}
e1f6b0a02   Steve Rae   disk: part_efi: m...
1066
  	if (validate_gpt_entries(pgpt_head, *pgpt_pte)) {
dbcf1e3cc   Luo Ji   [iot] Support dua...
1067
1068
1069
1070
1071
1072
1073
  
  #if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
  	/* Heap memory is very limited in SPL, if the dual bootloader is
  	 * enabled, just load pte to dram instead of oc-ram. In such case,
  	 * this part of  memory shouldn't be freed. But in common routine,
  	 * don't forget to free the memory after use.
  	 */
deb5ca802   Doug Anderson   disk: part_efi: f...
1074
  		free(*pgpt_pte);
dbcf1e3cc   Luo Ji   [iot] Support dua...
1075
  #endif
07f3d789b   richardretanubun   Add support for C...
1076
1077
  		return 0;
  	}
07f3d789b   richardretanubun   Add support for C...
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  	/* 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!
   */
4101f6879   Simon Glass   dm: Drop the bloc...
1091
1092
  static gpt_entry *alloc_read_gpt_entries(struct blk_desc *dev_desc,
  					 gpt_header *pgpt_head)
07f3d789b   richardretanubun   Add support for C...
1093
  {
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
1094
  	size_t count = 0, blk_cnt;
7c4213f6a   Stephen Warren   block: pass block...
1095
  	lbaint_t blk;
07f3d789b   richardretanubun   Add support for C...
1096
1097
1098
  	gpt_entry *pte = NULL;
  
  	if (!dev_desc || !pgpt_head) {
df70b1c2e   Doug Anderson   cosmetic: Replace...
1099
1100
  		printf("%s: Invalid Argument(s)
  ", __func__);
07f3d789b   richardretanubun   Add support for C...
1101
1102
  		return NULL;
  	}
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
1103
1104
  	count = le32_to_cpu(pgpt_head->num_partition_entries) *
  		le32_to_cpu(pgpt_head->sizeof_partition_entry);
07f3d789b   richardretanubun   Add support for C...
1105

5afb8d151   Simon Glass   part_efi: Fix com...
1106
1107
  	debug("%s: count = %u * %u = %lu
  ", __func__,
fae2bf22a   Chang Hyun Park   gpt: The leXX_to_...
1108
  	      (u32) le32_to_cpu(pgpt_head->num_partition_entries),
5afb8d151   Simon Glass   part_efi: Fix com...
1109
1110
  	      (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry),
  	      (ulong)count);
07f3d789b   richardretanubun   Add support for C...
1111

dbcf1e3cc   Luo Ji   [iot] Support dua...
1112
1113
1114
1115
1116
1117
  	/* Allocate memory for PTE.
  	 * Heap memory is very limited in SPL, if the dual bootloader is
  	 * enabled, just load pte to dram instead of oc-ram. In such case,
  	 * this part of  memory shouldn't be freed. But in common routine,
  	 * don't forget to free the memory after use.
  	 */
07f3d789b   richardretanubun   Add support for C...
1118
  	if (count != 0) {
dbcf1e3cc   Luo Ji   [iot] Support dua...
1119
1120
1121
  #if defined(CONFIG_DUAL_BOOTLOADER) && defined(CONFIG_SPL_BUILD)
  		pte = (gpt_entry *)CONFIG_SYS_SPL_PTE_RAM_BASE;
  #else
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
1122
1123
  		pte = memalign(ARCH_DMA_MINALIGN,
  			       PAD_TO_BLOCKSIZE(count, dev_desc));
dbcf1e3cc   Luo Ji   [iot] Support dua...
1124
  #endif
07f3d789b   richardretanubun   Add support for C...
1125
1126
1127
  	}
  
  	if (count == 0 || pte == NULL) {
5afb8d151   Simon Glass   part_efi: Fix com...
1128
1129
1130
  		printf("%s: ERROR: Can't allocate %#lX bytes for GPT Entries
  ",
  		       __func__, (ulong)count);
07f3d789b   richardretanubun   Add support for C...
1131
1132
  		return NULL;
  	}
07f3d789b   richardretanubun   Add support for C...
1133
  	/* Read GPT Entries from device */
7c4213f6a   Stephen Warren   block: pass block...
1134
  	blk = le64_to_cpu(pgpt_head->partition_entry_lba);
ae1768a72   Egbert Eich   disk/gpt: Fix GPT...
1135
  	blk_cnt = BLOCK_CNT(count, dev_desc);
2a981dc2c   Simon Glass   dm: block: Adjust...
1136
  	if (blk_dread(dev_desc, blk, (lbaint_t)blk_cnt, pte) != blk_cnt) {
07f3d789b   richardretanubun   Add support for C...
1137
1138
  		printf("*** ERROR: Can't read GPT Entries ***
  ");
dbcf1e3cc   Luo Ji   [iot] Support dua...
1139
  #if !defined(CONFIG_DUAL_BOOTLOADER) || !defined(CONFIG_SPL_BUILD)
07f3d789b   richardretanubun   Add support for C...
1140
  		free(pte);
dbcf1e3cc   Luo Ji   [iot] Support dua...
1141
  #endif
07f3d789b   richardretanubun   Add support for C...
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  		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) {
df70b1c2e   Doug Anderson   cosmetic: Replace...
1158
1159
  		printf("%s: Invalid Argument(s)
  ", __func__);
07f3d789b   richardretanubun   Add support for C...
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
  		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) {
df70b1c2e   Doug Anderson   cosmetic: Replace...
1170
1171
  		debug("%s: Found an unused PTE GUID at 0x%08X
  ", __func__,
9936be31f   Taylor Hutt   disk: Address cas...
1172
  		      (unsigned int)(uintptr_t)pte);
07f3d789b   richardretanubun   Add support for C...
1173
1174
1175
1176
1177
1178
  
  		return 0;
  	} else {
  		return 1;
  	}
  }
96e5b03c8   Simon Glass   dm: part: Convert...
1179
1180
1181
1182
1183
1184
1185
1186
1187
  
  /*
   * 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,
87b8530fe   Petr Kulhavy   disk: part: imple...
1188
  	.max_entries	= GPT_ENTRY_NUMBERS,
3e8bd4695   Simon Glass   dm: part: Rename ...
1189
  	.get_info	= part_get_info_ptr(part_get_info_efi),
084bf4c24   Simon Glass   part: Rename test...
1190
1191
  	.print		= part_print_ptr(part_print_efi),
  	.test		= part_test_efi,
96e5b03c8   Simon Glass   dm: part: Convert...
1192
  };
07f3d789b   richardretanubun   Add support for C...
1193
  #endif