* Per Intel EFI Specification v1.02
* http://developer.intel.com/technology/efi/efi.htm
* efi.[ch] by Matt Domsch <Matt_Domsch@dell.com>
- * Copyright 2000,2001,2002,2004 Dell Inc.
+ * Copyright 2000,2001,2002 Dell Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* TODO:
*
* Changelog:
- * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
- * - test for valid PMBR and valid PGPT before ever reading
- * AGPT, allow override with 'gpt' kernel command line option.
- * - check for first/last_usable_lba outside of size of disk
- *
* Tue Mar 26 2002 Matt Domsch <Matt_Domsch@dell.com>
* - Ported to 2.5.7-pre1 and 2.5.7-dj2
* - Applied patch to avoid fault in alternate header handling
return (crc32(~0L, buf, len) ^ ~0L);
}
+/**
+ * is_pmbr_valid(): test Protective MBR for validity
+ * @mbr: pointer to a legacy mbr structure
+ *
+ * Description: 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
+ */
+static int
+is_pmbr_valid(legacy_mbr *mbr)
+{
+ int i, found = 0, signature = 0;
+ if (!mbr)
+ return 0;
+ signature = (le16_to_cpu(mbr->signature) == MSDOS_MBR_SIGNATURE);
+ for (i = 0; signature && i < 4; i++) {
+ if (mbr->partition_record[i].sys_ind ==
+ EFI_PMBR_OSTYPE_EFI_GPT) {
+ found = 1;
+ break;
+ }
+ }
+ return (signature && found);
+}
+
/**
* last_lba(): return number of last logical block of device
* @bdev: block device
static u64
last_lba(struct block_device *bdev)
{
- if (!bdev || !bdev->bd_inode)
- return 0;
- return (bdev->bd_inode->i_size >> 9) - 1ULL;
-}
-
-static inline int
-pmbr_part_valid(struct partition *part, u64 lastlba)
-{
- if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
- le32_to_cpu(part->start_sect) == 1UL)
- return 1;
- return 0;
-}
-
-/**
- * is_pmbr_valid(): test Protective MBR for validity
- * @mbr: pointer to a legacy mbr structure
- * @lastlba: last_lba for the whole device
- *
- * Description: 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
- */
-static int
-is_pmbr_valid(legacy_mbr *mbr, u64 lastlba)
-{
- int i;
- if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
- return 0;
- for (i = 0; i < 4; i++)
- if (pmbr_part_valid(&mbr->partition_record[i], lastlba))
- return 1;
- return 0;
+ return (bdev->bd_inode->i_size >> 9) - 1;
}
/**
{
size_t totalreadcount = 0;
- if (!bdev || !buffer || lba > last_lba(bdev))
- return 0;
+ if (!bdev || !buffer)
+ return 0;
while (count) {
int copied = 512;
return totalreadcount;
}
+
/**
* alloc_read_gpt_entries(): reads partition entries from disk
* @bdev
gpt_header **gpt, gpt_entry **ptes)
{
u32 crc, origcrc;
- u64 lastlba;
if (!bdev || !gpt || !ptes)
return 0;
"%lld != %lld\n",
(unsigned long long)le64_to_cpu((*gpt)->signature),
(unsigned long long)GPT_HEADER_SIGNATURE);
- goto fail;
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
}
/* Check the GUID Partition Table CRC */
Dprintk
("GUID Partition Table Header CRC is wrong: %x != %x\n",
crc, origcrc);
- goto fail;
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
}
(*gpt)->header_crc32 = cpu_to_le32(origcrc);
Dprintk("GPT my_lba incorrect: %lld != %lld\n",
(unsigned long long)le64_to_cpu((*gpt)->my_lba),
(unsigned long long)lba);
- goto fail;
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
}
- /* Check the first_usable_lba and last_usable_lba are
- * within the disk.
- */
- lastlba = last_lba(bdev);
- if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) {
- Dprintk("GPT: first_usable_lba incorrect: %lld > %lld\n",
- (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba),
- (unsigned long long)lastlba);
- goto fail;
- }
- if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) {
- Dprintk("GPT: last_usable_lba incorrect: %lld > %lld\n",
- (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
- (unsigned long long)lastlba);
- goto fail;
+ if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt))) {
+ kfree(*gpt);
+ *gpt = NULL;
+ return 0;
}
- if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt)))
- goto fail;
-
/* Check the GUID Partition Entry Array CRC */
crc = efi_crc32((const unsigned char *) (*ptes),
le32_to_cpu((*gpt)->num_partition_entries) *
if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) {
Dprintk("GUID Partitition Entry Array CRC check failed.\n");
- goto fail_ptes;
+ kfree(*gpt);
+ *gpt = NULL;
+ kfree(*ptes);
+ *ptes = NULL;
+ return 0;
}
/* We're done, all's well */
return 1;
-
- fail_ptes:
- kfree(*ptes);
- *ptes = NULL;
- fail:
- kfree(*gpt);
- *gpt = NULL;
- return 0;
-}
-
-/**
- * is_pte_valid() - tests one PTE for validity
- * @pte is the pte to check
- * @lastlba is last lba of the disk
- *
- * Description: returns 1 if valid, 0 on error.
- */
-static inline int
-is_pte_valid(const gpt_entry *pte, const u64 lastlba)
-{
- if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) ||
- le64_to_cpu(pte->starting_lba) > lastlba ||
- le64_to_cpu(pte->ending_lba) > lastlba)
- return 0;
- return 1;
}
/**
* @ptes is a PTEs ptr, filled on return.
* Description: Returns 1 if valid, 0 on error.
* If valid, returns pointers to newly allocated GPT header and PTEs.
- * Validity depends on PMBR being valid (or being overridden by the
- * 'gpt' kernel command line option) and finding either the Primary
- * GPT header and PTEs valid, or the Alternate GPT header and PTEs
- * valid. If the Primary GPT header is not valid, the Alternate GPT header
- * is not checked unless the 'gpt' kernel command line option is passed.
- * This protects against devices which misreport their size, and forces
- * the user to decide to use the Alternate GPT.
+ * Validity depends on finding either the Primary GPT header and PTEs valid,
+ * or the Alternate GPT header and PTEs valid, and the PMBR valid.
*/
static int
find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
return 0;
lastlba = last_lba(bdev);
- if (!force_gpt) {
- /* This will be added to the EFI Spec. per Intel after v1.02. */
- legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
- if (legacymbr) {
- memset(legacymbr, 0, sizeof (*legacymbr));
- read_lba(bdev, 0, (u8 *) legacymbr,
- sizeof (*legacymbr));
- good_pmbr = is_pmbr_valid(legacymbr, lastlba);
- kfree(legacymbr);
- legacymbr=NULL;
- }
- if (!good_pmbr)
- goto fail;
- }
-
good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA,
&pgpt, &pptes);
- if (good_pgpt)
+ if (good_pgpt) {
good_agpt = is_gpt_valid(bdev,
- le64_to_cpu(pgpt->alternate_lba),
+ le64_to_cpu(pgpt->alternate_lba),
&agpt, &aptes);
- if (!good_agpt && force_gpt)
+ if (!good_agpt) {
+ good_agpt = is_gpt_valid(bdev, lastlba,
+ &agpt, &aptes);
+ }
+ }
+ else {
good_agpt = is_gpt_valid(bdev, lastlba,
&agpt, &aptes);
+ }
/* The obviously unsuccessful case */
- if (!good_pgpt && !good_agpt)
+ if (!good_pgpt && !good_agpt) {
+ goto fail;
+ }
+
+ /* This will be added to the EFI Spec. per Intel after v1.02. */
+ legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+ if (legacymbr) {
+ memset(legacymbr, 0, sizeof (*legacymbr));
+ read_lba(bdev, 0, (u8 *) legacymbr,
+ sizeof (*legacymbr));
+ good_pmbr = is_pmbr_valid(legacymbr);
+ kfree(legacymbr);
+ legacymbr=NULL;
+ }
+
+ /* Failure due to bad PMBR */
+ if ((good_pgpt || good_agpt) && !good_pmbr && !force_gpt) {
+ printk(KERN_WARNING
+ " Warning: Disk has a valid GPT signature "
+ "but invalid PMBR.\n");
+ printk(KERN_WARNING
+ " Assuming this disk is *not* a GPT disk anymore.\n");
+ printk(KERN_WARNING
+ " Use gpt kernel option to override. "
+ "Use GNU Parted to correct disk.\n");
goto fail;
+ }
+
+ /* Would fail due to bad PMBR, but force GPT anyhow */
+ if ((good_pgpt || good_agpt) && !good_pmbr && force_gpt) {
+ printk(KERN_WARNING
+ " Warning: Disk has a valid GPT signature but "
+ "invalid PMBR.\n");
+ printk(KERN_WARNING
+ " Use GNU Parted to correct disk.\n");
+ printk(KERN_WARNING
+ " gpt option taken, disk treated as GPT.\n");
+ }
compare_gpts(pgpt, agpt, lastlba);
/* The good cases */
- if (good_pgpt) {
+ if (good_pgpt && (good_pmbr || force_gpt)) {
*gpt = pgpt;
*ptes = pptes;
- kfree(agpt);
- kfree(aptes);
+ if (agpt) { kfree(agpt); agpt = NULL; }
+ if (aptes) { kfree(aptes); aptes = NULL; }
if (!good_agpt) {
printk(KERN_WARNING
"Alternate GPT is invalid, "
}
return 1;
}
- else if (good_agpt) {
+ else if (good_agpt && (good_pmbr || force_gpt)) {
*gpt = agpt;
*ptes = aptes;
- kfree(pgpt);
- kfree(pptes);
+ if (pgpt) { kfree(pgpt); pgpt = NULL; }
+ if (pptes) { kfree(pptes); pptes = NULL; }
printk(KERN_WARNING
"Primary GPT is invalid, using alternate GPT.\n");
return 1;
}
fail:
- kfree(pgpt);
- kfree(agpt);
- kfree(pptes);
- kfree(aptes);
+ if (pgpt) { kfree(pgpt); pgpt=NULL; }
+ if (agpt) { kfree(agpt); agpt=NULL; }
+ if (pptes) { kfree(pptes); pptes=NULL; }
+ if (aptes) { kfree(aptes); aptes=NULL; }
*gpt = NULL;
*ptes = NULL;
return 0;
Dprintk("GUID Partition Table is valid! Yea!\n");
for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) {
- if (!is_pte_valid(&ptes[i], last_lba(bdev)))
+ if (!efi_guidcmp(ptes[i].partition_type_guid, NULL_GUID))
continue;
put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba),
(le64_to_cpu(ptes[i].ending_lba) -
le64_to_cpu(ptes[i].starting_lba) +
- 1ULL));
+ 1));
- /* If this is a RAID volume, tell md */
+ /* If there's this is a RAID volume, tell md */
if (!efi_guidcmp(ptes[i].partition_type_guid,
PARTITION_LINUX_RAID_GUID))
state->parts[i+1].flags = 1;
printk("\n");
return 1;
}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */