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
40 static inline uint32_t
41 efi_crc32(const void *buf, unsigned long len)
43 return (crc32(~0L, buf, len) ^ ~0L);
47 * is_pmbr_valid(): test Protective MBR for validity
48 * @mbr: pointer to a legacy mbr structure
50 * Description: Returns 1 if PMBR is valid, 0 otherwise.
51 * Validity depends on two things:
52 * 1) MSDOS signature is in the last two bytes of the MBR
53 * 2) One partition of type 0xEE is found
56 is_pmbr_valid(legacy_mbr *mbr)
58 int i, found = 0, signature = 0;
61 signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
62 for (i = 0; signature && i < 4; i++) {
63 if (mbr->partition[i].sys_type ==
64 EFI_PMBR_OSTYPE_EFI_GPT) {
69 return (signature && found);
73 get_sector_size (int fd)
77 if (blkdev_get_sector_size(fd, §or_size) == -1)
78 return DEFAULT_SECTOR_SIZE;
83 get_num_sectors(int fd)
85 unsigned long long bytes=0;
87 if (blkdev_get_size(fd, &bytes) == -1)
89 return bytes / get_sector_size(fd);
98 memset(&s, 0, sizeof (s));
99 rc = fstat(filedes, &s);
101 fprintf(stderr, "last_lba() could not stat: %s\n",
106 if (S_ISBLK(s.st_mode)) {
107 sectors = get_num_sectors(filedes);
110 "last_lba(): I don't know how to handle files with mode %x\n",
119 read_lba(int fd, uint64_t lba, void *buffer, size_t bytes)
121 int sector_size = get_sector_size(fd);
122 off_t offset = lba * sector_size;
124 lseek(fd, offset, SEEK_SET);
125 return read(fd, buffer, bytes);
129 * alloc_read_gpt_entries(): reads partition entries from disk
130 * @fd is an open file descriptor to the whole disk
131 * @gpt is a buffer into which the GPT will be put
132 * Description: Returns ptes on success, NULL on error.
133 * Allocates space for PTEs based on information found in @gpt.
134 * Notes: remember to free pte when you're done!
137 alloc_read_gpt_entries(int fd, gpt_header * gpt)
140 size_t count = le32_to_cpu(gpt->num_partition_entries) *
141 le32_to_cpu(gpt->sizeof_partition_entry);
143 if (!count) return NULL;
145 pte = (gpt_entry *)malloc(count);
148 memset(pte, 0, count);
150 if (!read_lba(fd, le64_to_cpu(gpt->partition_entry_lba), pte,
159 * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk
160 * @fd is an open file descriptor to the whole disk
161 * @lba is the Logical Block Address of the partition table
163 * Description: returns GPT header on success, NULL on error. Allocates
164 * and fills a GPT header starting at @ from @bdev.
165 * Note: remember to free gpt when finished with it.
168 alloc_read_gpt_header(int fd, uint64_t lba)
172 malloc(sizeof (gpt_header));
175 memset(gpt, 0, sizeof (*gpt));
176 if (!read_lba(fd, lba, gpt, sizeof (gpt_header))) {
185 * is_gpt_valid() - tests one GPT header and PTEs for validity
186 * @fd is an open file descriptor to the whole disk
187 * @lba is the logical block address of the GPT header to test
188 * @gpt is a GPT header ptr, filled on return.
189 * @ptes is a PTEs ptr, filled on return.
191 * Description: returns 1 if valid, 0 on error.
192 * If valid, returns pointers to newly allocated GPT header and PTEs.
195 is_gpt_valid(int fd, uint64_t lba,
196 gpt_header ** gpt, gpt_entry ** ptes)
198 int rc = 0; /* default to not valid */
199 uint32_t crc, origcrc;
203 if (!(*gpt = alloc_read_gpt_header(fd, lba)))
206 /* Check the GUID Partition Table signature */
207 if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) {
209 printf("GUID Partition Table Header signature is wrong: %" PRIx64" != %" PRIx64 "\n",
210 le64_to_cpu((*gpt)->signature), GUID_PT_HEADER_SIGNATURE);
217 /* Check the GUID Partition Table Header CRC */
218 origcrc = le32_to_cpu((*gpt)->header_crc32);
219 (*gpt)->header_crc32 = 0;
220 crc = efi_crc32(*gpt, le32_to_cpu((*gpt)->header_size));
221 if (crc != origcrc) {
222 /* printf( "GPTH CRC check failed, %x != %x.\n", origcrc, crc); */
223 (*gpt)->header_crc32 = cpu_to_le32(origcrc);
228 (*gpt)->header_crc32 = cpu_to_le32(origcrc);
230 /* Check that the my_lba entry points to the LBA
231 * that contains the GPT we read */
232 if (le64_to_cpu((*gpt)->my_lba) != lba) {
233 /* printf( "my_lba % PRIx64 "x != lba %"PRIx64 "x.\n", le64_to_cpu((*gpt)->my_lba), lba); */
239 if (!(*ptes = alloc_read_gpt_entries(fd, *gpt))) {
245 /* Check the GUID Partition Entry Array CRC */
246 crc = efi_crc32(*ptes,
247 le32_to_cpu((*gpt)->num_partition_entries) *
248 le32_to_cpu((*gpt)->sizeof_partition_entry));
249 if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
250 /* printf("GUID Partitition Entry Array CRC check failed.\n"); */
258 /* We're done, all's well */
262 * compare_gpts() - Search disk for valid GPT headers and PTEs
263 * @pgpt is the primary GPT header
264 * @agpt is the alternate GPT header
265 * @lastlba is the last LBA number
266 * Description: Returns nothing. Sanity checks pgpt and agpt fields
267 * and prints warnings on discrepancies.
271 compare_gpts(gpt_header *pgpt, gpt_header *agpt, uint64_t lastlba)
276 if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
278 "GPT:Primary header LBA != Alt. header alternate_lba\n");
279 fprintf(stderr, "GPT:%" PRIx64 "x != %" PRIx64 "x\n",
280 le64_to_cpu(pgpt->my_lba),
281 le64_to_cpu(agpt->alternate_lba));
284 if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
286 "GPT:Primary header alternate_lba != Alt. header my_lba\n");
287 fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
288 le64_to_cpu(pgpt->alternate_lba),
289 le64_to_cpu(agpt->my_lba));
292 if (le64_to_cpu(pgpt->first_usable_lba) !=
293 le64_to_cpu(agpt->first_usable_lba)) {
294 fprintf(stderr, "GPT:first_usable_lbas don't match.\n");
295 fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
296 le64_to_cpu(pgpt->first_usable_lba),
297 le64_to_cpu(agpt->first_usable_lba));
300 if (le64_to_cpu(pgpt->last_usable_lba) !=
301 le64_to_cpu(agpt->last_usable_lba)) {
302 fprintf(stderr, "GPT:last_usable_lbas don't match.\n");
303 fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
304 le64_to_cpu(pgpt->last_usable_lba),
305 le64_to_cpu(agpt->last_usable_lba));
308 if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
309 fprintf(stderr, "GPT:disk_guids don't match.\n");
312 if (le32_to_cpu(pgpt->num_partition_entries) !=
313 le32_to_cpu(agpt->num_partition_entries)) {
314 fprintf(stderr, "GPT:num_partition_entries don't match: "
316 le32_to_cpu(pgpt->num_partition_entries),
317 le32_to_cpu(agpt->num_partition_entries));
320 if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
321 le32_to_cpu(agpt->sizeof_partition_entry)) {
323 "GPT:sizeof_partition_entry values don't match: "
325 le32_to_cpu(pgpt->sizeof_partition_entry),
326 le32_to_cpu(agpt->sizeof_partition_entry));
329 if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
330 le32_to_cpu(agpt->partition_entry_array_crc32)) {
332 "GPT:partition_entry_array_crc32 values don't match: "
334 le32_to_cpu(pgpt->partition_entry_array_crc32),
335 le32_to_cpu(agpt->partition_entry_array_crc32));
338 if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
340 "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
341 fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
342 le64_to_cpu(pgpt->alternate_lba), lastlba);
346 if (le64_to_cpu(agpt->my_lba) != lastlba) {
348 "GPT:Alternate GPT header not at the end of the disk.\n");
349 fprintf(stderr, "GPT:%" PRIx64 " != %" PRIx64 "\n",
350 le64_to_cpu(agpt->my_lba), lastlba);
356 "GPT: Use GNU Parted to correct GPT errors.\n");
361 * find_valid_gpt() - Search disk for valid GPT headers and PTEs
362 * @fd is an open file descriptor to the whole disk
363 * @gpt is a GPT header ptr, filled on return.
364 * @ptes is a PTEs ptr, filled on return.
365 * Description: Returns 1 if valid, 0 on error.
366 * If valid, returns pointers to newly allocated GPT header and PTEs.
367 * Validity depends on finding either the Primary GPT header and PTEs valid,
368 * or the Alternate GPT header and PTEs valid, and the PMBR valid.
371 find_valid_gpt(int fd, gpt_header ** gpt, gpt_entry ** ptes)
373 extern int force_gpt;
374 int good_pgpt = 0, good_agpt = 0, good_pmbr = 0;
375 gpt_header *pgpt = NULL, *agpt = NULL;
376 gpt_entry *pptes = NULL, *aptes = NULL;
377 legacy_mbr *legacymbr = NULL;
382 lastlba = last_lba(fd);
383 good_pgpt = is_gpt_valid(fd, GPT_PRIMARY_PARTITION_TABLE_LBA,
386 good_agpt = is_gpt_valid(fd,
387 le64_to_cpu(pgpt->alternate_lba),
390 good_agpt = is_gpt_valid(fd, lastlba,
395 good_agpt = is_gpt_valid(fd, lastlba,
399 /* The obviously unsuccessful case */
400 if (!good_pgpt && !good_agpt) {
404 /* This will be added to the EFI Spec. per Intel after v1.02. */
405 legacymbr = malloc(sizeof (*legacymbr));
407 memset(legacymbr, 0, sizeof (*legacymbr));
408 read_lba(fd, 0, (uint8_t *) legacymbr,
409 sizeof (*legacymbr));
410 good_pmbr = is_pmbr_valid(legacymbr);
415 /* Failure due to bad PMBR */
416 if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
418 " Warning: Disk has a valid GPT signature "
419 "but invalid PMBR.\n"
420 " Assuming this disk is *not* a GPT disk anymore.\n"
421 " Use gpt kernel option to override. "
422 "Use GNU Parted to correct disk.\n");
426 /* Would fail due to bad PMBR, but force GPT anyhow */
427 if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
429 " Warning: Disk has a valid GPT signature but "
431 " Use GNU Parted to correct disk.\n"
432 " gpt option taken, disk treated as GPT.\n");
435 compare_gpts(pgpt, agpt, lastlba);
438 if (good_pgpt && (good_pmbr || force_gpt)) {
441 if (agpt) { free(agpt); agpt = NULL; }
442 if (aptes) { free(aptes); aptes = NULL; }
445 "Alternate GPT is invalid, "
446 "using primary GPT.\n");
450 else if (good_agpt && (good_pmbr || force_gpt)) {
453 if (pgpt) { free(pgpt); pgpt = NULL; }
454 if (pptes) { free(pptes); pptes = NULL; }
456 "Primary GPT is invalid, using alternate GPT.\n");
461 if (pgpt) { free(pgpt); pgpt=NULL; }
462 if (agpt) { free(agpt); agpt=NULL; }
463 if (pptes) { free(pptes); pptes=NULL; }
464 if (aptes) { free(aptes); aptes=NULL; }
473 * @all - slice with start/size of whole disk
475 * 0 if this isn't our partition table
476 * number of partitions if successful
480 read_gpt_pt (int fd, struct slice all, struct slice *sp, int ns)
482 gpt_header *gpt = NULL;
483 gpt_entry *ptes = NULL;
486 int last_used_index=-1;
488 if (!find_valid_gpt (fd, &gpt, &ptes) || !gpt || !ptes) {
494 for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < ns; i++) {
495 if (!efi_guidcmp (NULL_GUID, ptes[i].partition_type_guid)) {
500 sp[n].start = le64_to_cpu(ptes[i].starting_lba);
501 sp[n].size = le64_to_cpu(ptes[i].ending_lba) -
502 le64_to_cpu(ptes[i].starting_lba) + 1;
509 return last_used_index+1;