[syslinux] [PATCH] add grubcfg= for passing an alternative config filename to GRUB Legacy and cleanup the root partition passing
Gert Hulselmans
gerth at zytor.com
Sun Jul 4 11:54:28 PDT 2010
Shao Miller wrote:
> A nice offering and please kindly accept the following code review. ;)
>
> Gert Hulselmans wrote:
>> Examples:
>> chain.c32 fs grub=/boot/grub/stage2 grubcfg=/boot/grub/grub.lst
>> chain.c32 hd1,10 grub=/boot/grub/stage2 grubcfg=/boot/grub/grub.lst
>
> Disadvantage: The user's use of 'grubcfg=...' without an accompanying
> 'grub=...' yields no warning/error. Even if it warned, GRUB might clear
> the screen anyway. :S Also, a lengthy path will be silently discarded.
>
>
>> - grub=<loader> Load GRUB stage2\n\
>> + grub=<loader> Load GRUB Legacy stage2\n\
>> + grubcfg=<filename> Set alternative config filename for GRUB
>> Legacy\n\
>
> Advantage: This keeps the usage narrow. :)
>
>> - /* GRUB's stage2 wants the partition number in the
>> install_partition
>> + /*
>> + * GRUB's stage2 wants the partition number in the
>> install_partition
>> * variable, located at memory address 0x8208.
>> - * We only need to change the value of memory address 0x820a too:
>> - * -1: whole drive (default)
>> + *
>> + * It looks very similar to the "boot information format" of the
>> + * Multiboot specification:
>> ...
>
> Some nice documentation here for the curious. :)
>
>> + if (opt.grubcfg && strlen(opt.grubcfg) <= 88
>> + && data[ndata].size > 0x26f)
>> +
>> + memcpy((char *)data[ndata].data + 0x217, opt.grubcfg,
>> + strlen(opt.grubcfg) + 1);
>> }
>
> Even so, some of these numbers are mystical and might be better off as
> '#define's or 'enum { ... };'s. The documentation certainly helps.
>
> For your '88': Personally, I enjoy using an array of 'char xxx[89];'
> somewhere and then using 'sizeof(xxx)' or 'sizeof(xxx) - 1' wherever I
> need to talk about its size. In this case, one way to do that would be
> to put the array in a struct and have a pointer-to-that-struct pointed
> at this special region in the stage2 binary.
>
> Quite a co-incidence of timing where Paul Bolle submitted a similar
> patch nearly simultaneously! It would be really great if chain.c32 got
> the best of both. :)
>
> I don't speak on behalf of Syslinux; just my review.
>
> - Shao Miller
>
Here is a new patch:
http://git.zytor.com/?p=users/gerth/syslinux.git;a=commit;h=601712aef7489e68d372a8b7290959a572cb67a3
-Gert Hulselmans
GRUB Legacy reserves 89 bytes for storing the filename of the configfile
from memory address 0x8217 to 0x826f.
We allow overwriting the default value (/boot/grub/menu.lst) when
grubcfg=<filename> is used together with grub=<loader>.
Examples:
chain.c32 fs grub=/boot/grub/stage2 grubcfg=/boot/grub/grub.lst
chain.c32 hd1,10 grub=/boot/grub/stage2 grubcfg=/boot/grub/grub.lst
Use a structure instead of hard-coded offsets for modifying the
install_partition variable
(and the configfile name) in the stage2 file.
Add some comments about the "boot information format" of the Multiboot
specification, which
is very similar to the install_partition variable used by GRUB Legacy.
Signed-off-by: Gert Hulselmans <gerth at zytor.com>
---
com32/modules/chain.c | 121
+++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 112 insertions(+), 9 deletions(-)
diff --git a/com32/modules/chain.c b/com32/modules/chain.c
index 4f5baf1..7a2c8d4 100644
--- a/com32/modules/chain.c
+++ b/com32/modules/chain.c
@@ -78,7 +78,11 @@
*
* grub=<loader>
* same as seg=0x800 file=<loader> & jumping to seg 0x820,
- * used with GRUB stage2 files.
+ * used with GRUB Legacy stage2 files.
+ *
+ * grubcfg=<filename>
+ * set an alternative config filename in stage2 of Grub Legacy,
+ * only applicable in combination with "grub=<loader>".
*
* grldr=<loader>
* pass the partition number to GRUB4DOS,
@@ -125,6 +129,7 @@ static struct options {
bool cmldr;
bool grub;
bool grldr;
+ const char *grubcfg;
bool swap;
bool hide;
bool sethidden;
@@ -1276,7 +1281,8 @@ Options: file=<loader> Load and execute file,
instead of boot sector\n\
freedos=<loader> Load FreeDOS KERNEL.SYS\n\
msdos=<loader> Load MS-DOS IO.SYS\n\
pcdos=<loader> Load PC-DOS IBMBIO.COM\n\
- grub=<loader> Load GRUB stage2\n\
+ grub=<loader> Load GRUB Legacy stage2\n\
+ grubcfg=<filename> Set alternative config filename for GRUB
Legacy\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\
@@ -1349,6 +1355,8 @@ int main(int argc, char *argv[])
opt.seg = 0x800; /* stage2 wants this address */
opt.loadfile = argv[i] + 5;
opt.grub = true;
+ } else if (!strncmp(argv[i], "grubcfg=", 8)) {
+ opt.grubcfg = argv[i] + 8;
} else if (!strncmp(argv[i], "grldr=", 6)) {
opt.loadfile = argv[i] + 6;
opt.grldr = true;
@@ -1392,6 +1400,11 @@ int main(int argc, char *argv[])
}
}
+ if (opt.grubcfg && !opt.grub) {
+ error("grubcfg=<filename> 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 {
@@ -1583,15 +1596,105 @@ int main(int argc, char *argv[])
}
if (opt.grub) {
- regs.ip = 0x200; /* jump 0x200 bytes into the loadfile */
+ /* Layout of stage2 file (from byte 0x0 to 0x270) */
+ struct grub_stage2_patch_area {
+ /* 0x0 to 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 */
+ struct {
+ /* 0x208: sub-partition in sub-partition part2 */
+ uint8_t part3;
+ /* 0x209: sub-partition in top-level partition */
+ uint8_t part2;
+ /* 0x20a: top-level partiton number */
+ uint8_t part1;
+ /* 0x20b: BIOS drive number (must be 0) */
+ uint8_t drive;
+ } __attribute__ ((packed)) install_partition;
+
+ /* 0x20c: 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) */
+ char version_string[5];
+ /* 0x217: config filename */
+ char config_file[89];
+ /* 0x270: start of code (after jump from 0x200) */
+ char codestart[1];
+ } __attribute__ ((packed));
+
+ 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;
+ }
+
+ struct grub_stage2_patch_area *stage2 = data[ndata].data;
- /* GRUB's stage2 wants the partition number in the install_partition
- * variable, located at memory address 0x8208.
- * We only need to change the value of memory address 0x820a too:
- * -1: whole drive (default)
+ /*
+ * 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) {
+ error
+ ("The file specified by grub=<loader> is not a supported stage2
GRUB Legacy binary\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 */
- ((uint8_t*) data[ndata].data)[0x20a] = (uint8_t)(whichpart - 1);
+ * 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) {
+ error
+ ("The config filename length can't exceed 88 characters.\n");
+ goto bail;
+ }
+
+ strcpy((char *)stage2->config_file, opt.grubcfg);
+ }
}
ndata++;
--
1.6.3.3
More information about the Syslinux
mailing list