]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - disk/part_efi.c
gpt: The leXX_to_int() calls replaced with ones defined at <compiler.h>
[karo-tx-uboot.git] / disk / part_efi.c
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