[syslinux] [PATCH] chain.c32: support chainloading GRUB2 core.img

Gert Hulselmans gerth at zytor.com
Tue Dec 21 13:07:47 PST 2010


Gert Hulselmans wrote:
> Here is a patch that makes it possible to chainload GRUB2 core.img form
> chain.c32.
>
> It reuses the grub= parameter (used for chainloading GRUB Legacy stage2):
> - both loaded at 0x8000
> - start execution at offset 0x200 (0x8200 in memory)
>
> GRUB2 allows to specify another "GRUB home dir" than the standard
> /boot/grub
> GRUB2 doesn't allow to change the configfile 'grub.cfg' name itself (I
> can't find it uncompressed).
>
> Usage with GRUB2: chain.c32 grub=/boot/grub2/core.img grub2dir=/boot/grub2
> hd1,6
>
> Usage with GRUB Legacy: chain.c32 grub=/boot/grub/stage2
> grubcfg=/boot/grub/grub.lst hd0,2
>
> Remarks are welcome.
> Testers too.
>
> diff is also attached.
>
> - Gert Hulselmans
>

Here is a new patch. Some additional fields are added to the grub2 struct.

The file kern/i386/ps/startup.S of GRUB2 (v1.98) seems to contain more
info that the source files I investigated yesterday. ATM we don't use
those additional fields (compat_version fields and additional
multiboot_header fields).

Would it be advised to check core.img for the compat_version fields too,
like we do for GRUB Legacy, instead of looking only for the multiboot
magic?

Values for GRUB2:
 - compat_version_major = 4
 - compat_version_minor = 0

