aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Soltys <soltys@ziu.info>2010-08-21 22:31:22 +0200
committerMichal Soltys <soltys@ziu.info>2010-09-28 09:32:52 +0200
commiteaa567927d61f43dd28c0f78807a2a2ddf1eb541 (patch)
tree0f2f4387aa767b58fee70ac3773796977edba60c
parentb7aa5fbdee4d97c9a91a6ec04e073b2486bbd3db (diff)
downloadsyslinux-eaa567927d61f43dd28c0f78807a2a2ddf1eb541.tar.gz
syslinux-eaa567927d61f43dd28c0f78807a2a2ddf1eb541.tar.xz
syslinux-eaa567927d61f43dd28c0f78807a2a2ddf1eb541.zip
chain.c: Improve setdrv option, remove setbpb4/
Option 'setdrv' can autodetect offset now. setbpb4 is removed, as it's no longer necessary. Signed-off-by: Michal Soltys <soltys@ziu.info>
-rw-r--r--com32/chain/chain.c142
1 files changed, 106 insertions, 36 deletions
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index dc76e058..5af6c152 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -72,6 +72,7 @@ static struct options {
bool sect;
bool save;
bool filebpb;
+ bool warn;
uint16_t keeppxe;
struct syslinux_rm_regs regs;
} opt;
@@ -502,15 +503,18 @@ Usage:\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\
- nosetdrv[@<o>] Set BPB's drive unit field at <o>\n\
- - <o> defaults to 0x24\n\
+ nosetdrv[@<off>] Set BPB's drive unit field at <o>\n\
+ - <off> defaults to autodetection\n\
- only 0x24 and 0x40 are accepted\n\
+ nosetbpb Enable set{hid,geo,drv}\n\
nosave Write adjusted sector back to disk\n\
hand Prepare handover area\n\
- hptr Force ds:{si,bp} to always point to handover area\n\
+ nohptr Force ds:si and ds:bp to point to handover area\n\
noswap Swap drive numbers, if bootdisk is not fd0/hd0\n\
- nohide Hide primary partitions, except selected partition\n\
+ nohide Hide primary partitions, unhide selected partition\n\
nokeeppxe Keep the PXE and UNDI stacks in memory (PXELINUX)\n\
+ nowarn Wait for a keypress to continue chainloading\n\
+ - useful to see emited warnings\n\
", "\
\nComposite options:\n\
isolinux=<loader> Load another version of ISOLINUX\n\
@@ -541,6 +545,8 @@ static int parse_args(int argc, char *argv[])
for (i = 1; i < argc; i++) {
if (!strncmp(argv[i], "file=", 5)) {
opt.file = argv[i] + 5;
+ } 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))
goto bail;
@@ -576,11 +582,15 @@ static int parse_args(int argc, char *argv[])
opt.fseg = 0x60; /* FREEDOS wants this address */
opt.foff = 0;
opt.fip = 0;
+ opt.sseg = 0x9000;
+ opt.soff = 0;
+ opt.sip = 0;
opt.file = argv[i] + 8;
opt.sethid = true;
opt.setgeo = true;
+ opt.setdrv = true;
+ opt.drvoff = ~0u;
/* opt.save = true; */
- opt.maps = false;
opt.hand = false;
} else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
!strncmp(argv[i], "pcdos=", v)) ||
@@ -588,22 +598,30 @@ static int parse_args(int argc, char *argv[])
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.file = argv[i] + v;
opt.sethid = true;
opt.setgeo = true;
+ opt.setdrv = true;
+ opt.drvoff = ~0u;
/* opt.save = true; */
- opt.maps = false;
opt.hand = false;
} else if (!strncmp(argv[i], "drmk=", 5)) {
opt.fseg = 0x70; /* DRMK wants this address */
opt.foff = 0;
opt.fip = 0;
+ opt.sseg = 0x2000;
+ opt.soff = 0;
+ opt.sip = 0;
opt.file = argv[i] + 5;
- opt.drmk = true;
+ /* opt.drmk = true; */
opt.sethid = true;
opt.setgeo = true;
+ opt.setdrv = true;
+ opt.drvoff = ~0u;
/* opt.save = true; */
- opt.maps = false;
opt.hand = false;
} else if (!strncmp(argv[i], "grub=", 5)) {
opt.fseg = 0x800; /* stage2 wants this address */
@@ -656,23 +674,32 @@ static int parse_args(int argc, char *argv[])
opt.setgeo = false;
} else if (!strncmp(argv[i], "setdrv",6)) {
if (!argv[i][6])
- v = 0x24;
+ v = ~0u; /* autodetect */
else if (argv[i][6] == '@' ||
argv[i][6] == '=' ||
- argv[i][6] == ':')
+ argv[i][6] == ':') {
v = strtoul(argv[i] + 7, NULL, 0);
- else {
- error("Invalid 'setdrv' specification.\n");
- goto bail;
- }
- if (!(v == 0x24 || v == 0x40)) {
- error("Invalid 'setdrv' offset.\n");
- goto bail;
- }
+ if (!(v == 0x24 || v == 0x40)) {
+ error("Invalid 'setdrv' offset.\n");
+ goto bail;
+ }
+ } else {
+ error("Invalid 'setdrv' specification.\n");
+ goto bail;
+ }
opt.setdrv = true;
opt.drvoff = v;
} else if (!strcmp(argv[i], "nosetdrv")) {
opt.setdrv = false;
+ } else if (!strcmp(argv[i], "setbpb")) {
+ opt.setdrv = true;
+ opt.drvoff = ~0u;
+ opt.setgeo = true;
+ opt.sethid = true;
+ } else if (!strcmp(argv[i], "nosetbpb")) {
+ opt.setdrv = false;
+ opt.setgeo = false;
+ opt.sethid = false;
} else if (!strncmp(argv[i], "sect=", 5) ||
!strcmp(argv[i], "sect")) {
if (argv[i][4]) {
@@ -694,6 +721,10 @@ static int parse_args(int argc, char *argv[])
opt.filebpb = true;
} else if (!strcmp(argv[i], "nofilebpb")) {
opt.filebpb = false;
+ } else if (!strcmp(argv[i], "warn")) {
+ opt.warn = true;
+ } else if (!strcmp(argv[i], "nowarn")) {
+ opt.warn = false;
} else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
&& argv[i][1] == 'd')
|| !strncmp(argv[i], "mbr:", 4)
@@ -1267,6 +1298,33 @@ static int mangles_cmldr(struct data_area *data)
return 0;
}
+int setdrv_auto(const struct part_iter *iter)
+{
+ int a, b;
+ char *buf;
+
+ if (!(buf = disk_read_sectors(&iter->di, iter->start_lba, 1))) {
+ error("Couldn't read a sector to detect 'setdrv' offset.\n");
+ return -1;
+ }
+
+ a = strncmp(buf + 0x36, "FAT", 3);
+ b = strncmp(buf + 0x52, "FAT", 3);
+
+ if ((!a && b && (buf[0x26] & 0xFE) == 0x28) || *((uint8_t*)buf + 0x26) == 0x80) {
+ opt.drvoff = 0x24;
+ } else if (a && !b && (buf[0x42] & 0xFE) == 0x28) {
+ opt.drvoff = 0x40;
+ } else {
+ error("WARNING: Couldn't autodetect 'setdrv' offset - turning option off.\n");
+ opt.setdrv = false;
+ }
+
+ free(buf);
+ return 0;
+
+}
+
int main(int argc, char *argv[])
{
struct part_iter *iter = NULL;
@@ -1288,6 +1346,9 @@ int main(int argc, char *argv[])
opt.hand = true; /* by def prepare handover */
opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
opt.drivename = "boot";
+#ifdef DEBUG
+ opt.warn = true;
+#endif
/* Parse arguments */
if (parse_args(argc, argv))
@@ -1312,6 +1373,10 @@ int main(int argc, char *argv[])
if (find_dp(&iter))
goto bail;
+ /* Try to autodetect setdrv offest */
+ if (opt.setdrv && opt.drvoff == ~0u && setdrv_auto(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;
@@ -1374,6 +1439,24 @@ int main(int argc, char *argv[])
}
}
+ /*
+ * Adjust registers - ds:si & ds:bp
+ * We do it here, as they might get further
+ * overriden during mangling.
+ */
+
+ 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;
+ }
/* Do file related stuff */
@@ -1404,21 +1487,6 @@ int main(int argc, char *argv[])
goto bail;
}
- /* 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;
@@ -1435,12 +1503,14 @@ int main(int argc, char *argv[])
printf("iter lba: %llu\n", iter->start_lba);
if (hand_area)
printf("hand lba: %u\n", hand_area->start_lba);
- printf("Press any key to continue ...\n");
- wait_key();
#endif
- do_boot(bdata, ndata);
+ if (opt.warn) {
+ puts("Press any key to continue booting...");
+ wait_key();
+ }
+ do_boot(bdata, ndata);
bail:
pi_del(&iter);
/* Free allocated areas */