Commit b05ebbbb authored by Davidlohr Bueso's avatar Davidlohr Bueso Committed by Linus Torvalds

partitions/efi: detect hybrid MBRs

One of the biggest problems with GPT is compatibility with older, non-GPT
systems.  The problem is addressed by creating hybrid mbrs, an extension,
or variant, of the traditional protective mbr.  This contains, apart from
the 0xEE partition, up three additional primary partitions that point to
the same space marked by up to three GPT partitions.  The result is that
legacy OSs can see the three required MBR partitions and at the same time
ignore the GPT-aware partitions that protect the GPT structures.

While hybrid MBRs are hacks, workarounds and simply not part of the GPT
standard, they do exist and we have no way around them.  For instance, by
default, OSX creates a hybrid scheme when using multi-OS booting.

In order for Linux to properly discover protective MBRs, it must be made
aware of devices that have hybrid MBRs.  No functionality is changed by
this patch, just a debug message informing the user of the MBR scheme that
is being used.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarDavidlohr Bueso <davidlohr@hp.com>
Reviewed-by: default avatarKarel Zak <kzak@redhat.com>
Acked-by: default avatarMatt Fleming <matt.fleming@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 3e69ac34
...@@ -158,7 +158,7 @@ static inline int pmbr_part_valid(gpt_mbr_record *part) ...@@ -158,7 +158,7 @@ static inline int pmbr_part_valid(gpt_mbr_record *part)
if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
goto invalid; goto invalid;
return 1; return GPT_MBR_PROTECTIVE;
invalid: invalid:
return 0; return 0;
} }
...@@ -167,21 +167,48 @@ static inline int pmbr_part_valid(gpt_mbr_record *part) ...@@ -167,21 +167,48 @@ static inline int pmbr_part_valid(gpt_mbr_record *part)
* is_pmbr_valid(): test Protective MBR for validity * is_pmbr_valid(): test Protective MBR for validity
* @mbr: pointer to a legacy mbr structure * @mbr: pointer to a legacy mbr structure
* *
* Description: Returns 1 if PMBR is valid, 0 otherwise. * Description: Checks for a valid protective or hybrid
* Validity depends on two things: * master boot record (MBR). The validity of a pMBR depends
* on all of the following properties:
* 1) MSDOS signature is in the last two bytes of the MBR * 1) MSDOS signature is in the last two bytes of the MBR
* 2) One partition of type 0xEE is found * 2) One partition of type 0xEE is found
*
* In addition, a hybrid MBR will have up to three additional
* primary partitions, which point to the same space that's
* marked out by up to three GPT partitions.
*
* Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or
* GPT_MBR_HYBRID depending on the device layout.
*/ */
static int static int is_pmbr_valid(legacy_mbr *mbr)
is_pmbr_valid(legacy_mbr *mbr)
{ {
int i; int i, ret = 0; /* invalid by default */
if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
return 0; goto done;
for (i = 0; i < 4; i++) {
ret = pmbr_part_valid(&mbr->partition_record[i]);
if (ret == GPT_MBR_PROTECTIVE) {
/*
* Ok, we at least know that there's a protective MBR,
* now check if there are other partition types for
* hybrid MBR.
*/
goto check_hybrid;
}
}
if (ret != GPT_MBR_PROTECTIVE)
goto done;
check_hybrid:
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
if (pmbr_part_valid(&mbr->partition_record[i])) if ((mbr->partition_record[i].os_type !=
return 1; EFI_PMBR_OSTYPE_EFI_GPT) &&
return 0; (mbr->partition_record[i].os_type != 0x00))
ret = GPT_MBR_HYBRID;
done:
return ret;
} }
/** /**
...@@ -549,15 +576,20 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, ...@@ -549,15 +576,20 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
lastlba = last_lba(state->bdev); lastlba = last_lba(state->bdev);
if (!force_gpt) { if (!force_gpt) {
/* This will be added to the EFI Spec. per Intel after v1.02. */ /* This will be added to the EFI Spec. per Intel after v1.02. */
legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL); legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL);
if (legacymbr) { if (!legacymbr)
read_lba(state, 0, (u8 *) legacymbr, goto fail;
sizeof (*legacymbr));
read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr));
good_pmbr = is_pmbr_valid(legacymbr); good_pmbr = is_pmbr_valid(legacymbr);
kfree(legacymbr); kfree(legacymbr);
}
if (!good_pmbr) if (!good_pmbr)
goto fail; goto fail;
pr_debug("Device has a %s MBR\n",
good_pmbr == GPT_MBR_PROTECTIVE ?
"protective" : "hybrid");
} }
good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
#define EFI_PMBR_OSTYPE_EFI 0xEF #define EFI_PMBR_OSTYPE_EFI 0xEF
#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
#define GPT_MBR_PROTECTIVE 1
#define GPT_MBR_HYBRID 2
#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
#define GPT_HEADER_REVISION_V1 0x00010000 #define GPT_HEADER_REVISION_V1 0x00010000
#define GPT_PRIMARY_PARTITION_TABLE_LBA 1 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment