[syslinux:master] chain.c: change file/sect/ hand area handling logic, add 'hptr' option

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


Commit-ID:  b7aa5fbdee4d97c9a91a6ec04e073b2486bbd3db
Gitweb:     http://www.syslinux.org/commit/b7aa5fbdee4d97c9a91a6ec04e073b2486bbd3db
Author:     Michal Soltys <soltys at ziu.info>
AuthorDate: Sat, 21 Aug 2010 19:33:42 +0200
Committer:  Michal Soltys <soltys at ziu.info>
CommitDate: Tue, 28 Sep 2010 09:32:52 +0200

chain.c: change file/sect/hand area handling logic, add 'hptr' option

The logic behind file/sect/hand area handling is more flexible
now. Furthermore, a user can explicitly control where ds:si/ds:bp
should point during chainloading.

Other misc. changes:

- registry setup is more conservative
- 'if' style

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

---
 com32/chain/chain.c |  168 +++++++++++++++++++++++++++-----------------------
 1 files changed, 91 insertions(+), 77 deletions(-)

diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index 8a96da9..dc76e05 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -63,6 +63,7 @@ static struct options {
     bool grldr;
     bool maps;
     bool hand;
+    bool hptr;
     bool swap;
     bool hide;
     bool sethid;
@@ -173,12 +174,12 @@ static int find_by_guid(const struct guid *gpt_guid,
 	    continue;
 	}
 	/* Check for a matching GPT disk guid */
-	if(!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
+	if (!memcmp(&boot_part->sub.gpt.disk_guid, gpt_guid, sizeof(*gpt_guid))) {
 	    goto ok;
 	}
 	/* disk guid doesn't match, maybe partition guid will */
 	while (pi_next(&boot_part)) {
-	    if(!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
+	    if (!memcmp(&boot_part->sub.gpt.part_guid, gpt_guid, sizeof(*gpt_guid)))
 		goto ok;
 	}
     }
@@ -449,9 +450,9 @@ static int soi_s2n(char *ptr, unsigned int *seg,
     char *p;
 
     segval = strtoul(ptr, &p, 0);
-    if(*p == ':')
+    if (*p == ':')
 	offval = strtoul(p+1, &p, 0);
-    if(*p == ':')
+    if (*p == ':')
 	ipval = strtoul(p+1, NULL, 0);
 
     val = (segval << 4) + offval;
@@ -468,11 +469,11 @@ static int soi_s2n(char *ptr, unsigned int *seg,
 	goto bail;
     }
 
-    if(seg)
+    if (seg)
 	*seg = segval;
-    if(off)
+    if (off)
 	*off = offval;
-    if(ip)
+    if (ip)
 	*ip  = ipval;
 
     return 0;
@@ -505,7 +506,8 @@ Usage:\n\
                          - <o> defaults to 0x24\n\
                          - only 0x24 and 0x40 are accepted\n\
     nosave               Write adjusted sector back to disk\n\
-    hand                 Prepare handover data\n\
+    hand                 Prepare handover area\n\
+    hptr                 Force ds:{si,bp} to always point to handover area\n\
     noswap               Swap drive numbers, if bootdisk is not fd0/hd0\n\
     nohide               Hide primary partitions, except selected partition\n\
     nokeeppxe            Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
@@ -540,7 +542,7 @@ static int parse_args(int argc, char *argv[])
 	if (!strncmp(argv[i], "file=", 5)) {
 	    opt.file = argv[i] + 5;
 	} 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))
 		goto bail;
 	} else if (!strncmp(argv[i], "isolinux=", 9)) {
 	    opt.file = argv[i] + 9;
@@ -630,6 +632,10 @@ static int parse_args(int argc, char *argv[])
 	    opt.hand = true;
 	} else if (!strcmp(argv[i], "nohand")) {
 	    opt.hand = false;
+	} else if (!strcmp(argv[i], "hptr")) {
+	    opt.hptr = true;
+	} else if (!strcmp(argv[i], "nohptr")) {
+	    opt.hptr = false;
 	} else if (!strcmp(argv[i], "swap")) {
 	    opt.swap = true;
 	} else if (!strcmp(argv[i], "noswap")) {
@@ -649,9 +655,9 @@ static int parse_args(int argc, char *argv[])
 	} else if (!strcmp(argv[i], "nosetgeo")) {
 	    opt.setgeo = false;
 	} else if (!strncmp(argv[i], "setdrv",6)) {
-	    if(!argv[i][6])
+	    if (!argv[i][6])
 		v = 0x24;
-	    else if(argv[i][6] == '@' ||
+	    else if (argv[i][6] == '@' ||
 		    argv[i][6] == '=' ||
 		    argv[i][6] == ':')
 		v = strtoul(argv[i] + 7, NULL, 0);
@@ -672,7 +678,7 @@ static int parse_args(int argc, char *argv[])
 	    if (argv[i][4]) {
 		if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip))
 		    goto bail;
-		if((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
+		if ((opt.sseg << 4) + opt.soff + SECTOR - 1 > ADDRMAX) {
 		    error("Arguments of 'sect=' are invalid - resulting address too big.\n");
 		    goto bail;
 		}
@@ -789,7 +795,7 @@ int find_dp(struct part_iter **_iter)
 	}
 #if 0
 	/* offsets match, but in case it changes in the future */
-	if(sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
+	if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
 	    drive = sdi->iso.drive_number;
 	    fs_lba = *sdi->iso.partoffset;
 	} else {
@@ -843,9 +849,6 @@ int find_dp(struct part_iter **_iter)
 	error("WARNING: Partitions on floppy devices may not work.\n");
     }
 
-    /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
-    opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
-
     *_iter = iter;
 
     return 0;
@@ -941,7 +944,7 @@ static int manglef_grldr(const struct part_iter *iter)
 /*
  * Legacy grub's stage2 chainloading
  */
-static int manglef_grublegacy(const struct part_iter *iter, struct data_area *data)
+static int manglef_grub(const struct part_iter *iter, struct data_area *data)
 {
     /* Layout of stage2 file (from byte 0x0 to 0x270) */
     struct grub_stage2_patch_area {
@@ -1091,7 +1094,7 @@ out:
     return h | (s << 8) | ((c & 0x300) << 6) | ((c & 0xFF) << 16);
 
 fallback:
-    if(di->disk & 0x80)
+    if (di->disk & 0x80)
 	return 0x00FFFFFE; /* 1023/63/254 */
     else
 	/* FIXME ?
@@ -1188,7 +1191,7 @@ static int manglef_bpb(const struct part_iter *iter, struct data_area *data)
 {
     /* BPB: hidden sectors */
     if (opt.sethid) {
-	if(iter->start_lba < ~0u)
+	if (iter->start_lba < ~0u)
 	    *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
 	else
 	    /* won't really help much, but ... */
@@ -1196,10 +1199,10 @@ static int manglef_bpb(const struct part_iter *iter, struct data_area *data)
     }
     /* BPB: legacy geometry */
     if (opt.setgeo) {
-	if(iter->di.cbios)
+	if (iter->di.cbios)
 	    *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.sect);
 	else {
-	    if(iter->di.disk & 0x80)
+	    if (iter->di.disk & 0x80)
 		*(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
 	    else
 		*(uint32_t *)((char *)data->data + 0x18) = 0x00020012;
@@ -1214,7 +1217,7 @@ static int manglef_bpb(const struct part_iter *iter, struct data_area *data)
     return 0;
 }
 
-static int try_sector_bpb(const struct part_iter *iter, struct data_area *data)
+static int try_mangles_bpb(const struct part_iter *iter, struct data_area *data)
 {
     void *cmp_buf = NULL;
 
@@ -1264,7 +1267,6 @@ static int mangles_cmldr(struct data_area *data)
     return 0;
 }
 
-
 int main(int argc, char *argv[])
 {
     struct part_iter *iter = NULL;
@@ -1273,8 +1275,8 @@ int main(int argc, char *argv[])
     void *sect_area = NULL;
     struct disk_dos_part_entry *hand_area = NULL;
 
-    struct data_area data[3];
-    int ndata = 0, fidx = -1, sidx = -1;
+    struct data_area data[3], bdata[3];
+    int ndata = 0, fidx = -1, sidx = -1, hidx = -1;
 
     console_ansi_raw();
 /*    openconsole(&dev_null_r, &dev_stdcon_w);*/
@@ -1288,70 +1290,91 @@ int main(int argc, char *argv[])
     opt.drivename = "boot";
 
     /* Parse arguments */
-    if(parse_args(argc, argv))
+    if (parse_args(argc, argv))
 	goto bail;
 
-    /* Set initial registry values, file takes precedence */
-    if(opt.file) {
-	opt.regs.es = opt.regs.cs = opt.regs.ss =
-	    opt.regs.ds = opt.regs.fs = opt.regs.gs = (uint16_t)opt.fseg;
+    /* Set initial registry values */
+    if (opt.file) {
+	opt.regs.cs = opt.regs.ds = opt.regs.ss = (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 = (uint16_t)opt.sseg;
+	opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
 	opt.regs.ip = (uint16_t)opt.sip;
     }
-    if(opt.regs.ip == 0x7C00 && !opt.regs.cs)
+
+    if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
 	opt.regs.esp.l = 0x7C00;
 
     /* Get max fixed disk number */
-
     fixed_cnt = *(uint8_t *)(0x475);
 
     /* Get disk/part iterator matching user supplied options */
-    if(find_dp(&iter))
+    if (find_dp(&iter))
 	goto bail;
 
+    /* DOS kernels want the drive number in BL instead of DL. Indulge them. */
+    opt.regs.ebx.b[0] = opt.regs.edx.b[0] = (uint8_t)iter->di.disk;
+
     /* Do hide / unhide if appropriate */
     if (opt.hide)
 	hide_unhide(iter);
 
-    /* Load file and sector */
-
+    /* Load the boot file */
     if (opt.file) {
 	data[ndata].base = (opt.fseg << 4) + opt.foff;
+
 	if (loadfile(opt.file, &data[ndata].data, &data[ndata].size)) {
 	    error("Couldn't read the boot file.\n");
 	    goto bail;
 	}
+	file_area = (void *)data[ndata].data;
+
 	if (data[ndata].base + data[ndata].size - 1 > ADDRMAX) {
 	    error("The boot file is too big to load at this address.\n");
 	    goto bail;
 	}
 
-	file_area = (void *)data[ndata].data;
 	fidx = ndata;
 	ndata++;
     }
 
+    /* Load the sector */
     if (opt.sect) {
 	data[ndata].size = SECTOR;
 	data[ndata].base = (opt.sseg << 4) + opt.soff;
+
 	if (opt.file && opt.maps && !no_ov(data + fidx, data + ndata)) {
-	    error("WARNING: Sector won't be loaded, as it would conflict with the boot file.\n");
+	    error("WARNING: The sector won't be loaded, as it would conflict with the boot file.\n");
 	} else {
 	    if (!(data[ndata].data = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
 		error("Couldn't read the sector.\n");
 		goto bail;
 	    }
 	    sect_area = (void *)data[ndata].data;
+
 	    sidx = ndata;
-	    if(opt.maps) {
-		ndata++;
-	    }
+	    ndata++;
 	}
     }
 
+    /* Prep the handover */
+    if (opt.hand && iter->index) {
+	if (setup_handover(iter, data + ndata))
+	    goto bail;
+	hand_area = (void *)data[ndata].data;
+
+	/* Verify possible conflicts */
+	if ( ( fidx >= 0 && !no_ov(data + fidx, data + ndata)) ||
+	     ( sidx >= 0 && opt.maps && !no_ov(data + sidx, data + ndata)) ) {
+	    error("WARNING: Handover area won't be prepared,\n"
+		  "as it would conflict with the boot file and/or the sector.\n");
+	} else {
+	    hidx = ndata;
+	    ndata++;
+	}
+    }
+
+
     /* Do file related stuff */
 
     if (fidx >= 0) {
@@ -1361,7 +1384,7 @@ int main(int argc, char *argv[])
 	if (opt.grldr && manglef_grldr(iter))
 	    goto bail;
 
-	if (opt.grub && manglef_grublegacy(iter, data + fidx))
+	if (opt.grub && manglef_grub(iter, data + fidx))
 	    goto bail;
 
 	if (opt.drmk && manglef_drmk(data + fidx))
@@ -1374,47 +1397,38 @@ int main(int argc, char *argv[])
     /* Do sector related stuff */
 
     if (sidx >= 0) {
-	if (try_sector_bpb(iter, data + sidx))
+	if (try_mangles_bpb(iter, data + sidx))
 	    goto bail;
 
 	if (opt.cmldr && mangles_cmldr(data + sidx))
 	    goto bail;
-
-	if (opt.maps && 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; 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.maps)) {
-	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 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 || !opt.maps || no_ov(data + sidx, data + ndata)) ) {
-	    /* If all is fine, prep registers and inc ndata */
-	    opt.regs.esi.l = opt.regs.ebp.l = (uint16_t)data[ndata].base;
-	    opt.regs.ds = 0;
-	    if(iter->type == typegpt)
-		opt.regs.eax.l = 0x54504721;	/* '!GPT' */
-	    ndata++;
-	} else {
-	    error("WARNING: Handover ignored due to overlapping regions.\n");
-	}
+    /* Adjust registers - ds:si & ds:bp */
+
+    if (sidx >= 0 && fidx >= 0 && opt.maps && !opt.hptr) {
+	opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
+	opt.regs.ds = (uint16_t)opt.sseg;
+	opt.regs.eax.l = 0;
+    } else if (hidx >= 0) {
+	opt.regs.esi.l = opt.regs.ebp.l = data[hidx].base;
+	opt.regs.ds = 0;
+	if (iter->type == typegpt)
+	    opt.regs.eax.l = 0x54504721;	/* '!GPT' */
+	else
+	    opt.regs.eax.l = 0;
     }
 
+    /* Prepare boot-time mmap data */
+
+    ndata = 0;
+    if (sidx >= 0)
+	memcpy(bdata + ndata++, data + sidx, sizeof(struct data_area));
+    if (fidx >= 0)
+	memcpy(bdata + ndata++, data + fidx, sizeof(struct data_area));
+    if (hidx >= 0)
+	memcpy(bdata + ndata++, data + hidx, sizeof(struct data_area));
+
 #ifdef DEBUG
     printf("iter dsk: %d\n", iter->di.disk);
     printf("iter idx: %d\n", iter->index);
@@ -1425,7 +1439,7 @@ int main(int argc, char *argv[])
     wait_key();
 #endif
 
-    do_boot(data, ndata);
+    do_boot(bdata, ndata);
 
 bail:
     pi_del(&iter);


More information about the Syslinux-commits mailing list