xref: /openbmc/u-boot/disk/part_efi.c (revision fae2bf22a2b1aee85734fc2643ac6ede88cbbd01)
1 /*
2  * Copyright (C) 2008 RuggedCom, Inc.
3  * Richard Retanubun <RichardRetanubun@RuggedCom.com>
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 /*
25  * Problems with CONFIG_SYS_64BIT_LBA:
26  *
27  * struct disk_partition.start in include/part.h is sized as ulong.
28  * When CONFIG_SYS_64BIT_LBA is activated, lbaint_t changes from ulong to uint64_t.
29  * For now, it is cast back to ulong at assignment.
30  *
31  * This limits the maximum size of addressable storage to < 2 Terra Bytes
32  */
33 #include <common.h>
34 #include <command.h>
35 #include <ide.h>
36 #include <malloc.h>
37 #include <part_efi.h>
38 #include <linux/ctype.h>
39 
40 #if defined(CONFIG_CMD_IDE) || \
41     defined(CONFIG_CMD_SATA) || \
42     defined(CONFIG_CMD_SCSI) || \
43     defined(CONFIG_CMD_USB) || \
44     defined(CONFIG_MMC) || \
45     defined(CONFIG_SYSTEMACE)
46 
47 /**
48  * efi_crc32() - EFI version of crc32 function
49  * @buf: buffer to calculate crc32 of
50  * @len - length of buf
51  *
52  * Description: Returns EFI-style CRC32 value for @buf
53  */
54 static inline u32 efi_crc32(const void *buf, u32 len)
55 {
56 	return crc32(0, buf, len);
57 }
58 
59 /*
60  * Private function prototypes
61  */
62 
63 static int pmbr_part_valid(struct partition *part);
64 static int is_pmbr_valid(legacy_mbr * mbr);
65 
66 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
67 				gpt_header * pgpt_head, gpt_entry ** pgpt_pte);
68 
69 static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
70 				gpt_header * pgpt_head);
71 
72 static int is_pte_valid(gpt_entry * pte);
73 
74 static char *print_efiname(gpt_entry *pte)
75 {
76 	static char name[PARTNAME_SZ + 1];
77 	int i;
78 	for (i = 0; i < PARTNAME_SZ; i++) {
79 		u8 c;
80 		c = pte->partition_name[i] & 0xff;
81 		c = (c && !isprint(c)) ? '.' : c;
82 		name[i] = c;
83 	}
84 	name[PARTNAME_SZ] = 0;
85 	return name;
86 }
87 
88 static void uuid_string(unsigned char *uuid, char *str)
89 {
90 	static const u8 le[16] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11,
91 				  12, 13, 14, 15};
92 	int i;
93 
94 	for (i = 0; i < 16; i++) {
95 		sprintf(str, "%02x", uuid[le[i]]);
96 		str += 2;
97 		switch (i) {
98 		case 3:
99 		case 5:
100 		case 7:
101 		case 9:
102 			*str++ = '-';
103 			break;
104 		}
105 	}
106 }
107 
108 static efi_guid_t system_guid = PARTITION_SYSTEM_GUID;
109 
110 static inline int is_bootable(gpt_entry *p)
111 {
112 	return p->attributes.fields.legacy_bios_bootable ||
113 		!memcmp(&(p->partition_type_guid), &system_guid,
114 			sizeof(efi_guid_t));
115 }
116 
117 /*
118  * Public Functions (include/part.h)
119  */
120 
121 void print_part_efi(block_dev_desc_t * dev_desc)
122 {
123 	ALLOC_CACHE_ALIGN_BUFFER(gpt_header, gpt_head, 1);
124 	gpt_entry *gpt_pte = NULL;
125 	int i = 0;
126 	char uuid[37];
127 
128 	if (!dev_desc) {
129 		printf("%s: Invalid Argument(s)\n", __func__);
130 		return;
131 	}
132 	/* This function validates AND fills in the GPT header and PTE */
133 	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
134 			 gpt_head, &gpt_pte) != 1) {
135 		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
136 		return;
137 	}
138 
139 	debug("%s: gpt-entry at %p\n", __func__, gpt_pte);
140 
141 	printf("Part\tStart LBA\tEnd LBA\t\tName\n");
142 	printf("\tAttributes\n");
143 	printf("\tType UUID\n");
144 	printf("\tPartition UUID\n");
145 
146 	for (i = 0; i < le32_to_cpu(gpt_head->num_partition_entries); i++) {
147 		/* Stop at the first non valid PTE */
148 		if (!is_pte_valid(&gpt_pte[i]))
149 			break;
150 
151 		printf("%3d\t0x%08llx\t0x%08llx\t\"%s\"\n", (i + 1),
152 			le64_to_cpu(gpt_pte[i].starting_lba),
153 			le64_to_cpu(gpt_pte[i].ending_lba),
154 			print_efiname(&gpt_pte[i]));
155 		printf("\tattrs:\t0x%016llx\n", gpt_pte[i].attributes.raw);
156 		uuid_string(gpt_pte[i].partition_type_guid.b, uuid);
157 		printf("\ttype:\t%s\n", uuid);
158 		uuid_string(gpt_pte[i].unique_partition_guid.b, uuid);
159 		printf("\tuuid:\t%s\n", uuid);
160 	}
161 
162 	/* Remember to free pte */
163 	free(gpt_pte);
164 	return;
165 }
166 
167 int get_partition_info_efi(block_dev_desc_t * dev_desc, int part,
168 				disk_partition_t * info)
169 {
170 	ALLOC_CACHE_ALIGN_BUFFER(gpt_header, gpt_head, 1);
171 	gpt_entry *gpt_pte = NULL;
172 
173 	/* "part" argument must be at least 1 */
174 	if (!dev_desc || !info || part < 1) {
175 		printf("%s: Invalid Argument(s)\n", __func__);
176 		return -1;
177 	}
178 
179 	/* This function validates AND fills in the GPT header and PTE */
180 	if (is_gpt_valid(dev_desc, GPT_PRIMARY_PARTITION_TABLE_LBA,
181 			gpt_head, &gpt_pte) != 1) {
182 		printf("%s: *** ERROR: Invalid GPT ***\n", __func__);
183 		return -1;
184 	}
185 
186 	if (part > le32_to_cpu(gpt_head->num_partition_entries) ||
187 	    !is_pte_valid(&gpt_pte[part - 1])) {
188 		printf("%s: *** ERROR: Invalid partition number %d ***\n",
189 			__func__, part);
190 		return -1;
191 	}
192 
193 	/* The ulong casting limits the maximum disk size to 2 TB */
194 	info->start = (u64)le64_to_cpu(gpt_pte[part - 1].starting_lba);
195 	/* The ending LBA is inclusive, to calculate size, add 1 to it */
196 	info->size = ((u64)le64_to_cpu(gpt_pte[part - 1].ending_lba) + 1)
197 		     - info->start;
198 	info->blksz = GPT_BLOCK_SIZE;
199 
200 	sprintf((char *)info->name, "%s",
201 			print_efiname(&gpt_pte[part - 1]));
202 	sprintf((char *)info->type, "U-Boot");
203 	info->bootable = is_bootable(&gpt_pte[part - 1]);
204 #ifdef CONFIG_PARTITION_UUIDS
205 	uuid_string(gpt_pte[part - 1].unique_partition_guid.b, info->uuid);
206 #endif
207 
208 	debug("%s: start 0x%lX, size 0x%lX, name %s", __func__,
209 		info->start, info->size, info->name);
210 
211 	/* Remember to free pte */
212 	free(gpt_pte);
213 	return 0;
214 }
215 
216 int test_part_efi(block_dev_desc_t * dev_desc)
217 {
218 	ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, legacymbr, 1);
219 
220 	/* Read legacy MBR from block 0 and validate it */
221 	if ((dev_desc->block_read(dev_desc->dev, 0, 1, (ulong *)legacymbr) != 1)
222 		|| (is_pmbr_valid(legacymbr) != 1)) {
223 		return -1;
224 	}
225 	return 0;
226 }
227 
228 /*
229  * Private functions
230  */
231 /*
232  * pmbr_part_valid(): Check for EFI partition signature
233  *
234  * Returns: 1 if EFI GPT partition type is found.
235  */
236 static int pmbr_part_valid(struct partition *part)
237 {
238 	if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
239 		le32_to_cpu(part->start_sect) == 1UL) {
240 		return 1;
241 	}
242 
243 	return 0;
244 }
245 
246 /*
247  * is_pmbr_valid(): test Protective MBR for validity
248  *
249  * Returns: 1 if PMBR is valid, 0 otherwise.
250  * Validity depends on two things:
251  *  1) MSDOS signature is in the last two bytes of the MBR
252  *  2) One partition of type 0xEE is found, checked by pmbr_part_valid()
253  */
254 static int is_pmbr_valid(legacy_mbr * mbr)
255 {
256 	int i = 0;
257 
258 	if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
259 		return 0;
260 
261 	for (i = 0; i < 4; i++) {
262 		if (pmbr_part_valid(&mbr->partition_record[i])) {
263 			return 1;
264 		}
265 	}
266 	return 0;
267 }
268 
269 /**
270  * is_gpt_valid() - tests one GPT header and PTEs for validity
271  *
272  * lba is the logical block address of the GPT header to test
273  * gpt is a GPT header ptr, filled on return.
274  * ptes is a PTEs ptr, filled on return.
275  *
276  * Description: returns 1 if valid,  0 on error.
277  * If valid, returns pointers to PTEs.
278  */
279 static int is_gpt_valid(block_dev_desc_t * dev_desc, unsigned long long lba,
280 			gpt_header * pgpt_head, gpt_entry ** pgpt_pte)
281 {
282 	u32 crc32_backup = 0;
283 	u32 calc_crc32;
284 	unsigned long long lastlba;
285 
286 	if (!dev_desc || !pgpt_head) {
287 		printf("%s: Invalid Argument(s)\n", __func__);
288 		return 0;
289 	}
290 
291 	/* Read GPT Header from device */
292 	if (dev_desc->block_read(dev_desc->dev, lba, 1, pgpt_head) != 1) {
293 		printf("*** ERROR: Can't read GPT header ***\n");
294 		return 0;
295 	}
296 
297 	/* Check the GPT header signature */
298 	if (le64_to_cpu(pgpt_head->signature) != GPT_HEADER_SIGNATURE) {
299 		printf("GUID Partition Table Header signature is wrong:"
300 			"0x%llX != 0x%llX\n",
301 			le64_to_cpu(pgpt_head->signature),
302 			GPT_HEADER_SIGNATURE);
303 		return 0;
304 	}
305 
306 	/* Check the GUID Partition Table CRC */
307 	memcpy(&crc32_backup, &pgpt_head->header_crc32, sizeof(crc32_backup));
308 	memset(&pgpt_head->header_crc32, 0, sizeof(pgpt_head->header_crc32));
309 
310 	calc_crc32 = efi_crc32((const unsigned char *)pgpt_head,
311 		le32_to_cpu(pgpt_head->header_size));
312 
313 	memcpy(&pgpt_head->header_crc32, &crc32_backup, sizeof(crc32_backup));
314 
315 	if (calc_crc32 != le32_to_cpu(crc32_backup)) {
316 		printf("GUID Partition Table Header CRC is wrong:"
317 			"0x%x != 0x%x\n",
318 		       le32_to_cpu(crc32_backup), calc_crc32);
319 		return 0;
320 	}
321 
322 	/* Check that the my_lba entry points to the LBA that contains the GPT */
323 	if (le64_to_cpu(pgpt_head->my_lba) != lba) {
324 		printf("GPT: my_lba incorrect: %llX != %llX\n",
325 			le64_to_cpu(pgpt_head->my_lba),
326 			lba);
327 		return 0;
328 	}
329 
330 	/* Check the first_usable_lba and last_usable_lba are within the disk. */
331 	lastlba = (unsigned long long)dev_desc->lba;
332 	if (le64_to_cpu(pgpt_head->first_usable_lba) > lastlba) {
333 		printf("GPT: first_usable_lba incorrect: %llX > %llX\n",
334 			le64_to_cpu(pgpt_head->first_usable_lba), lastlba);
335 		return 0;
336 	}
337 	if (le64_to_cpu(pgpt_head->last_usable_lba) > lastlba) {
338 		printf("GPT: last_usable_lba incorrect: %llX > %llX\n",
339 			(u64) le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
340 		return 0;
341 	}
342 
343 	debug("GPT: first_usable_lba: %llX last_usable_lba %llX last lba %llX\n",
344 		le64_to_cpu(pgpt_head->first_usable_lba),
345 		le64_to_cpu(pgpt_head->last_usable_lba), lastlba);
346 
347 	/* Read and allocate Partition Table Entries */
348 	*pgpt_pte = alloc_read_gpt_entries(dev_desc, pgpt_head);
349 	if (*pgpt_pte == NULL) {
350 		printf("GPT: Failed to allocate memory for PTE\n");
351 		return 0;
352 	}
353 
354 	/* Check the GUID Partition Table Entry Array CRC */
355 	calc_crc32 = efi_crc32((const unsigned char *)*pgpt_pte,
356 		le32_to_cpu(pgpt_head->num_partition_entries) *
357 		le32_to_cpu(pgpt_head->sizeof_partition_entry));
358 
359 	if (calc_crc32 != le32_to_cpu(pgpt_head->partition_entry_array_crc32)) {
360 		printf("GUID Partition Table Entry Array CRC is wrong:"
361 			"0x%x != 0x%x\n",
362 			le32_to_cpu(pgpt_head->partition_entry_array_crc32),
363 			calc_crc32);
364 
365 		free(*pgpt_pte);
366 		return 0;
367 	}
368 
369 	/* We're done, all's well */
370 	return 1;
371 }
372 
373 /**
374  * alloc_read_gpt_entries(): reads partition entries from disk
375  * @dev_desc
376  * @gpt - GPT header
377  *
378  * Description: Returns ptes on success,  NULL on error.
379  * Allocates space for PTEs based on information found in @gpt.
380  * Notes: remember to free pte when you're done!
381  */
382 static gpt_entry *alloc_read_gpt_entries(block_dev_desc_t * dev_desc,
383 					 gpt_header * pgpt_head)
384 {
385 	size_t count = 0;
386 	gpt_entry *pte = NULL;
387 
388 	if (!dev_desc || !pgpt_head) {
389 		printf("%s: Invalid Argument(s)\n", __func__);
390 		return NULL;
391 	}
392 
393 	count = le32_to_cpu(pgpt_head->num_partition_entries) *
394 		le32_to_cpu(pgpt_head->sizeof_partition_entry);
395 
396 	debug("%s: count = %u * %u = %zu\n", __func__,
397 	      (u32) le32_to_cpu(pgpt_head->num_partition_entries),
398 	      (u32) le32_to_cpu(pgpt_head->sizeof_partition_entry), count);
399 
400 	/* Allocate memory for PTE, remember to FREE */
401 	if (count != 0) {
402 		pte = memalign(ARCH_DMA_MINALIGN, count);
403 	}
404 
405 	if (count == 0 || pte == NULL) {
406 		printf("%s: ERROR: Can't allocate 0x%zX "
407 		       "bytes for GPT Entries\n",
408 			__func__, count);
409 		return NULL;
410 	}
411 
412 	/* Read GPT Entries from device */
413 	if (dev_desc->block_read (dev_desc->dev,
414 		le64_to_cpu(pgpt_head->partition_entry_lba),
415 		(lbaint_t) (count / GPT_BLOCK_SIZE), pte)
416 		!= (count / GPT_BLOCK_SIZE)) {
417 
418 		printf("*** ERROR: Can't read GPT Entries ***\n");
419 		free(pte);
420 		return NULL;
421 	}
422 	return pte;
423 }
424 
425 /**
426  * is_pte_valid(): validates a single Partition Table Entry
427  * @gpt_entry - Pointer to a single Partition Table Entry
428  *
429  * Description: returns 1 if valid,  0 on error.
430  */
431 static int is_pte_valid(gpt_entry * pte)
432 {
433 	efi_guid_t unused_guid;
434 
435 	if (!pte) {
436 		printf("%s: Invalid Argument(s)\n", __func__);
437 		return 0;
438 	}
439 
440 	/* Only one validation for now:
441 	 * The GUID Partition Type != Unused Entry (ALL-ZERO)
442 	 */
443 	memset(unused_guid.b, 0, sizeof(unused_guid.b));
444 
445 	if (memcmp(pte->partition_type_guid.b, unused_guid.b,
446 		sizeof(unused_guid.b)) == 0) {
447 
448 		debug("%s: Found an unused PTE GUID at 0x%08X\n", __func__,
449 		      (unsigned int)(uintptr_t)pte);
450 
451 		return 0;
452 	} else {
453 		return 1;
454 	}
455 }
456 #endif
457