[syslinux:master] chain.c: adjust what ds:si and ds: bp point to after chainloading

syslinux-bot for Michal Soltys soltys at ziu.info
Mon Mar 26 15:03:11 PDT 2012


Commit-ID:  f10e1f74f97ff8d46b994ca27f308fbc692b77dd
Gitweb:     http://www.syslinux.org/commit/f10e1f74f97ff8d46b994ca27f308fbc692b77dd
Author:     Michal Soltys <soltys at ziu.info>
AuthorDate: Thu, 19 Aug 2010 10:50:28 +0200
Committer:  Michal Soltys <soltys at ziu.info>
CommitDate: Sun, 22 Aug 2010 23:45:16 +0200

chain.c: adjust what ds:si and ds:bp point to after chainloading

Previously, chain module always set ds:si and ds:bp to handover
area (unless otherwise blocked). This is not necessarily valid in case
when both file and sector are being loaded - here file should receive
pointer to it's [relocated] sector, and it's unlikely interested in
mbr-like handover area at all.

Signed-off-by: Michal Soltys <soltys at ziu.info>

---
 com32/chain/chain.c |  117 +++++++++++++++++++++++++++++----------------------
 1 files changed, 66 insertions(+), 51 deletions(-)

diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index 6a58664..4f53336 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -37,19 +37,20 @@
 
 /* used in checks, whenever addresses supplied by user are sane */
 