I also tested that loading of GRUB Legacy still works with this patch
(didn't do that yesterday).

- Gert Hulselmans


diff -urp syslinux-4.03/com32/modules/chain.c
syslinux-4.03-chain-grub2/com32/modules/chain.c
--- syslinux-4.03/com32/modules/chain.c	2010-10-20 21:25:38.000000000 +0200
+++ syslinux-4.03-chain-grub2/com32/modules/chain.c	2010-12-21
20:18:28.947116001 +0100
@@ -82,10 +82,14 @@
  *
  * grub=<loader>
  *	same as seg=0x800 file=<loader> & jumping to seg 0x820,
- *	used with GRUB Legacy stage2 files.
+ *	used with GRUB Legacy stage2 files and GRUB2 core.img files.
  *
  * grubcfg=<filename>
- *	set an alternative config filename in stage2 of Grub Legacy,
+ *	set an alternative config filename in stage2 of GRUB Legacy.
+ *	only applicable in combination with "grub=<loader>".
+ *
+ * grub2dir=<dirname>
+ *	set an alternative directory name in core.img of GRUB2.
  *	only applicable in combination with "grub=<loader>".
  *
  * grldr=<loader>
@@ -134,6 +138,7 @@ static struct options {
     bool grub;
     bool grldr;
     const char *grubcfg;
+    const char *grub2dir;
     bool swap;
     bool hide;
     bool sethidden;
@@ -1283,8 +1288,9 @@ Options: file=<loader>      Load and exe
          msdos=<loader>     Load MS-DOS IO.SYS\n\
          pcdos=<loader>     Load PC-DOS IBMBIO.COM\n\
          drmk=<loader>      Load DRMK DELLBIO.BIN\n\
-         grub=<loader>      Load GRUB Legacy stage2\n\
+         grub=<loader>      Load GRUB Legacy stage2 or GRUB2 core.img\n\
          grubcfg=<filename> Set alternative config filename for GRUB
Legacy\n\
+         grub2dir=<dirname> Set alternative directory name for GRUB2\n\
          grldr=<loader>     Load GRUB4DOS grldr\n\
          seg=<segment>      Jump to <seg>:0000, instead of 0000:7C00\n\
          swap               Swap drive numbers, if bootdisk is not
fd0/hd0\n\
@@ -1364,6 +1370,8 @@ int main(int argc, char *argv[])
 	    opt.grub = true;
 	} else if (!strncmp(argv[i], "grubcfg=", 8)) {
 	    opt.grubcfg = argv[i] + 8;
+	} else if (!strncmp(argv[i], "grub2dir=", 9)) {
+	    opt.grub2dir = argv[i] + 9;
 	} else if (!strncmp(argv[i], "grldr=", 6)) {
 	    opt.loadfile = argv[i] + 6;
 	    opt.grldr = true;
@@ -1412,6 +1420,11 @@ int main(int argc, char *argv[])
 	goto bail;
     }

+    if (opt.grub2dir && !opt.grub) {
+	error("grub2dir=<dirname> must be used together with grub=<loader>.\n");
+	goto bail;
+    }
+
     if (opt.seg) {
 	regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg;
     } else {
@@ -1603,16 +1616,16 @@ int main(int argc, char *argv[])
 	}

 	if (opt.grub) {
-	    /* Layout of stage2 file (from byte 0x0 to 0x270) */
+	    /* Layout of stage2 file of GRUB Legacy (from byte 0x0 to 0x270) */
 	    struct grub_stage2_patch_area {
-		/* 0x0 to 0x205 */
+		/* 0x0 - 0x205 */
 		char unknown[0x206];
 		/* 0x206: compatibility version number major */
 		uint8_t compat_version_major;
 		/* 0x207: compatibility version number minor */
 		uint8_t compat_version_minor;

-		/* 0x208: install_partition variable */
+		/* 0x208 - 0x20b: install_partition variable */
 		struct {
 		    /* 0x208: sub-partition in sub-partition part2 */
 		    uint8_t part3;
@@ -1624,83 +1637,161 @@ int main(int argc, char *argv[])
 		    uint8_t drive;
 		} __attribute__ ((packed)) install_partition;

-		/* 0x20c: deprecated (historical reason only) */
+		/* 0x20c - 0x20f: deprecated (historical reason only) */
 		uint32_t saved_entryno;
 		/* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
 		uint8_t stage2_id;
 		/* 0x211: force LBA */
 		uint8_t force_lba;
-		/* 0x212: version string (will probably be 0.97) */
+		/* 0x212 - 0x216: version string (will normally be 0.97) */
 		char version_string[5];
-		/* 0x217: config filename */
+		/* 0x217 - 0x26f: config filename */
 		char config_file[89];
-		/* 0x270: start of code (after jump from 0x200) */
-		char codestart[1];
-	    } __attribute__ ((packed)) *stage2;
+	    } __attribute__ ((packed)) *grub_legacy_stage2;

-	    if (data[ndata].size < sizeof(struct grub_stage2_patch_area)) {
-		error
-		    ("The file specified by grub=<loader> is to small to be stage2 of
GRUB Legacy.\n");
-		goto bail;
-	    }
+	    /* Layout of GRUB2 core.img file (from byte 0x0 to 0x25c) */
+	    struct grub2_core_img_patch_area {
+		/* 0x0 - 0x205 */
+		char unknown[0x206];
+		/* 0x206: compatibility version number major */
+		uint8_t compat_version_major;
+		/* 0x207: compatibility version number minor */
+		uint8_t compat_version_minor;
+		/* 0x208 - 0x20b: GRUB2 total module size */
+		uint32_t grub2_total_module_size;
+		/* 0x20c - 0x20f: GRUB2 kernel image size */
+		uint32_t grub2_kernel_image_size;
+		/* 0x210 - 0x213: GRUB2 compressed size */
+		uint32_t grub2_compressed_size;
+		/* 0x214 - 0x217: msdos partition number  */
+		uint32_t install_dos_part;
+		/* 0x218 - 0x21b: BSD partition number */
+		uint32_t install_bsd_part;
+		/* 0x21c - 0x25b: GRUB2 directory name */
+		char grub2dir[0x40];

-	    stage2 = data[ndata].data;
+		/* 0x25c - 0x267: Multiboot header */
+		struct {
+		    /* 0x25c - 0x25f: magic number = 0x1badb002 */
+		    uint32_t magic;
+		    /* 0x260 - 0x263: flags */
+		    uint32_t flags;
+		    /* 0x264 - 0x267: checksum */
+		    uint32_t checksum;
+		    /* 0x268 - 0x26b: header address */
+		    uint32_t header_addr;
+		    /* 0x26c - 0x26f: load address */
+		    uint32_t load_addr;
+		    /* 0x270 - 0x273: load end address */
+		    uint32_t load_end_addr;
+		    /* 0x274 - 0x277: bss end address */
+		    uint32_t bss_end_addr;
+		    /* 0x278 - 0x27b: entry address */
+		    uint32_t entry_addr;
+		} __attribute__ ((packed)) multiboot_header;
+
+	    } __attribute__ ((packed)) *grub2_core_img;

-	    /*
-	     * Check the compatibility version number to see if we loaded a real
-	     * stage2 file or a stage2 file that we support.
-	     */
-	    if (stage2->compat_version_major != 3
-		|| stage2->compat_version_minor != 2) {
+	    /* check if the loaded file is at least 4 kiB */
+	    if (data[ndata].size < 0x1000) {
 		error
-		    ("The file specified by grub=<loader> is not a supported stage2
GRUB Legacy binary\n");
+		    ("The file specified by grub=<loader> is to small to be stage2 of
GRUB Legacy\nor core.img of GRUB2.\n");
 		goto bail;
 	    }

 	    /* jump 0x200 bytes into the loadfile */
 	    regs.ip = 0x200;

-	    /*
-	     * GRUB Legacy wants the partition number in the install_partition
-	     * variable, located at offset 0x208 of stage2.
-	     * When GRUB Legacy is loaded, it is located at memory address 0x8208.
-	     *
-	     * It looks very similar to the "boot information format" of the
-	     * Multiboot specification:
-	     *  
http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
-	     *
-	     *   0x208 = part3: sub-partition in sub-partition part2
-	     *   0x209 = part2: sub-partition in top-level partition
-	     *   0x20a = part1: top-level partition number
-	     *   0x20b = drive: BIOS drive number (must be 0)
-	     *
-	     * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
-	     * another location.
-	     *
-	     * Partition numbers always start from zero.
-	     * Unused partition bytes must be set to 0xFF.
-	     *
-	     * We only care about top-level partition, so we only need to change
-	     * "part1" to the appropriate value:
-	     *   -1:   whole drive (default) (-1 = 0xFF)
-	     *   0-3:  primary partitions
-	     *   4-*:  logical partitions
-	     */
-	    stage2->install_partition.part1 = whichpart - 1;
-
-	    /*
-	     * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
-	     * config filename. The filename passed via grubcfg= will overwrite
-	     * the default config filename "/boot/grub/menu.lst".
-	     */
-	    if (opt.grubcfg) {
-		if (strlen(opt.grubcfg) > sizeof(stage2->config_file) - 1) {
+	    grub2_core_img = data[ndata].data;
+
+	    /* Do we have core.img of GRUB2 ? */
+	    if (grub2_core_img->multiboot_header.magic == 0x1badb002) {
+		/* Check multiboot header: sum must be zero (32-bit unsigned)  */
+		if ((uint32_t) (grub2_core_img->multiboot_header.magic
+		    + grub2_core_img->multiboot_header.flags
+		    + grub2_core_img->multiboot_header.checksum) != 0) {
+			error
+			    ("The file specified by grub=<loader> is not a valid GRUB2
core.img binary.\n");
+			goto bail;
+		}
+
+		/*
+		 *   -1:   whole drive (default) (-1 = 0xffffffff)
+		 *   0-3:  primary partitions
+		 *   4-*:  logical partitions
+		 */
+		grub2_core_img->install_dos_part = ((uint32_t) whichpart) - 1;
+
+		/*
+		 * GRUB2 reserves 63 bytes (0x21c - 0x25b) for the GRUB2 directory.
+		 * The filename passed via grub2dir= will overwrite the default
+		 * GRUB2 directory "/boot/grub/".
+		 */
+		if (opt.grub2dir) {
+		    if (strlen(opt.grub2dir) > sizeof(grub2_core_img->grub2dir) - 1) {
+			error
+			    ("The config filename length can't exceed 63 characters.\n");
+			goto bail;
+		    }
+		    strcpy((char *)grub2_core_img->grub2dir, opt.grub2dir);
+		}
+	    } else {
+		grub_legacy_stage2 = data[ndata].data;
+
+		/* Do we have stage2 of GRUB legacy ?
+		 *
+		 * Check the compatibility version number to see if we loaded a real
+		 * stage2 file or a stage2 file that we support.
+		 */
+		if (grub_legacy_stage2->compat_version_major != 3
+		    || grub_legacy_stage2->compat_version_minor != 2) {
 		    error
-			("The config filename length can't exceed 88 characters.\n");
+			("The file specified by grub=<loader> is not a supported GRUB Legacy
stage2 binary\n");
 		    goto bail;
 		}

-		strcpy((char *)stage2->config_file, opt.grubcfg);
+		/*
+		 * GRUB Legacy wants the partition number in the install_partition
+		 * variable, located at offset 0x208 of stage2.
+		 * When GRUB Legacy is loaded, it is located at memory address 0x8208.
+		 *
+		 * It looks very similar to the "boot information format" of the
+		 * Multiboot specification:
+		 *  
http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
+		 *
+		 *   0x208 = part3: sub-partition in sub-partition part2
+		 *   0x209 = part2: sub-partition in top-level partition
+		 *   0x20a = part1: top-level partition number
+		 *   0x20b = drive: BIOS drive number (must be 0)
+		 *
+		 * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
+		 * another location.
+		 *
+		 * Partition numbers always start from zero.
+		 * Unused partition bytes must be set to 0xff.
+		 *
+		 * We only care about top-level partition, so we only need to change
+		 * "part1" to the appropriate value:
+		 *   -1:   whole drive (default) (-1 = 0xff)
+		 *   0-3:  primary partitions
+		 *   4-*:  logical partitions
+		 */
+		grub_legacy_stage2->install_partition.part1 = whichpart - 1;
+
+		/*
+		 * Grub Legacy reserves 89 bytes (from 0x217 to 0x26f) for the
+		 * config filename. The filename passed via grubcfg= will overwrite
+		 * the default config filename "/boot/grub/menu.lst".
+		 */
+		if (opt.grubcfg) {
+		    if (strlen(opt.grubcfg) > sizeof(grub_legacy_stage2->config_file) -
1) {
+			error
+			    ("The config filename length can't exceed 88 characters.\n");
+			goto bail;
+		    }
+
+		    strcpy((char *)grub_legacy_stage2->config_file, opt.grubcfg);
+		}
 	    }
 	}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: chain-grub2.diff
Type: text/x-patch
Size: 11219 bytes
Desc: not available
URL: <http://www.zytor.com/pipermail/syslinux/attachments/20101221/ec3e6205/attachment.bin>


More information about the Syslinux mailing list