[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