diff options
Diffstat (limited to 'com32/chain/options.c')
-rw-r--r-- | com32/chain/options.c | 436 |
1 files changed, 436 insertions, 0 deletions
diff --git a/com32/chain/options.c b/com32/chain/options.c new file mode 100644 index 0000000..a99e0d7 --- /dev/null +++ b/com32/chain/options.c @@ -0,0 +1,436 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin + * Copyright 2010 Shao Miller + * Copyright 2010-2012 Michal Soltys + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +#include <syslinux/movebits.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "chain.h" +#include "partiter.h" +#include "utility.h" +#include "options.h" + +struct options opt; + +static int soi_s2n(char *ptr, + addr_t *seg, + addr_t *off, + addr_t *ip, + addr_t def) +{ + addr_t segval, offval, ipval, val; + char *p; + + /* defaults */ + segval = 0; + offval = def; + ipval = def; + + segval = strtoul(ptr, &p, 0); + if (p[0] == ':' && p[1] && p[1] != ':') + offval = strtoul(p+1, &p, 0); + if (p[0] == ':' && p[1] && p[1] != ':') + ipval = strtoul(p+1, NULL, 0); + + /* verify if load address is within [dosmin, dosmax) */ + val = (segval << 4) + offval; + + if (val < dosmin || val >= dosmax) { + error("Invalid seg:off:* address specified."); + goto bail; + } + + /* + * verify if jump address is within [dosmin, dosmax) and offset is 16bit + * sane + */ + val = (segval << 4) + ipval; + + if (ipval > 0xFFFE || val < dosmin || val >= dosmax) { + error("Invalid seg:*:ip address specified."); + goto bail; + } + + if (seg) + *seg = segval; + if (off) + *off = offval; + if (ip) + *ip = ipval; + + return 0; +bail: + return -1; +} + +static void usage(void) +{ + size_t i; + static const char *const usage[] = { +"Usage:", +"", +" disk + partition selection:", +" chain.c32 [options]", +" chain.c32 hd#[,#] [options]", +" chain.c32 fd#[,#] [options]", +" chain.c32 mbr=<id>[,#] [options]", +" chain.c32 guid=<guid>[,#] [options]", +" chain.c32 boot[,#] [options]", +"", +" direct partition selection:", +" chain.c32 guid=<guid> [options]", +" chain.c32 label=<label> [options]", +" chain.c32 fs [options]", +"", +"You can use ':' instead of '=' and ' ' instead of ','.", +"The default is 'boot,0'.", +"", +"Options:", +" sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>", +" - defaults to 0:0x7C00:0x7C00", +" - omitted o/i values default to 0", +" maps Map loaded sector into real memory", +" setbpb Fix BPB fields in loaded sector", +" filebpb Apply 'setbpb' to loaded file", +" save Write adjusted sector back to disk", +" hand Prepare handover area", +" hptr Force ds:si and ds:bp to point to handover area", +" swap Swap drive numbers, if bootdisk is not fd0/hd0", +" nohide Disable all hide variations (default)", +" hide Hide primary partitions, unhide selected partition", +" hideall Hide *all* partitions, unhide selected partition", +" unhide Unhide primary partitions", +" unhideall Unhide *all* partitions", +" fixchs Walk *all* partitions and fix E/MBRs' CHS values", +" keeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)", +" warn Wait for a keypress to continue chainloading", +" break Don't chainload", +" strict[=<0|1|2>] Set the level of strictness in sanity checks", +" - strict w/o any value is the same as strict=2", +" relax The same as strict=0", +" 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>", +" - defaults to 0:0x7C00:0x7C00", +" - omitted o/i values default to 0", +" isolinux=<loader> Load another version of ISOLINUX", +" ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR", +" reactos=<loader> Load ReactOS's loader", +" cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003", +" freedos=<loader> Load FreeDOS KERNEL.SYS", +" msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS", +" msdos7=<loader> Load MS-DOS 7+ IO.SYS", +" pcdos=<loader> Load PC-DOS IBMBIO.COM", +" drmk=<loader> Load DRMK DELLBIO.BIN", +" grub=<loader> Load GRUB Legacy stage2", +" grubcfg=<config> Set alternative config filename for GRUB Legacy", +" grldr=<loader> Load GRUB4DOS grldr", +" bss=<sectimage> Emulate syslinux's BSS", +" bs=<sectimage> Emulate syslinux's BS", +"", +"Please see doc/chain.txt for the detailed documentation." +}; + for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) { + if (i % 20 == 19) { + puts("Press any key..."); + wait_key(); + } + puts(usage[i]); + } +} + +void opt_set_defs(void) +{ + memset(&opt, 0, sizeof opt); + opt.sect = true; /* by def. load sector */ + opt.maps = true; /* by def. map sector */ + opt.hand = true; /* by def. prepare handover */ + opt.brkchain = false; /* by def. do chainload */ + opt.piflags = PIF_STRICT; /* by def. be strict, but ignore disk sizes */ + opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00; + opt.drivename = "boot"; +#ifdef DEBUG + opt.warn = true; +#endif +} + +int opt_parse_args(int argc, char *argv[]) +{ + int i; + size_t v; + char *p; + + for (i = 1; i < argc; i++) { + if (!strncmp(argv[i], "file=", 5)) { + opt.file = argv[i] + 5; + } else if (!strcmp(argv[i], "nofile")) { + opt.file = NULL; + } else if (!strncmp(argv[i], "seg=", 4)) { + if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0)) + goto bail; + } else if (!strncmp(argv[i], "bss=", 4)) { + opt.file = argv[i] + 4; + opt.bss = true; + opt.maps = false; + opt.setbpb = true; + } else if (!strncmp(argv[i], "bs=", 3)) { + opt.file = argv[i] + 3; + opt.sect = false; + opt.filebpb = true; + } else if (!strncmp(argv[i], "isolinux=", 9)) { + opt.file = argv[i] + 9; + opt.isolinux = true; + opt.hand = false; + opt.sect = false; + } else if (!strncmp(argv[i], "ntldr=", 6)) { + opt.fseg = 0x2000; /* NTLDR wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.file = argv[i] + 6; + opt.setbpb = true; + opt.hand = false; + } else if (!strncmp(argv[i], "reactos=", 8)) { + /* + * settings based on commit + * ad4cf1470977f648ee1dd45e97939589ccb0393c + * note, conflicts with: + * http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt + */ + opt.fseg = 0; + opt.foff = 0x8000; + opt.fip = 0x8100; + opt.file = argv[i] + 8; + opt.setbpb = true; + opt.hand = false; + } else if (!strncmp(argv[i], "cmldr=", 6)) { + opt.fseg = 0x2000; /* CMLDR wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.file = argv[i] + 6; + opt.cmldr = true; + opt.setbpb = true; + opt.hand = false; + } else if (!strncmp(argv[i], "freedos=", 8)) { + opt.fseg = 0x60; /* FREEDOS wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.sseg = 0x1FE0; + opt.file = argv[i] + 8; + opt.setbpb = true; + opt.hand = false; + } else if ( (v = 6, !strncmp(argv[i], "msdos=", v) || + !strncmp(argv[i], "pcdos=", v)) || + (v = 7, !strncmp(argv[i], "msdos7=", v)) ) { + opt.fseg = 0x70; /* MS-DOS 2.00 .. 6.xx wants this address */ + opt.foff = 0; + opt.fip = v == 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */ + opt.sseg = 0x8000; + opt.file = argv[i] + v; + opt.setbpb = true; + opt.hand = false; + } else if (!strncmp(argv[i], "drmk=", 5)) { + opt.fseg = 0x70; /* DRMK wants this address */ + opt.foff = 0; + opt.fip = 0; + opt.sseg = 0x2000; + opt.soff = 0; + opt.sip = 0; + opt.file = argv[i] + 5; + /* opt.drmk = true; */ + opt.setbpb = true; + opt.hand = false; + } else if (!strncmp(argv[i], "grub=", 5)) { + opt.fseg = 0x800; /* stage2 wants this address */ + opt.foff = 0; + opt.fip = 0x200; + opt.file = argv[i] + 5; + opt.grub = true; + opt.hand = false; + opt.sect = false; + } else if (!strncmp(argv[i], "grubcfg=", 8)) { + opt.grubcfg = argv[i] + 8; + } else if (!strncmp(argv[i], "grldr=", 6)) { + opt.file = argv[i] + 6; + opt.grldr = true; + opt.hand = false; + opt.sect = false; + } else if (!strcmp(argv[i], "keeppxe")) { + opt.keeppxe = 3; + } else if (!strcmp(argv[i], "nokeeppxe")) { + opt.keeppxe = 0; + } else if (!strcmp(argv[i], "maps")) { + opt.maps = true; + } else if (!strcmp(argv[i], "nomaps")) { + opt.maps = false; + } else if (!strcmp(argv[i], "hand")) { + opt.hand = true; + } else if (!strcmp(argv[i], "nohand")) { + opt.hand = false; + } else if (!strcmp(argv[i], "hptr")) { + opt.hptr = true; + } else if (!strcmp(argv[i], "nohptr")) { + opt.hptr = false; + } else if (!strcmp(argv[i], "swap")) { + opt.swap = true; + } else if (!strcmp(argv[i], "noswap")) { + opt.swap = false; + } else if (!strcmp(argv[i], "nohide")) { + opt.hide = HIDE_OFF; + } else if (!strcmp(argv[i], "hide")) { + opt.hide = HIDE_ON; + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strcmp(argv[i], "hideall")) { + opt.hide = HIDE_ON | HIDE_EXT; + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strcmp(argv[i], "unhide")) { + opt.hide = HIDE_ON | HIDE_REV; + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strcmp(argv[i], "unhideall")) { + opt.hide = HIDE_ON | HIDE_EXT | HIDE_REV; + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strcmp(argv[i], "setbpb")) { + opt.setbpb = true; + } else if (!strcmp(argv[i], "nosetbpb")) { + opt.setbpb = false; + } else if (!strcmp(argv[i], "filebpb")) { + opt.filebpb = true; + } else if (!strcmp(argv[i], "nofilebpb")) { + opt.filebpb = false; + } else if (!strncmp(argv[i], "sect=", 5) || + !strcmp(argv[i], "sect")) { + if (argv[i][4]) { + if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0)) + goto bail; + } + opt.sect = true; + } else if (!strcmp(argv[i], "nosect")) { + opt.sect = false; + opt.maps = false; + } else if (!strcmp(argv[i], "save")) { + opt.save = true; + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strcmp(argv[i], "nosave")) { + opt.save = false; + } else if (!strcmp(argv[i], "fixchs")) { + opt.fixchs = true; + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strcmp(argv[i], "nofixchs")) { + opt.fixchs = false; + } else if (!strcmp(argv[i], "relax") || !strcmp(argv[i], "nostrict")) { + opt.piflags &= ~(PIF_STRICT | PIF_STRICTER); + } else if (!strcmp(argv[i], "norelax") || !strcmp(argv[i], "strict")) { + opt.piflags |= PIF_STRICT | PIF_STRICTER; + } else if (!strncmp(argv[i], "strict=", 7)) { + if (argv[i][7] < '0' || argv[i][7] > '2' || !argv[i][8]) { + error("Strict level must be 0, 1 or 2."); + goto bail; + } + opt.piflags &= ~(PIF_STRICT | PIF_STRICTER); + switch (argv[i][7]) { + case '2': opt.piflags |= PIF_STRICTER; + case '1': opt.piflags |= PIF_STRICT; break; + default:; + } + } else if (!strcmp(argv[i], "warn")) { + opt.warn = true; + } else if (!strcmp(argv[i], "nowarn")) { + opt.warn = false; + } else if (!strcmp(argv[i], "prefmbr")) { + opt.piflags |= PIF_PREFMBR; + } else if (!strcmp(argv[i], "noprefmbr")) { + opt.piflags &= ~PIF_PREFMBR; + } else if (!strcmp(argv[i], "nobreak")) { + opt.brkchain = false; + } else if (!strcmp(argv[i], "break")) { + opt.brkchain = true; + opt.file = NULL; + opt.maps = false; + opt.hand = false; + } else if (((argv[i][0] == 'h' || argv[i][0] == 'f') + && argv[i][1] == 'd') + || !strncmp(argv[i], "mbr:", 4) + || !strncmp(argv[i], "mbr=", 4) + || !strncmp(argv[i], "guid:", 5) + || !strncmp(argv[i], "guid=", 5) + || !strncmp(argv[i], "label:", 6) + || !strncmp(argv[i], "label=", 6) + || !strcmp(argv[i], "boot") + || !strncmp(argv[i], "boot,", 5) + || !strcmp(argv[i], "fs")) { + opt.drivename = argv[i]; + if (strncmp(argv[i], "label", 5)) + p = strchr(opt.drivename, ','); + else + p = NULL; + if (p) { + *p = '\0'; + opt.partition = p + 1; + } else if (argv[i + 1] && argv[i + 1][0] >= '0' + && argv[i + 1][0] <= '9') { + opt.partition = argv[++i]; + } + } else { + usage(); + goto bail; + } + } + + if (opt.grubcfg && !opt.grub) { + error("grubcfg=<filename> must be used together with grub=<loader>."); + goto bail; + } + + if (opt.filebpb && !opt.file) { + error("Option 'filebpb' requires a file."); + goto bail; + } + + if (opt.save && !opt.sect) { + error("Option 'save' requires a sector."); + goto bail; + } + + if (opt.setbpb && !opt.sect) { + error("Option 'setbpb' requires a sector."); + goto bail; + } + + if (opt.maps && !opt.sect) { + error("Option 'maps' requires a sector."); + goto bail; + } + + return 0; +bail: + return -1; +} + +/* vim: set ts=8 sts=4 sw=4 noet: */ |