[PATCH] chain.c32: Allow chaining the current Syslinux partition

Shao Miller shao.miller at yrdsb.edu.on.ca
Sat Mar 13 04:50:32 PST 2010


"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--



More information about the Syslinux mailing list