-#define ADDRMAX 0x9EFFF
-#define ADDRMIN 0x500
+#define ADDRMAX 0x9EFFFu
+#define ADDRMIN 0x500u
 
 static const char cmldr_signature[8] = "cmdcons";
 static int fixed_cnt;
 
 static struct options {
-    uint32_t flin;
-    uint16_t fseg;
-    uint16_t fip;
-    uint32_t slin;
-    uint16_t sseg;
-    uint16_t sip;
+    unsigned int fseg;
+    unsigned int foff;
+    unsigned int fip;
+    unsigned int sseg;
+    unsigned int soff;
+    unsigned int sip;
+    unsigned int drvoff;
     const char *drivename;
     const char *partition;
     const char *loadfile;
@@ -66,7 +67,6 @@ static struct options {
     bool sethid;
     bool setgeo;
     bool setdrv;
-    uint8_t drvoff;
     bool read;
     bool write;
     bool filebpb;
@@ -438,11 +438,13 @@ static uint32_t get_file_lba(const char *filename)
     return lba;
 }
 
-/* Convert string seg:off:ip values into numerical seg:linear:ip ones */
+/* Convert string seg:off:ip values into numerical seg:off:ip ones */
 
-static int soi2sli(char *ptr, uint16_t *seg, uint32_t *lin, uint16_t *ip)
+static int soi_s2n(char *ptr, unsigned int *seg,
+			      unsigned int *off,
+			      unsigned int *ip)
 {
-    uint32_t segval = 0, offval = 0, ipval = 0, val;
+    unsigned int segval = 0, offval = 0, ipval = 0, val;
     char *p;
 
     segval = strtoul(ptr, &p, 0);
@@ -451,9 +453,9 @@ static int soi2sli(char *ptr, uint16_t *seg, uint32_t *lin, uint16_t *ip)
     if(*p == ':')
 	ipval = strtoul(p+1, NULL, 0);
 
-    offval = (segval << 4) + offval;
+    val = (segval << 4) + offval;
 
-    if (offval < ADDRMIN || offval > ADDRMAX) {
+    if (val < ADDRMIN || val > ADDRMAX) {
 	error("Invalid seg:off:* address specified..\n");
 	goto bail;
     }
@@ -461,16 +463,16 @@ static int soi2sli(char *ptr, uint16_t *seg, uint32_t *lin, uint16_t *ip)
     val = (segval << 4) + ipval;
 
     if (ipval > 0xFFFE || val < ADDRMIN || val > ADDRMAX) {
-	error("Invalid *:*:ip address specified.\n");
+	error("Invalid seg:*:ip address specified.\n");
 	goto bail;
     }
 
     if(seg)
-	*seg = (uint16_t)segval;
-    if(lin)
-	*lin = offval;
+	*seg = segval;
+    if(off)
+	*off = offval;
     if(ip)
-	*ip  = (uint16_t)ipval;
+	*ip  = ipval;
 
     return 0;
 
@@ -537,12 +539,12 @@ static int parse_args(int argc, char *argv[])
 	    opt.loadfile = argv[i] + 5;
 	} else if ((v = 4, !strncmp(argv[i], "seg=", v)) ||
 		   (v = 5, !strncmp(argv[i], "fseg=", v))) {
-	    if(soi2sli(argv[i] + v, &opt.fseg, &opt.flin, &opt.fip))
+	    if(soi_s2n(argv[i] + v, &opt.fseg, &opt.foff, &opt.fip))
 		goto bail;
 	} else if (!strncmp(argv[i], "sseg=", 5)) {
-	    if(soi2sli(argv[i] + 5, &opt.sseg, &opt.slin, &opt.sip))
+	    if(soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip))
 		goto bail;
-	    if(opt.slin + SECTOR - 1 > ADDRMAX) {
+	    if((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
 		error("Option 'sseg' is invalid - address too big.\n");
 		goto bail;
 	    }
@@ -553,7 +555,7 @@ static int parse_args(int argc, char *argv[])
 	    opt.read = false;
 	} else if (!strncmp(argv[i], "ntldr=", 6)) {
 	    opt.fseg = 0x2000;  /* NTLDR wants this address */
-	    opt.flin = 0x20000;
+	    opt.foff = 0;
 	    opt.fip = 0;
 	    opt.loadfile = argv[i] + 6;
 	    opt.sethid = true;
@@ -564,7 +566,7 @@ static int parse_args(int argc, char *argv[])
 	    opt.hand = false;
 	} else if (!strncmp(argv[i], "cmldr=", 6)) {
 	    opt.fseg = 0x2000;  /* CMLDR wants this address */
-	    opt.flin = 0x20000;
+	    opt.foff = 0;
 	    opt.fip = 0;
 	    opt.loadfile = argv[i] + 6;
 	    opt.cmldr = true;
@@ -576,7 +578,7 @@ static int parse_args(int argc, char *argv[])
 	    opt.hand = false;
 	} else if (!strncmp(argv[i], "freedos=", 8)) {
 	    opt.fseg = 0x60;    /* FREEDOS wants this address */
-	    opt.flin = 0x600;
+	    opt.foff = 0;
 	    opt.fip = 0;
 	    opt.loadfile = argv[i] + 8;
 	    opt.sethid = true;
@@ -588,7 +590,7 @@ static int parse_args(int argc, char *argv[])
 		     !strncmp(argv[i], "pcdos=", v)) ||
 		    (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
 	    opt.fseg = 0x70;    /* MS-DOS 2.00 .. 6.xx wants this address */
-	    opt.flin = 0x700;
+	    opt.foff = 0;
 	    opt.fip = v == 7 ? 0x200 : 0;  /* MS-DOS 7.0+ wants this ip */
 	    opt.loadfile = argv[i] + v;
 	    opt.sethid = true;
@@ -598,7 +600,7 @@ static int parse_args(int argc, char *argv[])
 	    opt.hand = false;
 	} else if (!strncmp(argv[i], "drmk=", 5)) {
 	    opt.fseg = 0x70;    /* DRMK wants this address */
-	    opt.flin = 0x700;
+	    opt.foff = 0;
 	    opt.fip = 0;
 	    opt.loadfile = argv[i] + 5;
 	    opt.drmk = true;
@@ -609,7 +611,7 @@ static int parse_args(int argc, char *argv[])
 	    opt.hand = false;
 	} else if (!strncmp(argv[i], "grub=", 5)) {
 	    opt.fseg = 0x800;	/* stage2 wants this address */
-	    opt.flin = 0x8000;
+	    opt.foff = 0;
 	    opt.fip = 0x200;
 	    opt.loadfile = argv[i] + 5;
 	    opt.grub = true;
@@ -666,7 +668,7 @@ static int parse_args(int argc, char *argv[])
 		goto bail;
 	    }
 	    opt.setdrv = true;
-	    opt.drvoff = (uint8_t)v;
+	    opt.drvoff = v;
 	} else if (!strcmp(argv[i], "nosetdrv")) {
 	    opt.setdrv = false;
 	} else if (!strcmp(argv[i], "read")) {
@@ -1053,7 +1055,7 @@ static int manglef_drmk(struct data_area *data)
     }
     data->size = tsize;
     /* ds:[bp+28] must be 0x0000003f */
-    opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2u));
+    opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
     /* "Patch" into tail of the new space */
     *(uint32_t *)((char*)data->data + tsize - 4) = 0x0000003f;
 
@@ -1085,13 +1087,16 @@ out:
 
 fallback:
     if(di->disk & 0x80)
-	return 0x00FFFFFE; /* 254/63/1023 */
+	return 0x00FFFFFE; /* 1023/63/254 */
     else
 	/* FIXME ?
 	 * this is mostly "useful" with partitioned floppy,
 	 * maybe stick to 2.88mb ?
 	 */
