blob: a99e0d7bb4ce2898c43a7a1d353d3a3884a8fbd0 [file] [log] [blame]
Greg Hartman76d05dc2016-11-23 15:51:27 -08001/* ----------------------------------------------------------------------- *
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
40struct options opt;
41
42static 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;
89bail:
90 return -1;
91}
92
93static 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
170void 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
185int 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;
432bail:
433 return -1;
434}
435
436/* vim: set ts=8 sts=4 sw=4 noet: */