1 /* ----------------------------------------------------------------------- *
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-2015 Michal Soltys
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
17 * The above copyright notice and this permission notice shall
18 * be included in all copies or substantial portions of the Software.
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.
29 * ----------------------------------------------------------------------- */
31 #include <syslinux/movebits.h>
42 static int soi_s2n(char *ptr
,
48 addr_t segval
, offval
, ipval
, val
;
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);
62 /* verify if load address is within [dosmin, dosmax) */
63 val
= (segval
<< 4) + offval
;
65 if (val
< dosmin
|| val
>= dosmax
) {
66 error("Invalid seg:off:* address specified.");
71 * verify if jump address is within [dosmin, dosmax) and offset is 16bit
74 val
= (segval
<< 4) + ipval
;
76 if (ipval
> 0xFFFE || val
< dosmin
|| val
>= dosmax
) {
77 error("Invalid seg:*:ip address specified.");
93 static void usage(void)
96 static const char *const usage
[] = {
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]",
107 " direct partition selection:",
108 " chain.c32 guid=<guid> [options]",
109 " chain.c32 label=<label> [options]",
110 " chain.c32 fs [options]",
112 "You can use ':' instead of '=' and ' ' instead of ','.",
113 "The default is 'boot,0'.",
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 " gpthcrc Perform gpt header crc check",
136 " gptlcrc Perform gpt list crc check",
137 " strict[=<0|1|2>] Set the level of strictness in sanity checks",
138 " - strict w/o any value is the same as strict=2",
139 " relax The same as strict=0",
140 " prefmbr On hybrid MBR/GPT disks, prefer legacy layout",
141 " exit Don't read anything after this keyword",
143 " file=<file> Load and execute <file>",
144 " seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>",
145 " - defaults to 0:0x7C00:0x7C00",
146 " - omitted o/i values default to 0",
147 " isolinux=<loader> Load another version of ISOLINUX",
148 " ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR",
149 " reactos=<loader> Load ReactOS's loader",
150 " cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003",
151 " freedos=<loader> Load FreeDOS KERNEL.SYS",
152 " msdos=<loader> Load MS-DOS 2.xx - 6.xx IO.SYS",
153 " msdos7=<loader> Load MS-DOS 7+ IO.SYS",
154 " pcdos=<loader> Load PC-DOS IBMBIO.COM",
155 " drmk=<loader> Load DRMK DELLBIO.BIN",
156 " grub=<loader> Load GRUB Legacy stage2",
157 " grubcfg=<config> Set alternative config filename for GRUB Legacy",
158 " grldr=<loader> Load GRUB4DOS grldr",
159 " bss=<sectimage> Emulate syslinux's BSS",
160 " bs=<sectimage> Emulate syslinux's BS",
162 "Please see doc/chain.txt for the detailed documentation."
164 for (i
= 0; i
< sizeof(usage
)/sizeof(usage
[0]); i
++) {
166 puts("Press any key...");
173 void opt_set_defs(void)
175 memset(&opt
, 0, sizeof opt
);
176 opt
.sect
= true; /* by def. load sector */
177 opt
.maps
= true; /* by def. map sector */
178 opt
.hand
= true; /* by def. prepare handover */
179 opt
.brkchain
= false; /* by def. do chainload */
180 /* strict but ignore disk size, do all gpt crc checks */
181 opt
.piflags
= PIF_STRICT
| PIF_GPTHCRC
| PIF_GPTLCRC
;
182 opt
.foff
= opt
.soff
= opt
.fip
= opt
.sip
= 0x7C00;
183 opt
.drivename
= "boot";
189 int opt_parse_args(int argc
, char *argv
[])
195 for (i
= 1; i
< argc
; i
++) {
196 if (!strncmp(argv
[i
], "file=", 5)) {
197 opt
.file
= argv
[i
] + 5;
198 } else if (!strncmp(argv
[i
], "exit", 4)) {
200 } else if (!strcmp(argv
[i
], "nofile")) {
202 } else if (!strncmp(argv
[i
], "seg=", 4)) {
203 if (soi_s2n(argv
[i
] + 4, &opt
.fseg
, &opt
.foff
, &opt
.fip
, 0))
205 } else if (!strncmp(argv
[i
], "bss=", 4)) {
206 opt
.file
= argv
[i
] + 4;
210 } else if (!strncmp(argv
[i
], "bs=", 3)) {
211 opt
.file
= argv
[i
] + 3;
214 } else if (!strncmp(argv
[i
], "isolinux=", 9)) {
215 opt
.file
= argv
[i
] + 9;
219 } else if (!strncmp(argv
[i
], "ntldr=", 6)) {
220 opt
.fseg
= 0x2000; /* NTLDR wants this address */
223 opt
.file
= argv
[i
] + 6;
226 } else if (!strncmp(argv
[i
], "reactos=", 8)) {
230 opt
.file
= argv
[i
] + 8;
233 } else if (!strncmp(argv
[i
], "cmldr=", 6)) {
234 opt
.fseg
= 0x2000; /* CMLDR wants this address */
237 opt
.file
= argv
[i
] + 6;
241 } else if (!strncmp(argv
[i
], "freedos=", 8)) {
242 opt
.fseg
= 0x60; /* FREEDOS wants this address */
246 opt
.file
= argv
[i
] + 8;
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 */
254 opt
.fip
= v
== 7 ? 0x200 : 0; /* MS-DOS 7.0+ wants this ip */
256 opt
.file
= argv
[i
] + v
;
259 } else if (!strncmp(argv
[i
], "drmk=", 5)) {
260 opt
.fseg
= 0x70; /* DRMK wants this address */
266 opt
.file
= argv
[i
] + 5;
267 /* opt.drmk = true; */
270 } else if (!strncmp(argv
[i
], "grub=", 5)) {
271 opt
.fseg
= 0x800; /* stage2 wants this address */
274 opt
.file
= argv
[i
] + 5;
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;
285 } else if (!strcmp(argv
[i
], "keeppxe")) {
287 } else if (!strcmp(argv
[i
], "nokeeppxe")) {
289 } else if (!strcmp(argv
[i
], "maps")) {
291 } else if (!strcmp(argv
[i
], "nomaps")) {
293 } else if (!strcmp(argv
[i
], "hand")) {
295 } else if (!strcmp(argv
[i
], "nohand")) {
297 } else if (!strcmp(argv
[i
], "hptr")) {
299 } else if (!strcmp(argv
[i
], "nohptr")) {
301 } else if (!strcmp(argv
[i
], "swap")) {
303 } else if (!strcmp(argv
[i
], "noswap")) {
305 } else if (!strcmp(argv
[i
], "nohide")) {
307 } else if (!strcmp(argv
[i
], "hide")) {
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")) {
321 } else if (!strcmp(argv
[i
], "nosetbpb")) {
323 } else if (!strcmp(argv
[i
], "filebpb")) {
325 } else if (!strcmp(argv
[i
], "nofilebpb")) {
327 } else if (!strncmp(argv
[i
], "sect=", 5) ||
328 !strcmp(argv
[i
], "sect")) {
330 if (soi_s2n(argv
[i
] + 5, &opt
.sseg
, &opt
.soff
, &opt
.sip
, 0))
334 } else if (!strcmp(argv
[i
], "nosect")) {
337 } else if (!strcmp(argv
[i
], "save")) {
339 opt
.piflags
|= PIF_STRICT
| PIF_STRICTER
;
340 } else if (!strcmp(argv
[i
], "nosave")) {
342 } else if (!strcmp(argv
[i
], "fixchs")) {
344 opt
.piflags
|= PIF_STRICT
| PIF_STRICTER
;
345 } else if (!strcmp(argv
[i
], "nofixchs")) {
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.");
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;
362 } else if (!strcmp(argv
[i
], "gpthcrc")) {
363 opt
.piflags
|= PIF_GPTHCRC
;
364 } else if (!strcmp(argv
[i
], "nogpthcrc")) {
365 opt
.piflags
&= ~PIF_GPTHCRC
;
366 } else if (!strcmp(argv
[i
], "gptlcrc")) {
367 opt
.piflags
|= PIF_GPTLCRC
;
368 } else if (!strcmp(argv
[i
], "nogptlcrc")) {
369 opt
.piflags
&= ~PIF_GPTLCRC
;
370 } else if (!strcmp(argv
[i
], "warn")) {
372 } else if (!strcmp(argv
[i
], "nowarn")) {
374 } else if (!strcmp(argv
[i
], "prefmbr")) {
375 opt
.piflags
|= PIF_PREFMBR
;
376 } else if (!strcmp(argv
[i
], "noprefmbr")) {
377 opt
.piflags
&= ~PIF_PREFMBR
;
378 } else if (!strcmp(argv
[i
], "nobreak")) {
379 opt
.brkchain
= false;
380 } else if (!strcmp(argv
[i
], "break")) {
385 } else if (((argv
[i
][0] == 'h' || argv
[i
][0] == 'f')
386 && argv
[i
][1] == 'd')
387 || !strncmp(argv
[i
], "mbr:", 4)
388 || !strncmp(argv
[i
], "mbr=", 4)
389 || !strncmp(argv
[i
], "guid:", 5)
390 || !strncmp(argv
[i
], "guid=", 5)
391 || !strncmp(argv
[i
], "label:", 6)
392 || !strncmp(argv
[i
], "label=", 6)
393 || !strcmp(argv
[i
], "boot")
394 || !strncmp(argv
[i
], "boot,", 5)
395 || !strcmp(argv
[i
], "fs")) {
396 opt
.drivename
= argv
[i
];
397 if (strncmp(argv
[i
], "label", 5))
398 p
= strchr(opt
.drivename
, ',');
403 opt
.partition
= p
+ 1;
404 } else if (argv
[i
+ 1] && argv
[i
+ 1][0] >= '0'
405 && argv
[i
+ 1][0] <= '9') {
406 opt
.partition
= argv
[++i
];
414 if (opt
.grubcfg
&& !opt
.grub
) {
415 error("grubcfg=<filename> must be used together with grub=<loader>.");
419 if (opt
.filebpb
&& !opt
.file
) {
420 error("Option 'filebpb' requires a file.");
424 if (opt
.save
&& !opt
.sect
) {
425 error("Option 'save' requires a sector.");
429 if (opt
.setbpb
&& !opt
.sect
) {
430 error("Option 'setbpb' requires a sector.");
434 if (opt
.maps
&& !opt
.sect
) {
435 error("Option 'maps' requires a sector.");
444 /* vim: set ts=8 sts=4 sw=4 noet: */