[syslinux] [PATCH 16/28] com32/chain: implement handling of non-standard hybrid GPT+MBR layouts

Michal Soltys soltys at ziu.info
Tue Jan 29 06:06:03 PST 2013


We also take a bit relaxed approach - so we check for presence of 0xEE
at any place, then attempt to read GPT header only if prefmbr is not
set.

Signed-off-by: Michal Soltys <soltys at ziu.info>
---
 com32/chain/chain.c    |   10 +++++-----
 com32/chain/mangle.c   |    4 ++--
 com32/chain/options.c  |    5 +++++
 com32/chain/options.h  |   15 ++++++++-------
 com32/chain/partiter.c |    7 +++++--
 com32/chain/partiter.h |    5 +++--
 doc/chain.txt          |    6 ++++++
 7 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index f1120d9..d6eab7c 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -72,7 +72,7 @@ static int find_by_sig(uint32_t mbr_sig,
     for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
 	if (disk_get_params(drive, &diskinfo))
 	    continue;		/* Drive doesn't exist */
-	if (!(boot_part = pi_begin(&diskinfo, opt.relax)))
+	if (!(boot_part = pi_begin(&diskinfo, opt.relax | opt.prefmbr)))
 	    continue;
 	/* Check for a MBR disk */
 	if (boot_part->type != typedos) {
@@ -103,7 +103,7 @@ static int find_by_guid(const struct guid *gpt_guid,
     for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
 	if (disk_get_params(drive, &diskinfo))
 	    continue;		/* Drive doesn't exist */
-	if (!(boot_part = pi_begin(&diskinfo, opt.relax)))
+	if (!(boot_part = pi_begin(&diskinfo, opt.relax | opt.prefmbr)))
 	    continue;
 	/* Check for a GPT disk */
 	if (boot_part->type != typegpt) {
@@ -135,7 +135,7 @@ static int find_by_label(const char *label, struct part_iter **_boot_part)
     for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
 	if (disk_get_params(drive, &diskinfo))
 	    continue;		/* Drive doesn't exist */
-	if (!(boot_part = pi_begin(&diskinfo, opt.relax)))
+	if (!(boot_part = pi_begin(&diskinfo, opt.relax | opt.prefmbr)))
 	    continue;
 	/* Check for a GPT disk */
 	if (!(boot_part->type == typegpt)) {
@@ -324,7 +324,7 @@ int find_dp(struct part_iter **_iter)
 	if (disk_get_params(drive, &diskinfo))
 	    goto bail;
 	/* this will start iteration over FDD, possibly raw */
-	if (!(iter = pi_begin(&diskinfo, opt.relax)))
+	if (!(iter = pi_begin(&diskinfo, opt.relax | opt.prefmbr)))
 	    goto bail;
 
     } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
@@ -344,7 +344,7 @@ int find_dp(struct part_iter **_iter)
 	if (disk_get_params(drive, &diskinfo))
 	    goto bail;
 	/* this will start iteration over disk emulation, possibly raw */
-	if (!(iter = pi_begin(&diskinfo, opt.relax)))
+	if (!(iter = pi_begin(&diskinfo, opt.relax | opt.prefmbr)))
 	    goto bail;
 
 	/* 'fs' => we should lookup the syslinux partition number and use it */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index 252128d..94e6e90 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -537,7 +537,7 @@ int manglepe_hide(struct part_iter *miter)
     if (miter->index > 4 && !(opt.hide & HIDE_EXT))
 	warn("Specified partition is logical, so it can't be unhidden without 'unhideall'.");
 
-    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.relax)))
+    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.relax | opt.prefmbr)))
 	return -1;
 
     while (!pi_next(iter) && !werr) {
@@ -611,7 +611,7 @@ int manglepe_fixchs(struct part_iter *miter)
 	return -1;
     }
 
