• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
4  *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5  *   Copyright 2010 Shao Miller
6  *   Copyright 2010-2012 Michal Soltys
7  *
8  *   Permission is hereby granted, free of charge, to any person
9  *   obtaining a copy of this software and associated documentation
10  *   files (the "Software"), to deal in the Software without
11  *   restriction, including without limitation the rights to use,
12  *   copy, modify, merge, publish, distribute, sublicense, and/or
13  *   sell copies of the Software, and to permit persons to whom
14  *   the Software is furnished to do so, subject to the following
15  *   conditions:
16  *
17  *   The above copyright notice and this permission notice shall
18  *   be included in all copies or substantial portions of the Software.
19  *
20  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
22  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
25  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27  *   OTHER DEALINGS IN THE SOFTWARE.
28  *
29  * ----------------------------------------------------------------------- */
30 
31 #include <syslinux/movebits.h>
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "chain.h"
36 #include "partiter.h"
37 #include "utility.h"
38 #include "options.h"
39 
40 struct options opt;
41 
soi_s2n(char * ptr,addr_t * seg,addr_t * off,addr_t * ip,addr_t def)42 static int soi_s2n(char *ptr,
43 			addr_t *seg,
44 			addr_t *off,
45 			addr_t *ip,
46 			addr_t def)
47 {
48     addr_t segval, offval, ipval, val;
49     char *p;
50 
51     /* defaults */
52     segval = 0;
53     offval = def;
54     ipval = def;
55 
56     segval = strtoul(ptr, &p, 0);
57     if (p[0] == ':' && p[1] && p[1] != ':')
58 	offval = strtoul(p+1, &p, 0);
59     if (p[0] == ':' && p[1] && p[1] != ':')
60 	ipval = strtoul(p+1, NULL, 0);
61 
62     /* verify if load address is within [dosmin, dosmax) */
63     val = (segval << 4) + offval;
64 
65     if (val < dosmin || val >= dosmax) {
66 	error("Invalid seg:off:* address specified.");
67 	goto bail;
68     }
69 
70     /*
71      * verify if jump address is within [dosmin, dosmax) and offset is 16bit
72      * sane
73      */
74     val = (segval << 4) + ipval;
75 
76     if (ipval > 0xFFFE || val < dosmin || val >= dosmax) {
77 	error("Invalid seg:*:ip address specified.");
78 	goto bail;
79     }
80 
81     if (seg)
82 	*seg = segval;
83     if (off)
84 	*off = offval;
85     if (ip)
86 	*ip  = ipval;
87 
88     return 0;
89 bail:
90     return -1;
91 }
92 
usage(void)93 static void usage(void)
94 {
95     size_t i;
96     static const char *const usage[] = {
97 "Usage:",
98 "",
99 "  disk + partition selection:",
100 "        chain.c32 [options]",
101 "        chain.c32 hd#[,#] [options]",
102 "        chain.c32 fd#[,#] [options]",
103 "        chain.c32 mbr=<id>[,#] [options]",
104 "        chain.c32 guid=<guid>[,#] [options]",
105 "        chain.c32 boot[,#] [options]",
106 "",
107 "  direct partition selection:",
108 "        chain.c32 guid=<guid> [options]",
109 "        chain.c32 label=<label> [options]",
110 "        chain.c32 fs [options]",
111 "",
112 "You can use ':' instead of '=' and ' ' instead of ','.",
113 "The default is 'boot,0'.",
114 "",
115 "Options:",
116 "  sect[=<s[:o[:i]]>]   Load sector at <s:o>, jump to <s:i>",
117 "                       - defaults to 0:0x7C00:0x7C00",
118 "                       - omitted o/i values default to 0",
119 "  maps                 Map loaded sector into real memory",
120 "  setbpb               Fix BPB fields in loaded sector",
121 "  filebpb              Apply 'setbpb' to loaded file",
122 "  save                 Write adjusted sector back to disk",
123 "  hand                 Prepare handover area",
124 "  hptr                 Force ds:si and ds:bp to point to handover area",
125 "  swap                 Swap drive numbers, if bootdisk is not fd0/hd0",
126 "  nohide               Disable all hide variations (default)",
127 "  hide                 Hide primary partitions, unhide selected partition",
128 "  hideall              Hide *all* partitions, unhide selected partition",
129 "  unhide               Unhide primary partitions",
130 "  unhideall            Unhide *all* partitions",
131 "  fixchs               Walk *all* partitions and fix E/MBRs' CHS values",
132 "  keeppxe              Keep the PXE and UNDI stacks in memory (PXELINUX)",
133 "  warn                 Wait for a keypress to continue chainloading",
134 "  break                Don't chainload",
135 "  strict[=<0|1|2>]     Set the level of strictness in sanity checks",
136 "                       - strict w/o any value is the same as strict=2",
137 "  relax                The same as strict=0",
138 "  prefmbr              On hybrid MBR/GPT disks, prefer legacy layout",
139 "",
140 "  file=<file>          Load and execute <file>",
141 "  seg=<s[:o[:i]]>      Load file at <s:o>, jump to <s:i>",
142 "                       - defaults to 0:0x7C00:0x7C00",
143 "                       - omitted o/i values default to 0",
144 "  isolinux=<loader>    Load another version of ISOLINUX",
145 "  ntldr=<loader>       Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR",
146 "  reactos=<loader>     Load ReactOS's loader",
147 "  cmldr=<loader>       Load Recovery Console of Windows NT/2K/XP/2003",
148 "  freedos=<loader>     Load FreeDOS KERNEL.SYS",
149 "  msdos=<loader>       Load MS-DOS 2.xx - 6.xx IO.SYS",
150 "  msdos7=<loader>      Load MS-DOS 7+ IO.SYS",
151 "  pcdos=<loader>       Load PC-DOS IBMBIO.COM",
152 "  drmk=<loader>        Load DRMK DELLBIO.BIN",
153 "  grub=<loader>        Load GRUB Legacy stage2",
154 "  grubcfg=<config>     Set alternative config filename for GRUB Legacy",
155 "  grldr=<loader>       Load GRUB4DOS grldr",
156 "  bss=<sectimage>      Emulate syslinux's BSS",
157 "  bs=<sectimage>       Emulate syslinux's BS",
158 "",
159 "Please see doc/chain.txt for the detailed documentation."
160 };
161     for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
162 	if (i % 20 == 19) {
163 	    puts("Press any key...");
164 	    wait_key();
165 	}
166 	puts(usage[i]);
167     }
168 }
169 
opt_set_defs(void)170 void opt_set_defs(void)
171 {
172     memset(&opt, 0, sizeof opt);
173     opt.sect = true;	    /* by def. load sector */
174     opt.maps = true;	    /* by def. map sector */
175     opt.hand = true;	    /* by def. prepare handover */
176     opt.brkchain = false;   /* by def. do chainload */
177     opt.piflags = PIF_STRICT;	/* by def. be strict, but ignore disk sizes */
178     opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
179     opt.drivename = "boot";
180 #ifdef DEBUG
181     opt.warn = true;
182 #endif
183 }
184 
opt_parse_args(int argc,char * argv[])185 int opt_parse_args(int argc, char *argv[])
186 {
187     int i;
188     size_t v;
189     char *p;
190 
191     for (i = 1; i < argc; i++) {
192 	if (!strncmp(argv[i], "file=", 5)) {
193 	    opt.file = argv[i] + 5;
194 	} else if (!strcmp(argv[i], "nofile")) {
195 	    opt.file = NULL;
196 	} else if (!strncmp(argv[i], "seg=", 4)) {
197 	    if (soi_s2n(argv[i] + 4, &opt.fseg, &opt.foff, &opt.fip, 0))
198 		goto bail;
199 	} else if (!strncmp(argv[i], "bss=", 4)) {
200 	    opt.file = argv[i] + 4;
201 	    opt.bss = true;
202 	    opt.maps = false;
203 	    opt.setbpb = true;
204 	} else if (!strncmp(argv[i], "bs=", 3)) {
205 	    opt.file = argv[i] + 3;
206 	    opt.sect = false;
207 	    opt.filebpb = true;
208 	} else if (!strncmp(argv[i], "isolinux=", 9)) {
209 	    opt.file = argv[i] + 9;
210 	    opt.isolinux = true;
211 	    opt.hand = false;
212 	    opt.sect = false;
213 	} else if (!strncmp(argv[i], "ntldr=", 6)) {
214 	    opt.fseg = 0x2000;  /* NTLDR wants this address */
215 	    opt.foff = 0;
216 	    opt.fip = 0;
217 	    opt.file = argv[i] + 6;
218 	    opt.setbpb = true;
219 	    opt.hand = false;
220 	} else if (!strncmp(argv[i], "reactos=", 8)) {
221 	    /*
222 	     * settings based on commit
223 	     *   ad4cf1470977f648ee1dd45e97939589ccb0393c
224 	     * note, conflicts with:
225 	     *   http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt
226 	     */
227 	    opt.fseg = 0;
228 	    opt.foff = 0x8000;
229 	    opt.fip = 0x8100;
230 	    opt.file = argv[i] + 8;
231 	    opt.setbpb = true;
232 	    opt.hand = false;
233 	} else if (!strncmp(argv[i], "cmldr=", 6)) {
234 	    opt.fseg = 0x2000;  /* CMLDR wants this address */
235 	    opt.foff = 0;
236 	    opt.fip = 0;
237 	    opt.file = argv[i] + 6;
238 	    opt.cmldr = true;
239 	    opt.setbpb = true;
240 	    opt.hand = false;
241 	} else if (!strncmp(argv[i], "freedos=", 8)) {
242 	    opt.fseg = 0x60;    /* FREEDOS wants this address */
243 	    opt.foff = 0;
244 	    opt.fip = 0;
245 	    opt.sseg = 0x1FE0;
246 	    opt.file = argv[i] + 8;
247 	    opt.setbpb = true;
248 	    opt.hand = false;
249 	} else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
250 		     !strncmp(argv[i], "pcdos=", v)) ||
251 		    (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
252 	    opt.fseg = 0x70;    /* MS-DOS 2.00 .. 6.xx wants this address */
253 	    opt.foff = 0;
254 	    opt.fip = v == 7 ? 0x200 : 0;  /* MS-DOS 7.0+ wants this ip */
255 	    opt.sseg = 0x8000;
256 	    opt.file = argv[i] + v;
257 	    opt.setbpb = true;
258 	    opt.hand = false;
259 	} else if (!strncmp(argv[i], "drmk=", 5)) {
260 	    opt.fseg = 0x70;    /* DRMK wants this address */
261 	    opt.foff = 0;
262 	    opt.fip = 0;
263 	    opt.sseg = 0x2000;
264 	    opt.soff = 0;
265 	    opt.sip = 0;
266 	    opt.file = argv[i] + 5;
267 	    /* opt.drmk = true; */
268 	    opt.setbpb = true;
269 	    opt.hand = false;
270 	} else if (!strncmp(argv[i], "grub=", 5)) {
271 	    opt.fseg = 0x800;	/* stage2 wants this address */
272 	    opt.foff = 0;
273 	    opt.fip = 0x200;
274 	    opt.file = argv[i] + 5;
275 	    opt.grub = true;
276 	    opt.hand = false;
277 	    opt.sect = false;
278 	} else if (!strncmp(argv[i], "grubcfg=", 8)) {
279 	    opt.grubcfg = argv[i] + 8;
280 	} else if (!strncmp(argv[i], "grldr=", 6)) {
281 	    opt.file = argv[i] + 6;
282 	    opt.grldr = true;
283 	    opt.hand = false;
284 	    opt.sect = false;
285 	} else if (!strcmp(argv[i], "keeppxe")) {
286 	    opt.keeppxe = 3;
287 	} else if (!strcmp(argv[i], "nokeeppxe")) {
288 	    opt.keeppxe = 0;
289 	} else if (!strcmp(argv[i], "maps")) {
290 	    opt.maps = true;
291 	} else if (!strcmp(argv[i], "nomaps")) {
292 	    opt.maps = false;
293 	} else if (!strcmp(argv[i], "hand")) {
294 	    opt.hand = true;
295 	} else if (!strcmp(argv[i], "nohand")) {
296 	    opt.hand = false;
297 	} else if (!strcmp(argv[i], "hptr")) {
298 	    opt.hptr = true;
299 	} else if (!strcmp(argv[i], "nohptr")) {
300 	    opt.hptr = false;
301 	} else if (!strcmp(argv[i], "swap")) {
302 	    opt.swap = true;
303 	} else if (!strcmp(argv[i], "noswap")) {
304 	    opt.swap = false;
305 	} else if (!strcmp(argv[i], "nohide")) {
306 	    opt.hide = HIDE_OFF;
307 	} else if (!strcmp(argv[i], "hide")) {
308 	    opt.hide = HIDE_ON;
309 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
310 	} else if (!strcmp(argv[i], "hideall")) {
311 	    opt.hide = HIDE_ON | HIDE_EXT;
312 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
313 	} else if (!strcmp(argv[i], "unhide")) {
314 	    opt.hide = HIDE_ON | HIDE_REV;
315 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
316 	} else if (!strcmp(argv[i], "unhideall")) {
317 	    opt.hide = HIDE_ON | HIDE_EXT | HIDE_REV;
318 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
319 	} else if (!strcmp(argv[i], "setbpb")) {
320 	    opt.setbpb = true;
321 	} else if (!strcmp(argv[i], "nosetbpb")) {
322 	    opt.setbpb = false;
323 	} else if (!strcmp(argv[i], "filebpb")) {
324 	    opt.filebpb = true;
325 	} else if (!strcmp(argv[i], "nofilebpb")) {
326 	    opt.filebpb = false;
327 	} else if (!strncmp(argv[i], "sect=", 5) ||
328 		   !strcmp(argv[i], "sect")) {
329 	    if (argv[i][4]) {
330 		if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0))
331 		    goto bail;
332 	    }
333 	    opt.sect = true;
334 	} else if (!strcmp(argv[i], "nosect")) {
335 	    opt.sect = false;
336 	    opt.maps = false;
337 	} else if (!strcmp(argv[i], "save")) {
338 	    opt.save = true;
339 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
340 	} else if (!strcmp(argv[i], "nosave")) {
341 	    opt.save = false;
342 	} else if (!strcmp(argv[i], "fixchs")) {
343 	    opt.fixchs = true;
344 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
345 	} else if (!strcmp(argv[i], "nofixchs")) {
346 	    opt.fixchs = false;
347 	} else if (!strcmp(argv[i], "relax") || !strcmp(argv[i], "nostrict")) {
348 	    opt.piflags &= ~(PIF_STRICT | PIF_STRICTER);
349 	} else if (!strcmp(argv[i], "norelax") || !strcmp(argv[i], "strict")) {
350 	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
351 	} else if (!strncmp(argv[i], "strict=", 7)) {
352 	    if (argv[i][7] < '0' || argv[i][7] > '2' || !argv[i][8]) {
353 		error("Strict level must be 0, 1 or 2.");
354 		goto bail;
355 	    }
356 	    opt.piflags &= ~(PIF_STRICT | PIF_STRICTER);
357 	    switch (argv[i][7]) {
358 		case '2': opt.piflags |= PIF_STRICTER;
359 		case '1': opt.piflags |= PIF_STRICT; break;
360 		default:;
361 	    }
362 	} else if (!strcmp(argv[i], "warn")) {
363 	    opt.warn = true;
364 	} else if (!strcmp(argv[i], "nowarn")) {
365 	    opt.warn = false;
366 	} else if (!strcmp(argv[i], "prefmbr")) {
367 	    opt.piflags |= PIF_PREFMBR;
368 	} else if (!strcmp(argv[i], "noprefmbr")) {
369 	    opt.piflags &= ~PIF_PREFMBR;
370 	} else if (!strcmp(argv[i], "nobreak")) {
371 	    opt.brkchain = false;
372 	} else if (!strcmp(argv[i], "break")) {
373 	    opt.brkchain = true;
374 	    opt.file = NULL;
375 	    opt.maps = false;
376 	    opt.hand = false;
377 	} else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
378 		    && argv[i][1] == 'd')
379 		   || !strncmp(argv[i], "mbr:", 4)
380 		   || !strncmp(argv[i], "mbr=", 4)
381 		   || !strncmp(argv[i], "guid:", 5)
382 		   || !strncmp(argv[i], "guid=", 5)
383 		   || !strncmp(argv[i], "label:", 6)
384 		   || !strncmp(argv[i], "label=", 6)
385 		   || !strcmp(argv[i], "boot")
386 		   || !strncmp(argv[i], "boot,", 5)
387 		   || !strcmp(argv[i], "fs")) {
388 	    opt.drivename = argv[i];
389 	    if (strncmp(argv[i], "label", 5))
390 		p = strchr(opt.drivename, ',');
391 	    else
392 		p = NULL;
393 	    if (p) {
394 		*p = '\0';
395 		opt.partition = p + 1;
396 	    } else if (argv[i + 1] && argv[i + 1][0] >= '0'
397 		    && argv[i + 1][0] <= '9') {
398 		opt.partition = argv[++i];
399 	    }
400 	} else {
401 	    usage();
402 	    goto bail;
403 	}
404     }
405 
406     if (opt.grubcfg && !opt.grub) {
407 	error("grubcfg=<filename> must be used together with grub=<loader>.");
408 	goto bail;
409     }
410 
411     if (opt.filebpb && !opt.file) {
412 	error("Option 'filebpb' requires a file.");
413 	goto bail;
414     }
415 
416     if (opt.save && !opt.sect) {
417 	error("Option 'save' requires a sector.");
418 	goto bail;
419     }
420 
421     if (opt.setbpb && !opt.sect) {
422 	error("Option 'setbpb' requires a sector.");
423 	goto bail;
424     }
425 
426     if (opt.maps && !opt.sect) {
427 	error("Option 'maps' requires a sector.");
428 	goto bail;
429     }
430 
431     return 0;
432 bail:
433     return -1;
434 }
435 
436 /* vim: set ts=8 sts=4 sw=4 noet: */
437