From: H. Peter Anvin Date: Mon, 2 May 2011 01:00:19 +0000 (-0700) Subject: chain.c32: allow specifying arbitrary seg/offs/entry X-Git-Tag: syslinux-4.05-pre1~5 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=42fb596d240474c31152d965648860e9c40e54b6;p=profile%2Fivi%2Fsyslinux.git chain.c32: allow specifying arbitrary seg/offs/entry Augment the seg= option to also allow for the offset and entry point to be specified. Signed-off-by: H. Peter Anvin --- diff --git a/com32/modules/chain.c b/com32/modules/chain.c index 0e289f6..ced105a 100644 --- a/com32/modules/chain.c +++ b/com32/modules/chain.c @@ -49,8 +49,11 @@ * loads the file **from the Syslinux filesystem** * instead of loading the boot sector. * - * seg= - * loads at and jumps to :0000 instead of 0000:7C00. + * seg=[:][{+@}entry] + * loads at : and jumps to : instead + * of the default 0000:7C00. and default to 0 and +0 + * repectively. If start with + (rather than @) then the + * entry point address is added to the offset. * * isolinux= * chainload another version/build of the ISOLINUX bootloader and patch @@ -132,10 +135,11 @@ static struct options { const char *loadfile; uint16_t keeppxe; uint16_t seg; + uint16_t offs; + uint16_t entry; bool isolinux; bool cmldr; bool grub; - bool freeldr; bool grldr; const char *grubcfg; bool swap; @@ -1289,7 +1293,8 @@ Options: file= Load and execute file, instead of boot sector\n\ grub= Load GRUB Legacy stage2\n\ grubcfg= Set alternative config filename for GRUB Legacy\n\ grldr= Load GRUB4DOS grldr\n\ - seg= Jump to :0000, instead of 0000:7C00\n\ + seg= Jump to :0000, instead of 0000:7C00\n\ + seg=[:][{+@}] also specified offset and entrypoint\n\ swap Swap drive numbers, if bootdisk is not fd0/hd0\n\ hide Hide primary partitions, except selected partition\n\ sethidden Set the FAT/NTFS hidden sectors field\n\ @@ -1325,49 +1330,88 @@ int main(int argc, char *argv[]) /* Prepare the register set */ memset(®s, 0, sizeof regs); + opt.seg = 0; + opt.offs = 0x7c00; + opt.entry = 0x7c00; + for (i = 1; i < argc; i++) { if (!strncmp(argv[i], "file=", 5)) { opt.loadfile = argv[i] + 5; } else if (!strncmp(argv[i], "seg=", 4)) { - uint32_t segval = strtoul(argv[i] + 4, NULL, 0); - if (segval < 0x50 || segval > 0x9f000) { - error("Invalid segment\n"); + uint32_t v; + bool add_entry = true; + char *ep, *p = argv[i] + 4; + + v = strtoul(p, &ep, 0); + if (ep == p || v < 0x50 || v > 0x9f000) { + error("seg: Invalid segment\n"); goto bail; } - opt.seg = segval; + opt.seg = v; + opt.offs = opt.entry = 0; + if (*ep == ':') { + p = ep+1; + v = strtoul(p, &ep, 0); + if (ep == p) { + error("seg: Invalid offset\n"); + goto bail; + } + opt.offs = v; + } + if (*ep == '@' || *ep == '+') { + add_entry = (*ep == '+'); + p = ep+1; + v = strtoul(p, &ep, 0); + if (ep == p) { + error("seg: Invalid entry point\n"); + goto bail; + } + opt.entry = v; + } + if (add_entry) + opt.entry += opt.offs; } else if (!strncmp(argv[i], "isolinux=", 9)) { opt.loadfile = argv[i] + 9; opt.isolinux = true; } else if (!strncmp(argv[i], "ntldr=", 6)) { opt.seg = 0x2000; /* NTLDR wants this address */ + opt.offs = opt.entry = 0; opt.loadfile = argv[i] + 6; opt.sethidden = true; } else if (!strncmp(argv[i], "cmldr=", 6)) { opt.seg = 0x2000; /* CMLDR wants this address */ + opt.offs = opt.entry = 0; opt.loadfile = argv[i] + 6; opt.cmldr = true; opt.sethidden = true; } else if (!strncmp(argv[i], "freedos=", 8)) { opt.seg = 0x60; /* FREEDOS wants this address */ + opt.offs = opt.entry = 0; opt.loadfile = argv[i] + 8; opt.sethidden = true; } else if (!strncmp(argv[i], "freeldr=", 8)) { opt.loadfile = argv[i] + 8; opt.sethidden = true; /* The FreeLdr PE wants to be at 0:8000 */ - opt.freeldr = true; + opt.seg = 0; + opt.offs = 0x8000; + /* TODO: Properly parse the PE. Right now, this is hard-coded */ + opt.entry = 0x8100; } else if (!strncmp(argv[i], "msdos=", 6) || !strncmp(argv[i], "pcdos=", 6)) { opt.seg = 0x70; /* MS-DOS 2.0+ wants this address */ + opt.offs = opt.entry = 0; opt.loadfile = argv[i] + 6; opt.sethidden = true; } else if (!strncmp(argv[i], "drmk=", 5)) { opt.seg = 0x70; /* DRMK wants this address */ + opt.offs = opt.entry = 0; opt.loadfile = argv[i] + 5; opt.sethidden = true; opt.drmk = true; } else if (!strncmp(argv[i], "grub=", 5)) { opt.seg = 0x800; /* stage2 wants this address */ + opt.offs = opt.entry = 0; opt.loadfile = argv[i] + 5; opt.grub = true; } else if (!strncmp(argv[i], "grubcfg=", 8)) { @@ -1422,18 +1466,20 @@ int main(int argc, char *argv[]) goto bail; } - if (opt.seg) { - regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg; - } else { - regs.ip = regs.esp.l = 0x7c00; - } + /* + * Set up initial register values + */ + regs.es = regs.cs = regs.ss = regs.ds = regs.fs = regs.gs = opt.seg; + regs.ip = opt.entry; + + /* + * For the special case of the standard 0:7C00 entry point, put + * the stack below; otherwise leave the stack pointer at the end + * of the segment (sp = 0). + */ + if (opt.seg == 0 && opt.offs == 0x7c00) + regs.esp.l = 0x7c00; - if (opt.freeldr) { - /* Load to 0800:0000, which happens to be 0000:8000 */ - opt.seg = 0x800; - /* TODO: Properly parse the PE. Right now, this is hard-coded */ - regs.ip = 0x8100; - } hd = 0; if (!strncmp(drivename, "mbr", 3)) { @@ -1544,7 +1590,7 @@ int main(int argc, char *argv[]) } /* Do the actual chainloading */ - load_base = opt.seg ? (opt.seg << 4) : 0x7c00; + load_base = (opt.seg << 4) + opt.offs; if (opt.loadfile) { fputs("Loading the boot file...\n", stdout);