-	return 0x004F1201; /* 1/18/79 */
+	return 0x004F1201; /* 79/18/1 */
+#if 0
+	return 0x004F2401; /* 79/36/1 */
+#endif
 }
 
 static int setup_handover(const struct part_iter *iter,
@@ -1274,10 +1279,10 @@ int main(int argc, char *argv[])
 
     /* Prepare and set defaults */
     memset(&opt, 0, sizeof(opt));
-    opt.read = true;	/* by def read bs / mbr */
-    opt.hand = true;	/* by def do prepare handover */
-    opt.smap = true;	/* by def map bs / mbr */
-    opt.flin = opt.slin = opt.fip = opt.sip = 0x7C00;
+    opt.read = true;	/* by def load sector */
+    opt.smap = true;	/* by def map sector */
+    opt.hand = true;	/* by def prepare handover */
+    opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
     opt.drivename = "boot";
 
     /* Parse arguments */
@@ -1287,12 +1292,12 @@ int main(int argc, char *argv[])
     /* Set initial registry values, file takes precedence */
     if(opt.loadfile) {
 	opt.regs.es = opt.regs.cs = opt.regs.ss =
-	   opt.regs.ds = opt.regs.fs = opt.regs.gs = opt.fseg;
-	opt.regs.ip = opt.fip;
+	    opt.regs.ds = opt.regs.fs = opt.regs.gs = (uint16_t)opt.fseg;
+	opt.regs.ip = (uint16_t)opt.fip;
     } else {
 	opt.regs.es = opt.regs.cs = opt.regs.ss =
-	    opt.regs.ds = opt.regs.fs = opt.regs.gs = opt.sseg;
-	opt.regs.ip = opt.sip;
+	    opt.regs.ds = opt.regs.fs = opt.regs.gs = (uint16_t)opt.sseg;
+	opt.regs.ip = (uint16_t)opt.sip;
     }
     if(opt.regs.ip == 0x7C00 && !opt.regs.cs)
 	opt.regs.esp.l = 0x7C00;
@@ -1311,13 +1316,13 @@ int main(int argc, char *argv[])
 
     /* Load file and bs/mbr */
 
-    data[ndata].base = opt.flin;
+    data[ndata].base = (opt.fseg << 4) + opt.foff;
     if (opt.loadfile) {
 	if (loadfile(opt.loadfile, &data[ndata].data, &data[ndata].size)) {
 	    error("Couldn't read the boot file.\n");
 	    goto bail;
 	}
-	if (opt.flin + data[ndata].size - 1 > ADDRMAX) {
+	if (data[ndata].base + data[ndata].size - 1 > ADDRMAX) {
 	    error("Can't load the boot file at this address.\n");
 	    goto bail;
 	}
@@ -1331,10 +1336,10 @@ int main(int argc, char *argv[])
      * in first 512 bytes.
      */
     data[ndata].size = SECTOR;
-    data[ndata].base = opt.slin;
+    data[ndata].base = (opt.sseg << 4) + opt.soff;
     if (opt.read && (!opt.loadfile || !opt.smap || no_ov(data + fidx, data + ndata))) {
 	if (!(data[ndata].data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
-	    error("Couldn't read the bs / mbr.\n");
+	    error("Couldn't read the sector.\n");
 	    goto bail;
 	}
 	sect_area = (void *)data[ndata].data;
@@ -1344,7 +1349,7 @@ int main(int argc, char *argv[])
 	}
     }
 
-    /* Mangle file area */
+    /* Do file related stuff */
 
     if (fidx >= 0) {
 	if (opt.isolinux && manglef_isolinux(data + fidx))
@@ -1363,7 +1368,7 @@ int main(int argc, char *argv[])
 	    goto bail;
     }
 
-    /* Mangle bs/mbr area */
+    /* Do sector related stuff */
 
     if (sidx >= 0) {
 	if (try_sector_bpb(iter, data + sidx))
@@ -1371,23 +1376,33 @@ int main(int argc, char *argv[])
 
 	if (opt.cmldr && mangles_cmldr(data + sidx))
 	    goto bail;
+
+	if (opt.smap && fidx >= 0) {
+	    /* if we mmap bootsector for kernel to use,
+	     * let's point registers there
+	     */
+	    opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
+	    opt.regs.ds = (uint16_t)opt.sseg;
+	}
     }
 
-    /* Prepare handover (skip if not at partition) */
-    if (opt.hand && iter->index) {
+    /* Prepare handover; if both file and sector are loaded, sector must not be
+     * mmapped - if it is, then registers prepared for loaded file already
+     * point at the sector. */
+    if (iter->index && opt.hand && (((sidx < 0) ^ (fidx < 0)) || !opt.smap)) {
 	if (setup_handover(iter, data + ndata))
 	    goto bail;
 	hand_area = data[ndata].data;
 	/*
 	 * We have to make sure, that handover data doesn't overlap with the
-	 * file and/or the boot sector. For example, part of FreeDOS kernel
+	 * file or the sector. For example, part of FreeDOS kernel
 	 * loaded at 0x600 would conflict with the handover data. Handover
 	 * is not critical, so we can let it pass with a warning.
 	 */
 	if ( ( fidx < 0 || no_ov(data + fidx, data + ndata)) &&
-	     ( sidx < 0 || no_ov(data + sidx, data + ndata)) ) {
+	     ( sidx < 0 || !opt.smap || no_ov(data + sidx, data + ndata)) ) {
 	    /* If all is fine, prep registers and inc ndata */
-	    opt.regs.esi.w[0] = opt.regs.ebp.w[0] = 0x7be;
+	    opt.regs.esi.l = opt.regs.ebp.l = 0x7be;
 	    opt.regs.ds = 0;
 	    if(iter->type == typegpt)
 		opt.regs.eax.l = 0x54504721;	/* '!GPT' */


More information about the Syslinux-commits mailing list