int soi_s2n(char *ptr, unsigned int *seg,
unsigned int *off,
- unsigned int *ip)
+ unsigned int *ip,
+ unsigned int def)
{
- unsigned int segval = 0, offval = 0x7c00, ipval = 0x7c00, val;
+ unsigned int segval = 0, offval, ipval, val;
char *p;
+ offval = def;
+ ipval = def;
+
segval = strtoul(ptr, &p, 0);
if (p[0] == ':' && p[1] && p[1] != ':')
offval = strtoul(p+1, &p, 0);
"\
Usage:\n\
chain.c32 [options]\n\
- chain.c32 {fd|hd}<disk> [<partition>] [options]\n\
- chain.c32 mbr{:|=}<id> [<partition>] [options]\n\
- chain.c32 guid{:|=}<guid> [<partition>] [options]\n\
- chain.c32 label{:|=}<label> [<partition>] [options]\n\
- chain.c32 boot{,| }[<partition>] [options]\n\
+ chain.c32 {fd|hd}<disk>{,| }[<part#>] [options]\n\
+ chain.c32 mbr{:|=}<id>{, | }[<part#>] [options]\n\
+ chain.c32 guid{:|=}<guid>{,| }[<part#>] [options]\n\
+ chain.c32 label{:|=}<label> [<part#>] [options]\n\
+ chain.c32 boot{,| }[<part#>] [options]\n\
chain.c32 fs [options]\n\
", "\
-\nOptions ('no' prefix specify default value):\n\
- file=<loader> Load and execute file\n\
+\nOptions #1 ('no' prefix specifies default value):\n\
+ file=<file> Load and execute <file>\n\
seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
- nofilebpb Treat file in memory as BPB compatible\n\
+ - defaults to 0:0x7C00:0x7C00\n\
+ - ommited o/i values default to 0\n\
sect[=<s[:o[:i]]>] Load sector at <s:o>, jump to <s:i>\n\
- defaults to 0:0x7C00:0x7C00\n\
- - ommited o/i values default 0x7C00\n\
+ - ommited o/i values default to 0x7C00\n\
maps Map loaded sector into real memory\n\
nosethid[den] Set BPB's hidden sectors field\n\
nosetgeo Set BPB's sectors per track and heads fields\n\
- <off> defaults to autodetection\n\
- only 0x24 and 0x40 are accepted\n\
nosetbpb Enable set{hid,geo,drv}\n\
+ nofilebpb Treat file in memory as BPB compatible\n\
+", "\
+\nOptions #2 ('no' prefix specifies default value):\n\
nosave Write adjusted sector back to disk\n\
hand Prepare handover area\n\
nohptr Force ds:si and ds:bp to point to handover area\n\
nowarn Wait for a keypress to continue chainloading\n\
- useful to see emited warnings\n\
", "\
-\nComposite options:\n\
+\nOptions #3 ('no' prefix specifies default value):\n\
isolinux=<loader> Load another version of ISOLINUX\n\
ntldr=<loader> Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR\n\
cmldr=<loader> Load Recovery Console of Windows NT/2K/XP/2003\n\
} 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))
+ 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.setdrv = true;
opt.drvoff = ~0u;
opt.filebpb = true;
+ /* opt.save = true; */
} else if (!strncmp(argv[i], "isolinux=", 9)) {
opt.file = argv[i] + 9;
opt.isolinux = true;
opt.fseg = 0x60; /* FREEDOS wants this address */
opt.foff = 0;
opt.fip = 0;
- opt.sseg = 0x9000;
- opt.soff = 0;
- opt.sip = 0;
+ opt.sseg = 0x1FE0;
opt.file = argv[i] + 8;
opt.sethid = true;
opt.setgeo = true;
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 = 0x9000;
- opt.soff = 0;
- opt.sip = 0;
+ opt.sseg = 0x8000;
opt.file = argv[i] + v;
opt.sethid = true;
opt.setgeo = true;
} 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))
+ if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0x7c00))
goto bail;
if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
error("Arguments of 'sect=' are invalid - resulting address too big.\n");
|| !strncmp(argv[i], "boot,", 5)
|| !strcmp(argv[i], "fs")) {
opt.drivename = argv[i];
- p = strchr(opt.drivename, ',');
- 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];
+ if (strncmp(argv[i], "label", 5)) {
+ p = strchr(opt.drivename, ',');
+ 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();
chain.c32 documentation
Although syslinux is capable of (very simple) native chainloading (through .bss
-and .bs options - see doc/syslinux.txt), it also has a very roboust and
-feature-rich com32 module designed for such purpose. This module should allow
-you to boot virtually anything.
+and .bs options - see doc/syslinux.txt), it also features a very roboust and
+rich com32 module designed for such purpose.
+Chain module can perform few basic tasks:
-!FIXME: initial move from chain.c below
+- load and jump to a sector
+- load and jump to a file (also loading a sector for other purposes)
+- prepare handover data to use by a file / boot sector
+- fix different options in a file / sector / partition entries
+It can chainload data from both GPT and DOS partitions, as well as boot the
+first sector from a raw disk.
-Chainload a hard disk.
+In more details, the flow of code is as follows:
-Usage: chain [options]
- chain hd<disk#> [<partition>] [options]
- chain fd<disk#> [options]
- chain mbr:<id> [<partition>] [options]
- chain guid:<guid> [<partition>] [options]
- chain label:<label> [<partition>] [options]
- chain boot [<partition>] [options]
+1. Parse arguments.
+2. Find drive and/or partition to boot from.
+3. Hide / unhide systems and/or fix chs values in partition entries on the
+ drive syslinux is booting from (options: 'hide', 'hideall', 'mbrchs').
+4. Load file to boot from (options: 'file', 'seg').
+5. Load sector to boot from (options: 'sect', 'maps'), if it doesn't conflict
+ with #5.
+6. Prepare handover area (options: 'hand', 'maps'), if it doesn't conflict
+ with #5 & #6, and syslinux is booting a partition.
+7. Adjust ds:si and ds:bp to point to either a handover, a sector (options:
+ 'hptr', 'maps', 'sect', 'file') or nowhere.
+8. Patch loaded file if necessary ('isolinux', 'grub', 'grldr', 'filebpb')
+9. Patch loaded sector if necessary ('setdrv', 'sethid', 'setgeo', 'setbpb',
+ 'save', 'cmldr')
+10. Chainload (options: 'swap').
-For example, "chain msdos=io.sys" will load DOS from the current Syslinux
-filesystem. "chain hd0 1" will boot the first partition on the first hard
-disk.
+In most basic form, syslinux loads specified boot sector (or mbr, if not
+specified) at 0:0x7c00, prepares handover area as a standard mbr would do, and
+jumps to 0:0x7c00.
-When none of the "hdX", "fdX", "mbr:", "guid:", "label:", "boot" or "fs"
-options are specified, the default behaviour is equivalent to "boot".
-"boot" means to use the current Syslinux drive, and you can also specify
-a partition.
-The mbr: syntax means search all the hard disks until one with a
-specific MBR serial number (bytes 440-443) is found.
+Module invocation:
-Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.)
+chain [drive/partition] [options]
-"fs" will use the current Syslinux filesystem as the boot drive/partition.
-When booting from PXELINUX, you will most likely wish to specify a disk.
+ DRIVE / PARTITION SPECIFICATION
-Options:
+Drive can be specified as 'hd#', 'fd#', 'boot', 'mbr', or 'guid'.
-file=<loader>
- loads the file <loader> **from the Syslinux filesystem**
- instead of loading the boot sector.
+- 'mbr' will select a drive by a signature.
+- 'guid' will select a drive by a guid
+- 'boot' is the drive syslinux was booted from. This is the default value, if
+ nothing else is specified.
+- 'hd#' and 'fd#' are standard ways to specify drive number as seen by bios,
+ starting from 0.
-seg=<segment>
- loads at and jumps to <seg>:0000 instead of 0000:7C00.
+Option 'guid' is shared with partition selection (see below). If you happened
+to have non-unique guids, they are searched in disk0, partitions of disk0,
+disk1 ... order.
-isolinux=<loader>
- chainload another version/build of the ISOLINUX bootloader and patch
- the loader with appropriate parameters in memory.
- This avoids the need for the -eltorito-alt-boot parameter of mkisofs,
- when you want more than one ISOLINUX per CD/DVD.
+The priority of those options are the same as in the above list.
-ntldr=<loader>
- equivalent to seg=0x2000 file=<loader> sethidden,
- used with WinNT's loaders
+If you specify the same value more than once, the last value will be used.
-cmldr=<loader>
- used with Recovery Console of Windows NT/2K/XP.
- same as ntldr=<loader> & "cmdcons\0" written to
- the system name field in the bootsector
+'mbr' and 'guid' take extra parameter - you should use ':' or '=' as a
+delimiter.
-freedos=<loader>
- equivalent to seg=0x60 file=<loader> sethidden,
- used with FreeDOS' kernel.sys.
-msdos=<loader>
-pcdos=<loader>
- equivalent to seg=0x70 file=<loader> sethidden,
- used with DOS' io.sys.
+Partition can be specified as '#', 'guid', 'label' or 'fs'.
-grub=<loader>
- same as seg=0x800 file=<loader> & jumping to seg 0x820,
- used with GRUB Legacy stage2 files.
+- 'guid' option will select a partition by a guid (not a type guid !)
+- 'label' will select a partition by a label (searching is done in
+ disk order)
+- 'fs' will select a partition from which syslinux was executed
+- '#' is the standard method. Partitions 1-4 are primary, 5+ logical, 0 = boot
+ MBR (default).
-grubcfg=<filename>
- set an alternative config filename in stage2 of Grub Legacy,
- only applicable in combination with "grub=<loader>".
+The priority of those options are the same as in the above list.
-grldr=<loader>
- pass the partition number to GRUB4DOS,
- used with GRUB4DOS' grldr.
+If you use a number to select a partition it should be specified after a drive
+using space or comma as delimiters (after 'hd#', 'fd#', 'mbr', 'guid' or 'boot').
-swap
- if the disk is not fd0/hd0, install a BIOS stub which swaps
- the drive numbers.
+ OPTIONS
+ file=<file>
+ *nofile
-hide
- change type of primary partitions with IDs 01, 04, 06, 07,
- 0b, 0c, or 0e to 1x, except for the selected partition, which
- is converted the other way.
+It's often convenient to load a file directly and transfer control to it,
+instead of the sector from the disk. Note, that the <file> must reside on
+syslinux partition.
-sethidden
- update the "hidden sectors" (partition offset) field in a
- FAT/NTFS boot sector.
+If you choose this option without specifying any addresses explicitly (see
+options 'sect=' and 'seg='), the file will cause sector to not be loaded at all
+(as their memory placement would overlap).
-keeppxe
- keep the PXE and UNDI stacks in memory (PXELINUX only).
+ seg=<segment>:<offset>:<ip>
+ *seg=0:0x7c00:0x7c00
+This triplet lets you alter the addresses a file will use. Loading is done to
+<segment:offset>, jumping to <segment:ip>. When you chainload some other
+bootloader or kernel, it's almost always mandatory.
- file=<loader> Load and execute file; boot sector is also\n\
- msdos7=<loader> Load MS-DOS 7+ IO.SYS\n\
- seg=<s[:o[:i]]> Load file at <s:o>, jump to <s:i>\n\
- segbs=<s[:o[:i]]> Load boot sector at <s:o>, jump to <s:i>;\n\
- sethidden Set the FAT/NTFS hidden sectors field\n\
- setgeometry Set the FAT/NTFS sectors per track and heads fields\n\
- setdrive@<offset> Set the FAT/NTFS drive unit field at <offset>;\n\
- setdrive option alone defaults to 0x24\n\
- setbpb Enable set{hidden,geometry} options\n\
- writebs Write updated boot sector to the disk\n\
- filebpb Also mangle file with bpb options\n\
- bsnomap Don't map boot sector into real memory.\n\
+The defaults, if option is not specified, are 0:0x7c00:0x7c00
+If some of the fields are ommited (e.g. 0x2000::), they default to 0.
+
+ sect=<segment>:<offset>:<ip>
+ nosect
+ *sect=0:0x7c00:0x7c00
+
+This triplet lets you alter the addresses a sector will use. File is loaded at
+<segment:offset>, the jump is made to <segment:ip>. This option is mostly used
+in tandem with 'file=' and 'seg=' options, as some loaders/kernels will expect
+relocated sector at some particular address (e.g. DRKM).
+
+'nosect' will cause sector to not be loaded at all. In plenty cases, when a file
+is being chainloaded, sector is not necessary.
+
+The defaults if option is not specified, are 0:0x7c00:0x7c00.
+If some of the fields are ommited (e.g. 0x2000::), segment defaults to 0,
+offset and ip to 0x7c00.
+
+ *maps
+ nomaps
+
+In some cases, it's useful to fix BPB values in NTFS/FATxx bootsectors and
+evntually write them back, but otherwise boot sector itself is not necessary to
+continue booting. 'nomaps' allows that - a sector will be loaded, but won't be
+mmapped into real memory. Any overlap tests (vs. handover or file areas) are
+not performed, being meaningless in such case.
+
+ sethid[den]
+ *nosethid[den]
+
+ setgeo
+ *nosetgeo
+
+ setdrv[@<addr>]
+ *nodrv
+
+Microsoft side of the world is paritculary bitchy about certain BPB values.
+Depending on the system and chainloading method (sector or file), some or all
+of those fields must match reality - and after e.g. drive clonning or
+when using usb stick in different computers - that is often not the case.
+
+The "reality" means:
+
+"hidden sectors" - valid offset of the partition from the beginning of the disk
+"geometry" - valid disk geometry as reported by BIOS
+"drive" - valid drive number
+
+'sethidden'
+ updates the partition offset to match the current disk position
+'setgeo'
+ updates "heads" and "sectors per track" values as reported by BIOS
+'setdrv'
+ will update the drive value at proper offset. Only 0x24 and 0x40 are
+ accepted as valid values. You can use '@', '=' and ':' as delimiters.
+ If the address is not specified, it's autodetected.
+
+ setbpb
+ *nosetbpb
+
+Handy shortcut for setdrv, setgeo and sethid.
+
+ filebpb
+ *nofilebpb
+
+Chainloaded file can simply be an image of a sector. In such case, it could be
+useful to also fix its BPB values.
+
+ save
+ *nosave
+
+Fixing BPB values only in memory might not be enough. This option allows
+writing of the corrected sector. You will probably want to use this option
+together with 'setbpb' or other ones using that implicitly.
+
+- this option never applies to a loaded file
+- chain module will never save anything to disk by default
+- writing is only performed, if the values actually changed
+
+ hand
+ *hand
+
+By default, a handover area is always prepared if possible and potentially
+useful - meaning it doesn't overlap with other areas, and syslinux chainloads a
+partition. It's often not necessary though - usually, a chainloaded file or
+kernel don't care about it anymore, so a user can disable it explicitly with
+this option.
+
+ hptr
+ *nohptr
+
+In case when both file and sector are loaded, ds:si and ds:bp will point to
+sector address before the chainloading. This option lets user force those
+registers to point to handover area. This is useful when both the file and the
+sector are actually a sector's image and the sector is mmapped.
+
+ swap
+ *noswap
+
+This option will install a tiny stub code used to swap drive numbers, if the
+drive we use during chainloading is not fd0 or hd0.
+
+ hide[all]
+ *nohide
+
+In certain situations it's useful to hide partitions - for example to make sure
+DOS gets C:. 'hide' will hide hidable primary partitions, except the one we're
+booting from. Similary, 'hideall' will hide all hidable partitions, except the
+one we're booting from. Hiding is performed only on the boot drive.
+Writing is only performed, if the values actually changed.
+
+ mbrchs
+ *nombrchs
+
+If you want to make a drive you're booting from totally compatible with current
+BIOS, you can use this to fix all partitions' CHS numbers. Good to silence e.g.
+FreeDOS complainig about 'logical CHS differs from physcial' of sfdisk about
+'found (...) expected (...). Functionally seems to be mostly cosmetic, as
+Microsoft world - in cases it cares about geometry - generally sticks to values
+written in bootsectors. And the rest of the world generally doesn't care about
+them at all. Writing is only performed, if the values actually changed.
+
+ keepexe
+ *nokeepexe
+
+If you're booting over a network using pxelinux - this lets you keep UNDI
+stacks in memory.
+
+ warn
+ *nowarn
+
+This option will wait for a keypress right before continuing the chainloading.
+Useful to see warnings emited by the chain module.
+
+ isolinux=<file>
+ sets: file=<file> nohand nosect
+
+Chainload another version/build of the ISOLINUX bootloader and patch the loader
+with appropriate parameters in memory. This avoids the need for the
+-eltorito-alt-boot parameter of mkisofs, when you want more than one ISOLINUX
+per CD/DVD.
+
+ ntldr=<file>
+ sets: file=<file> seg=0x2000 setbpb nohand
+
+Prepares to load ntldr directly. You might want to add 'save' option to store
+corrected BPB values.
+
+ cmldr=<file>
+ sets: file=<file> seg=0x2000 setbpb nohand
+
+Prepares to load recovery console directly. In-memory copy of bootsector is
+patched with "cmdcons\0". Remarks the same as in 'ntldr='.
+
+ freedos=<file>
+ sets: file=<file> seg=0x60 sect=0x1FE0 setbpb nohand
+
+Prepares to load freedos kernel directly. You will likely want to add 'save'
+option, as those kernels seem to require proper geometry written back to disk.
+Sector address is chosen based on where freedos' bootsectors relocate themselves,
+although it seems the kernel doesn't rely on one.
+You might also want to employ 'hide' option, if you have problems with properly
+assigned C: drive.
+
+ pcdos=<file>
+ msdos=<file>
+ sets: file=<file> seg=0x70 sect=0x8000 setbpb nohand
+
+Similary to 'freedos=', This prepares to load MSDOS 2.00 - 6.xx or derivatives.
+Sector address is chosen arbitrarily. Otherwise comments as above.
+
+ msdos7=<file>
+ sets: file=<file> seg=0x70::0x200 sect=0x8000 setbpb nohand
+
+Only for MSDOS 7+ versions (98se ~ 7.xx, millenium ~ 8.xx). Comments as above.
+TODO/TEST
+
+ drmk=<file>
+ sets: file=<file> seg=0x70 sect=0x2000:0:0 setbpb nohand
+
+This is used for loading of *only* Dell's DOS derivatives. It does require boot
+sector at 0x2000 and overall valid BPB values. As with other DOSish cases,
+likely candidates for use are 'save' and 'hide'.
+
+ grub=<file>
+ grubcfg=<config>
+ sets: file=<file> seg=0x800::0x200 nohand nosect
+
+Chainloads grub legacy's stage2, performing additional corrections on the file
+in memory. Additionally, alternate config file can be specified through
+'grubcfg=' option
+
+ grldr=<file>
+ sets: file=<file> nohand nosect
+
+Chainloads GRUB4DOS grldr, performing additional corrections on the file
+in memory.
+
+ bss=<file>
+ sets: bss=<file> nomaps setbpb filebpb
+
+This attempts to emulate syslinux's native BSS option to certain extent. This
+loads both the file and the sector and adjusts BPB values in both. As only basic BPB
+fields are corrected, both the file and the sector should be identical enough
+(except boot code, drive number, geometry, hidden sectors). Don't forget about
+'save' and 'swap' options.
+
+This will likely get expanded in future.