Shao Miller
2010-Mar-13 12:50 UTC
[PATCH] chain.c32: Allow chaining the current Syslinux partition
"chain.c32 fs" will determine the disk and partition (if applicable) and boot it, possibly with additional options. Only applicable from SYSLINUX and EXTLINUX at this time. Signed-off-by: Shao Miller <shao.miller at yrdsb.edu.on.ca> --- com32/modules/chain.c | 112 ++++++++++++++++++++++++++++++++----------------- 1 files changed, 74 insertions(+), 38 deletions(-) mode change 100644 => 100755 com32/modules/chain.c diff --git a/com32/modules/chain.c b/com32/modules/chain.c old mode 100644 new mode 100755 index 160aa70..07e1bc6 --- a/com32/modules/chain.c +++ b/com32/modules/chain.c @@ -16,24 +16,33 @@ * * Chainload a hard disk (currently rather braindead.) * - * Usage: chain hd<disk#> [<partition>] [options] + * Usage: chain [options] + * chain hd<disk#> [<partition>] [options] * chain fd<disk#> [options] * chain mbr:<id> [<partition>] [options] * chain boot [<partition>] [options] + * chain fs [options] * - * ... e.g. "chain hd0 1" will boot the first partition on the first hard + * 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. * + * When none of the "hdX", "fdX", "mbr:", "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. * * Partitions 1-4 are primary, 5+ logical, 0 = boot MBR (default.) * + * "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. + * * Options: * * file=<loader>: - * loads the file <loader> **from the SYSLINUX filesystem** + * loads the file <loader> **from the Syslinux filesystem** * instead of loading the boot sector. * * seg=<segment>: @@ -376,7 +385,7 @@ struct part_entry { are relative to the beginning of the extended partition all the way back at the MBR... but still not absolute! */ -int nextpart; /* Number of the next logical partition */ +int nextpart = 1; /* Number of the next logical partition */ static struct part_entry *find_logical_partition(int whichpart, char *table, struct part_entry *self, @@ -406,6 +415,15 @@ static struct part_entry *find_logical_partition(int whichpart, char *table, if (!ptab[i].length) continue; + /* + * We support a reverse-lookup mode where "self" is a + * partition table entry to find the partition number for. + */ + if (whichpart == 0 && + self->start_lba == ptab[i].start_lba && + self->length == ptab[i].length) + return self; + /* Adjust the offset to account for the extended partition itself */ ptab[i].start_lba += self->start_lba; @@ -596,10 +614,8 @@ static int hide_unhide(char *mbr, int part) int i; struct part_entry *pt; const uint16_t mask - (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | (1 << 0x07) | (1 << 0x0b) | (1 - << - 0x0c) - | (1 << 0x0e); + (1 << 0x01) | (1 << 0x04) | (1 << 0x06) | + (1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e); uint8_t t; bool write_back = false; @@ -668,21 +684,29 @@ static uint32_t get_file_lba(const char *filename) static void usage(void) { - error("Usage: chain.c32 hd<disk#> [<partition>] [options]\n" + error("Usage: chain.c32 [options]\n" + " chain.c32 hd<disk#> [<partition>] [options]\n" " chain.c32 fd<disk#> [options]\n" " chain.c32 mbr:<id> [<partition>] [options]\n" " chain.c32 boot [<partition>] [options]\n" - "Options: file=<loader> load file, instead of boot sector\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\n" - " freedos=<loader> load FreeDOS kernel.sys\n" - " msdos=<loader> load MS-DOS io.sys\n" - " pcdos=<loader> load PC-DOS ibmbio.com\n" - " seg=<segment> jump to <seg>:0000 instead of 0000:7C00\n" - " swap swap drive numbers, if bootdisk is not fd0/hd0\n" - " hide hide primary partitions, except selected partition\n" - " sethidden set the FAT/NTFS hidden sectors field\n" + " chain.c32 fs [options]\n" + "Options: file=<loader> Load file, instead of boot sector\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\n" + " freedos=<loader> Load FreeDOS kernel.sys\n" + " msdos=<loader> Load MS-DOS io.sys\n" + " pcdos=<loader> Load PC-DOS ibmbio.com\n" + " seg=<segment> Jump to <seg>:0000 instead of " + "0000:7C00\n" + " swap Swap drive numbers, if bootdisk is not " + "fd0/hd0\n" + " hide Hide primary partitions, except " + "selected partition\n" + " sethidden Set the FAT/NTFS hidden sectors field\n" + "See syslinux/com32/modules/chain.c for more information\n" ); } @@ -691,9 +715,10 @@ int main(int argc, char *argv[]) { char *mbr, *p; struct part_entry *partinfo; + static struct part_entry *fs = NULL; /* Syslinux partition */ struct syslinux_rm_regs regs; char *drivename, *partition; - int hd, drive, whichpart; + int hd, drive, whichpart = 0; /* MBR by default */ int i; uint32_t file_lba = 0; unsigned char *isolinux_bin; @@ -761,7 +786,8 @@ int main(int argc, char *argv[]) || !strncmp(argv[i], "mbr:", 4) || !strncmp(argv[i], "mbr=", 4) || !strcmp(argv[i], "boot") - || !strncmp(argv[i], "boot,", 5)) { + || !strncmp(argv[i], "boot,", 5) + || !strncmp(argv[i], "fs", 2)) { drivename = argv[i]; p = strchr(drivename, '',''); if (p) { @@ -795,13 +821,19 @@ int main(int argc, char *argv[]) hd = drivename[0] == ''h''; drivename += 2; drive = (hd ? 0x80 : 0) | strtoul(drivename, NULL, 0); - } else if (!strcmp(drivename, "boot")) { + } else if (!strcmp(drivename, "boot") || !strcmp(drivename, "fs")) { const union syslinux_derivative_info *sdi; + sdi = syslinux_derivative_info(); if (sdi->c.filesystem == SYSLINUX_FS_PXELINUX) drive = 0x80; /* Boot drive not available */ else drive = sdi->disk.drive_number; + if (!strcmp(drivename, "fs") + && (sdi->c.filesystem == SYSLINUX_FS_SYSLINUX + || sdi->c.filesystem == SYSLINUX_FS_EXTLINUX)) + /* We should lookup the Syslinux partition number and use it */ + fs = (struct part_entry *)sdi->disk.ptab_ptr; } else { error("Unparsable drive specification\n"); goto bail; @@ -810,34 +842,38 @@ int main(int argc, char *argv[]) /* DOS kernels want the drive number in BL instead of DL. Indulge them. */ regs.ebx.b[0] = regs.edx.b[0] = drive; - whichpart = 0; /* Default */ + /* Get the disk geometry and disk access setup */ + if (get_disk_params(drive)) { + error("Cannot get disk parameters\n"); + goto bail; + } + + /* Get MBR */ + if (!(mbr = read_sector(0))) { + error("Cannot read Master Boot Record\n"); + goto bail; + } + if (partition) whichpart = strtoul(partition, NULL, 0); + /* We should lookup the Syslinux partition number and use it */ + if (fs != NULL) + whichpart = (find_logical_partition(0, mbr, fs, NULL) != NULL) + ? nextpart : 0; + if (!(drive & 0x80) && whichpart) { error("Warning: Partitions of floppy devices may not work\n"); } - /* - * grldr of Grub4dos wants the partition number in DH: + /* + * GRLDR of GRUB4DOS wants the partition number in DH: * -1: whole drive (default) * 0-3: primary partitions * 4-*: logical partitions */ regs.edx.b[1] = whichpart-1; - /* Get the disk geometry and disk access setup */ - if (get_disk_params(drive)) { - error("Cannot get disk parameters\n"); - goto bail; - } - - /* Get MBR */ - if (!(mbr = read_sector(0))) { - error("Cannot read Master Boot Record\n"); - goto bail; - } - if (opt.hide) { if (whichpart < 1 || whichpart > 4) error("WARNING: hide specified without a non-primary partition\n"); -- 1.5.3.4 --------------060300050103070204070604--