-    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.relax)))
+    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.relax | opt.prefmbr)))
 	return -1;
 
     while (!pi_next(iter) && !werr) {
diff --git a/com32/chain/options.c b/com32/chain/options.c
index 209ad01..4044520 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -125,6 +125,7 @@ static void usage(void)
 "  warn                 Wait for a keypress to continue chainloading",
 "  break                Don't chainload",
 "  relax                Relax sanity checks",
+"  prefmbr              On hybrid MBR/GPT disks, prefer legacy layout",
 "",
 "  file=<file>          Load and execute <file>",
 "  seg=<s[:o[:i]]>      Load file at <s:o>, jump to <s:i>",
@@ -334,6 +335,10 @@ int opt_parse_args(int argc, char *argv[])
 	    opt.warn = true;
 	} else if (!strcmp(argv[i], "nowarn")) {
 	    opt.warn = false;
+	} else if (!strcmp(argv[i], "prefmbr")) {
+	    opt.prefmbr = PIF_PREFMBR;
+	} else if (!strcmp(argv[i], "noprefmbr")) {
+	    opt.prefmbr = 0;
 	} else if (!strcmp(argv[i], "nobreak")) {
 	    opt.brkchain = false;
 	} else if (!strcmp(argv[i], "break")) {
diff --git a/com32/chain/options.h b/com32/chain/options.h
index ac8f356..5ae4109 100644
--- a/com32/chain/options.h
+++ b/com32/chain/options.h
@@ -37,16 +37,20 @@
 enum {HIDE_OFF = 0, HIDE_ON = 1, HIDE_EXT = 2, HIDE_REV = 4};
 
 struct options {
+    const char *drivename;
+    const char *partition;
+    const char *file;
+    const char *grubcfg;
     unsigned int fseg;
     unsigned int foff;
     unsigned int fip;
     unsigned int sseg;
     unsigned int soff;
     unsigned int sip;
-    const char *drivename;
-    const char *partition;
-    const char *file;
-    const char *grubcfg;
+    int hide;
+    int relax;
+    int prefmbr;
+    uint16_t keeppxe;
     bool isolinux;
     bool cmldr;
     bool drmk;
@@ -56,7 +60,6 @@ struct options {
     bool hand;
     bool hptr;
     bool swap;
-    int hide;
     bool sect;
     bool save;
     bool bss;
@@ -64,9 +67,7 @@ struct options {
     bool filebpb;
     bool fixchs;
     bool warn;
-    int relax;
     bool brkchain;
-    uint16_t keeppxe;
     struct syslinux_rm_regs regs;
 };
 
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
index 967769f..3c7670d 100644
--- a/com32/chain/partiter.c
+++ b/com32/chain/partiter.c
@@ -549,7 +549,7 @@ void pi_del(struct part_iter **_iter)
 /* pi_begin() - validate and and get proper iterator for a disk described by di */
 struct part_iter *pi_begin(const struct disk_info *di, int flags)
 {
-    int ret = -1;
+    int gptprot, ret = -1;
     struct part_iter *iter;
     struct disk_dos_mbr *mbr = NULL;
     struct disk_gpt_header *gpth = NULL;
@@ -574,7 +574,10 @@ struct part_iter *pi_begin(const struct disk_info *di, int flags)
     }
 
     /* Check for GPT protective MBR */
-    if (mbr->table[0].ostype == 0xEE) {
+    gptprot = 0;
+    for (size_t i = 0; i < 4; i++)
+	gptprot |= (mbr->table[i].ostype == 0xEE);
+    if (gptprot && !(flags & PIF_PREFMBR)) {
 	if (!(gpth = disk_read_sectors(di, 1, 1))) {
 	    error("Couldn't read potential GPT header.");
 	    goto bail;
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
index a737584..4004ef9 100644
--- a/com32/chain/partiter.h
+++ b/com32/chain/partiter.h
@@ -46,8 +46,9 @@ enum {PI_OK, PI_DONE, PI_INSANE, PI_ERRLOAD};
 
 /* flags */
 
-#define PIF_STEPALL 0x01
-#define PIF_RELAX   0x02
+#define PIF_STEPALL 0b001
+#define PIF_RELAX   0b010
+#define PIF_PREFMBR 0b100
 
 struct itertype;
 struct part_iter;
diff --git a/doc/chain.txt b/doc/chain.txt
index d3c012c..2321c10 100644
--- a/doc/chain.txt
+++ b/doc/chain.txt
@@ -226,6 +226,12 @@ stacks in memory (pxelinux only).
 This option will wait for a keypress right before continuing the chainloading.
 Useful to see warnings emited by the chain module.
 
+	prefmbr
+	*noprefmbr
+
+In the case of presence of non-standard hybrid MBR/GPT layout, this flag makes
+chain module prefer MBR layout over GPT.
+
 	relax
 	*norelax
 
-- 
1.7.10.4



More information about the Syslinux mailing list