4 Copyright (C) 2000-2001 Dell Computer Corporation <Matt_Domsch@dell.com>
6 EFI GUID Partition Table handling
7 Per Intel EFI Specification v1.02
8 http://developer.intel.com/technology/efi/efi.htm
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <sys/ioctl.h>
34 #include <sys/utsname.h>
35 #include <asm/byteorder.h>
39 #include "efibootmgr.h"
41 #define BLKGETLASTSECT _IO(0x12,108) /* get last sector of block device */
42 #define BLKGETSIZE _IO(0x12,96) /* return device size */
43 #define BLKSSZGET _IO(0x12,104) /* get block device sector size */
44 #define BLKGETSIZE64 _IOR(0x12,114,uint64_t) /* return device size in bytes (u64 *arg) */
46 struct blkdev_ioctl_param {
48 size_t content_length;
49 char * block_contents;
53 * efi_crc32() - EFI version of crc32 function
54 * @buf: buffer to calculate crc32 of
55 * @len - length of buf
57 * Description: Returns EFI-style CRC32 value for @buf
59 * This function uses the little endian Ethernet polynomial
60 * but seeds the function with ~0, and xor's with ~0 at the end.
61 * Note, the EFI Specification, v1.02, has a reference to
62 * Dr. Dobbs Journal, May 1994 (actually it's in May 1992).
64 static inline uint32_t
65 efi_crc32(const void *buf, unsigned long len)
67 return (crc32(buf, len, ~0L) ^ ~0L);
71 * is_pmbr_valid(): test Protective MBR for validity
72 * @mbr: pointer to a legacy mbr structure
74 * Description: Returns 1 if PMBR is valid, 0 otherwise.
75 * Validity depends on two things:
76 * 1) MSDOS signature is in the last two bytes of the MBR
77 * 2) One partition of type 0xEE is found
80 is_pmbr_valid(legacy_mbr *mbr)
82 int i, found = 0, signature = 0;
85 signature = (__le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
86 for (i = 0; signature && i < 4; i++) {
87 if (mbr->partition[i].os_type ==
88 EFI_PMBR_OSTYPE_EFI_GPT) {
93 return (signature && found);
97 * kernel_has_blkgetsize64()
99 * Returns: 0 on false, 1 on true
100 * True means kernel is 2.4.x, x>=18, or
105 kernel_has_blkgetsize64(void)
107 int major=0, minor=0, patch=0, parsed;
111 memset(&u, 0, sizeof(u));
115 parsed = sscanf(u.release, "%d.%d.%d", &major, &minor, &patch);
116 if (parsed < 3) return 0;
117 if (major > 2) return 1;
118 if (major == 2 && minor > 5) return 1;
119 if (major == 2 && minor == 5 && patch >= 4) return 1;
120 if (major == 2 && minor == 4 && patch >= 18) return 1;
125 /************************************************************
128 * - filedes is an open file descriptor, suitable for reading
131 * Last LBA value on success
134 * Try getting BLKGETSIZE64 and BLKSSZGET first,
135 * then BLKGETSIZE if necessary.
136 * Kernels 2.4.15-2.4.18 and 2.5.0-2.5.3 have a broken BLKGETSIZE64
137 * which returns the number of 512-byte sectors, not the size of
138 * the disk in bytes. Fixed in kernels 2.4.18-pre8 and 2.5.4-pre3.
139 ************************************************************/
141 _get_num_sectors(int filedes)
143 unsigned long sectors=0;
146 if (kernel_has_blkgetsize64()) {
147 rc = ioctl(filedes, BLKGETSIZE64, &bytes);
149 return bytes / get_sector_size(filedes);
152 rc = ioctl(filedes, BLKGETSIZE, §ors);
159 /************************************************************
160 * last_lba(): return number of last logical block of device
164 * Description: returns Last LBA value on success, 0 on error.
165 * Notes: The value st_blocks gives the size of the file
166 * in 512-byte blocks, which is OK if
167 * EFI_BLOCK_SIZE_SHIFT == 9.
168 ************************************************************/
171 last_lba(int filedes)
174 uint64_t sectors = 0;
176 memset(&s, 0, sizeof (s));
177 rc = fstat(filedes, &s);
179 fprintf(stderr, "last_lba() could not stat: %s\n",
184 if (S_ISBLK(s.st_mode)) {
185 sectors = _get_num_sectors(filedes);
188 "last_lba(): I don't know how to handle files with mode %x\n",
198 read_lastoddsector(int fd, uint64_t lba, void *buffer, size_t count)
201 struct blkdev_ioctl_param ioctl_param;
203 if (!buffer) return 0;
205 ioctl_param.block = 0; /* read the last sector */
206 ioctl_param.content_length = count;
207 ioctl_param.block_contents = buffer;
209 rc = ioctl(fd, BLKGETLASTSECT, &ioctl_param);
210 if (rc == -1) perror("read failed");
216 read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
218 int sector_size = get_sector_size(fd);
219 off_t offset = lba * sector_size;
225 iobuf_size = lcm(bytes, sector_size);
226 rc = posix_memalign(&iobuf, sector_size, iobuf_size);
229 memset(iobuf, 0, bytes);
232 lseek(fd, offset, SEEK_SET);
233 bytesread = read(fd, iobuf, iobuf_size);
234 memcpy(buffer, iobuf, bytes);
237 /* Kludge. This is necessary to read/write the last
238 block of an odd-sized disk, until Linux 2.5.x kernel fixes.
239 This is only used by gpt.c, and only to read
240 one sector, so we don't have to be fancy.
242 if (!bytesread && !(last_lba(fd) & 1) && lba == last_lba(fd)) {
243 bytesread = read_lastoddsector(fd, lba, buffer, bytes);
249 * alloc_read_gpt_entries(): reads partition entries from disk
250 * @fd is an open file descriptor to the whole disk
251 * @gpt is a buffer into which the GPT will be put
252 * Description: Returns ptes on success, NULL on error.
253 * Allocates space for PTEs based on information found in @gpt.
254 * Notes: remember to free pte when you're done!
257 alloc_read_gpt_entries(int fd, gpt_header * gpt)
260 size_t count = __le32_to_cpu(gpt->num_partition_entries) *
261 __le32_to_cpu(gpt->sizeof_partition_entry);
263 if (!count) return NULL;
265 pte = (gpt_entry *)malloc(count);
268 memset(pte, 0, count);
270 if (!read_lba(fd, __le64_to_cpu(gpt->partition_entry_lba), pte,
279 * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
280 * @fd is an open file descriptor to the whole disk
281 * @lba is the Logical Block Address of the partition table
283 * Description: returns GPT header on success, NULL on error. Allocates
284 * and fills a GPT header starting at @ from @bdev.
285 * Note: remember to free gpt when finished with it.
288 alloc_read_gpt_header(int fd, uint64_t lba)
292 malloc(sizeof (gpt_header));
295 memset(gpt, 0, sizeof (*gpt));
296 if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
305 * is_gpt_valid() - tests one GPT header and PTEs for validity
306 * @fd is an open file descriptor to the whole disk
307 * @lba is the logical block address of the GPT header to test
308 * @gpt is a GPT header ptr, filled on return.
309 * @ptes is a PTEs ptr, filled on return.
311 * Description: returns 1 if valid, 0 on error.
312 * If valid, returns pointers to newly allocated GPT header and PTEs.
315 is_gpt_valid(int fd, uint64_t lba,
316 gpt_header ** gpt, gpt_entry ** ptes)
318 int rc = 0; /* default to not valid */
319 uint32_t crc, origcrc;
323 if (!(*gpt = alloc_read_gpt_header(fd, lba)))
326 /* Check the GUID Partition Table signature */
327 if (__le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
329 printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
330 __le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
337 /* Check the GUID Partition Table Header CRC */
338 origcrc = __le32_to_cpu((*gpt)->header_crc32);
339 (*gpt)->header_crc32 = 0;
340 crc = efi_crc32(*gpt, __le32_to_cpu((*gpt)->header_size));
341 if (crc != origcrc) {
342 // printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc);
343 (*gpt)->header_crc32 = __cpu_to_le32(origcrc);
348 (*gpt)->header_crc32 = __cpu_to_le32(origcrc);
350 /* Check that the my_lba entry points to the LBA
351 * that contains the GPT we read */
352 if (__le64_to_cpu((*gpt)->my_lba) != lba) {
353 // printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", __le64_to_cpu((*gpt)->my_lba), lba);
359 if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) {
365 /* Check the GUID Partition Entry Array CRC */
366 crc = efi_crc32(*ptes,
367 __le32_to_cpu((*gpt)->num_partition_entries) *
368 __le32_to_cpu((*gpt)->sizeof_partition_entry));
369 if (crc != __le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
370 // printf("GUID Partitition Entry Array CRC check failed.\n");
378 /* We're done, all's well */
382 * compare_gpts() - Search disk for valid GPT headers and PTEs
383 * @pgpt is the primary GPT header
384 * @agpt is the alternate GPT header
385 * @lastlba is the last LBA number
386 * Description: Returns nothing. Sanity checks pgpt and agpt fields
387 * and prints warnings on discrepancies.
391 compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
396 if (__le64_to_cpu(pgpt->my_lba) != __le64_to_cpu(agpt->alternate_lba)) {
398 "GPT:Primary header LBA != Alt. header alternate_lba\n");
399 fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
400 __le64_to_cpu(pgpt->my_lba),
401 __le64_to_cpu(agpt->alternate_lba));
404 if (__le64_to_cpu(pgpt->alternate_lba) != __le64_to_cpu(agpt->my_lba)) {
406 "GPT:Primary header alternate_lba != Alt. header my_lba\n");
407 fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
408 __le64_to_cpu(pgpt->alternate_lba),
409 __le64_to_cpu(agpt->my_lba));
412 if (__le64_to_cpu(pgpt->first_usable_lba) !=
413 __le64_to_cpu(agpt->first_usable_lba)) {
414 fprintf(stderr, "GPT:first_usable_lbas don't match.\n");
415 fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
416 __le64_to_cpu(pgpt->first_usable_lba),
417 __le64_to_cpu(agpt->first_usable_lba));
420 if (__le64_to_cpu(pgpt->last_usable_lba) !=
421 __le64_to_cpu(agpt->last_usable_lba)) {
422 fprintf(stderr, "GPT:last_usable_lbas don't match.\n");
423 fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
424 __le64_to_cpu(pgpt->last_usable_lba),
425 __le64_to_cpu(agpt->last_usable_lba));
428 if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
429 fprintf(stderr, "GPT:disk_guids don't match.\n");
432 if (__le32_to_cpu(pgpt->num_partition_entries) !=
433 __le32_to_cpu(agpt->num_partition_entries)) {
434 fprintf(stderr, "GPT:num_partition_entries don't match: "
436 __le32_to_cpu(pgpt->num_partition_entries),
437 __le32_to_cpu(agpt->num_partition_entries));
440 if (__le32_to_cpu(pgpt->sizeof_partition_entry) !=
441 __le32_to_cpu(agpt->sizeof_partition_entry)) {
443 "GPT:sizeof_partition_entry values don't match: "
445 __le32_to_cpu(pgpt->sizeof_partition_entry),
446 __le32_to_cpu(agpt->sizeof_partition_entry));
449 if (__le32_to_cpu(pgpt->partition_entry_array_crc32) !=
450 __le32_to_cpu(agpt->partition_entry_array_crc32)) {
452 "GPT:partition_entry_array_crc32 values don't match: "
454 __le32_to_cpu(pgpt->partition_entry_array_crc32),
455 __le32_to_cpu(agpt->partition_entry_array_crc32));
458 if (__le64_to_cpu(pgpt->alternate_lba) != lastlba) {
460 "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
461 fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
462 __le64_to_cpu(pgpt->alternate_lba), lastlba);
466 if (__le64_to_cpu(agpt->my_lba) != lastlba) {
468 "GPT:Alternate GPT header not at the end of the disk.\n");
469 fprintf(stderr, "GPT:0x%" PRIx64 " != 0x%" PRIx64 "\n",
470 __le64_to_cpu(agpt->my_lba), lastlba);
476 "GPT: Use GNU Parted to correct GPT errors.\n");
481 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
482 * @fd is an open file descriptor to the whole disk
483 * @gpt is a GPT header ptr, filled on return.
484 * @ptes is a PTEs ptr, filled on return.
485 * Description: Returns 1 if valid, 0 on error.
486 * If valid, returns pointers to newly allocated GPT header and PTEs.
487 * Validity depends on finding either the Primary GPT header and PTEs valid,
488 * or the Alternate GPT header and PTEs valid, and the PMBR valid.
491 find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
493 int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
494 gpt_header *pgpt = NULL, *agpt = NULL;
495 gpt_entry *pptes = NULL, *aptes = NULL;
496 legacy_mbr *legacymbr = NULL;
501 lastlba = last_lba(fd);
502 good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
505 good_agpt = is_gpt_valid(fd,
506 __le64_to_cpu(pgpt->alternate_lba),
509 good_agpt = is_gpt_valid(fd, lastlba,
514 good_agpt = is_gpt_valid(fd, lastlba,
518 /* The obviously unsuccessful case */
519 if (!good_pgpt && !good_agpt) {
523 /* This will be added to the EFI Spec. per Intel after v1.02. */
524 legacymbr = malloc(sizeof (*legacymbr));
526 memset(legacymbr, 0, sizeof (*legacymbr));
527 read_lba(fd, 0, (uint8_t *) legacymbr,
528 sizeof (*legacymbr));
529 good_pmbr = is_pmbr_valid(legacymbr);
534 /* Failure due to bad PMBR */
535 if ((good_pgpt || good_agpt) && !good_pmbr && !opts.forcegpt) {
537 " Warning: Disk has a valid GPT signature "
538 "but invalid PMBR.\n"
539 " Assuming this disk is *not* a GPT disk anymore.\n"
540 " Use gpt kernel option to override. "
541 "Use GNU Parted to correct disk.\n");
545 /* Would fail due to bad PMBR, but force GPT anyhow */
546 if ((good_pgpt || good_agpt) && !good_pmbr && opts.forcegpt) {
548 " Warning: Disk has a valid GPT signature but "
550 " Use GNU Parted to correct disk.\n"
551 " gpt option taken, disk treated as GPT.\n");
554 compare_gpts(pgpt, agpt, lastlba);
557 if (good_pgpt && (good_pmbr || opts.forcegpt)) {
560 if (agpt) { free(agpt); agpt = NULL; }
561 if (aptes) { free(aptes); aptes = NULL; }
564 "Alternate GPT is invalid, "
565 "using primary GPT.\n");
569 else if (good_agpt && (good_pmbr || opts.forcegpt)) {
572 if (pgpt) { free(pgpt); pgpt = NULL; }
573 if (pptes) { free(pptes); pptes = NULL; }
575 "Primary GPT is invalid, using alternate GPT.\n");
580 if (pgpt) { free(pgpt); pgpt=NULL; }
581 if (agpt) { free(agpt); agpt=NULL; }
582 if (pptes) { free(pptes); pptes=NULL; }
583 if (aptes) { free(aptes); aptes=NULL; }
590 /************************************************************
591 * gpt_disk_get_partition_info()
593 * - open file descriptor fd
594 * - start, size, signature, mbr_type, signature_type
595 * Modifies: all these
598 * non-zero on failure
600 ************************************************************/
602 gpt_disk_get_partition_info(int fd,
604 uint64_t * start, uint64_t * size,
606 uint8_t * mbr_type, uint8_t * signature_type)
608 gpt_header *gpt = NULL;
609 gpt_entry *ptes = NULL, *p;
611 if (!find_valid_gpt(fd, &gpt, &ptes))
615 *signature_type = 0x02;
617 if (num > 0 && num <= __le32_to_cpu(gpt->num_partition_entries)) {
619 *start = __le64_to_cpu(p->starting_lba);
620 *size = __le64_to_cpu(p->ending_lba) -
621 __le64_to_cpu(p->starting_lba) + 1;
622 memcpy(signature, &p->unique_partition_guid,
623 sizeof (p->unique_partition_guid));
625 fprintf (stderr,"partition %d is not valid\n", num);
632 * Overrides for Emacs so that we follow Linus's tabbing style.
633 * Emacs will notice this stuff at the end of the file and automatically
634 * adjust the settings for this buffer only. This must remain at the end
636 * ---------------------------------------------------------------------------
639 * c-brace-imaginary-offset: 0
641 * c-argdecl-indent: 4
643 * c-continued-statement-offset: 4
644 * c-continued-brace-offset: 0
645 * indent-tabs-mode: nil