summaryrefslogtreecommitdiff
path: root/com32/chain/mangle.c
diff options
context:
space:
mode:
authorMichal Soltys <soltys@ziu.info>2010-08-28 01:06:13 +0200
committerMichal Soltys <soltys@ziu.info>2010-09-28 09:32:52 +0200
commit0d591b9348e43cf59cd4857dcc0e9029566d96e5 (patch)
tree5916f3f441a6cca1434c3f44ffe12f55feba774e /com32/chain/mangle.c
parent32bcebfdcf56da6b27688d2b78dc42ef59453dd0 (diff)
downloadsyslinux-0d591b9348e43cf59cd4857dcc0e9029566d96e5.tar.gz
chain module: setbpb changes, bss & bs options, bugfixes
Generic function detecting BPB type (7 versions) have been added. set{hid,geo,drv} have been replaced by single setbpb option, using mentioned function to make more precise decisions what to update where. Full BSS and BS emulation has been added, also employing BPB detection. Some logic/flow changes in chain's main(). There was also a bug, in which backup sector was populated with wrong data. Appropriate documentation updates. Signed-off-by: Michal Soltys <soltys@ziu.info>
Diffstat (limited to 'com32/chain/mangle.c')
-rw-r--r--com32/chain/mangle.c226
1 files changed, 170 insertions, 56 deletions
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index 3ddff716..34b033e9 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -6,6 +6,7 @@
#include <syslinux/config.h>
#include "common.h"
#include "chain.h"
+#include "options.h"
#include "utility.h"
#include "partiter.h"
#include "mangle.h"
@@ -24,7 +25,7 @@ int manglef_isolinux(struct data_area *data)
uint32_t *checksum, *chkhead, *chktail;
uint32_t file_lba = 0;
- if (!opt.isolinux)
+ if (!(opt.file && opt.isolinux))
return 0;
sdi = syslinux_derivative_info();
@@ -88,21 +89,6 @@ bail:
}
/*
- * GRLDR of GRUB4DOS wants the partition number in DH:
- * -1: whole drive (default)
- * 0-3: primary partitions
- * 4-*: logical partitions
- */
-int manglef_grldr(const struct part_iter *iter)
-{
- if (!opt.grldr)
- return 0;
-
- opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
- return 0;
-}
-
-/*
* Legacy grub's stage2 chainloading
*/
int manglef_grub(const struct part_iter *iter, struct data_area *data)
@@ -142,7 +128,7 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
char codestart[1];
} __attribute__ ((packed)) *stage2;
- if (!opt.grub)
+ if (!(opt.file && opt.grub))
return 0;
if (data->size < sizeof(struct grub_stage2_patch_area)) {
@@ -207,22 +193,62 @@ int manglef_grub(const struct part_iter *iter, struct data_area *data)
bail:
return -1;
}
-
+#if 0
/*
- * Adjust BPB of a BPB-compatible file
+ * Dell's DRMK chainloading.
*/
-int mangles_bpb(const struct part_iter *iter, struct data_area *data)
+int manglef_drmk(struct data_area *data)
+{
+ /*
+ * DRMK entry is different than MS-DOS/PC-DOS
+ * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
+ * We only really need 4 new, usable bytes at the end.
+ */
+
+ if (!(opt.file && opt.drmk))
+ return 0;
+
+ uint32_t tsize = (data->size + 19) & 0xfffffff0;
+ opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
+ if (!realloc(data->data, tsize)) {
+ error("Failed to realloc for DRMK.\n");
+ goto bail;
+ }
+ data->size = tsize;
+ /* ds:[bp+28] must be 0x0000003f */
+ 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;
+
+ return 0;
+bail:
+ return -1;
+}
+#endif
+/* Adjust BPB common function */
+static int mangle_bpb(const struct part_iter *iter, struct data_area *data)
{
- /* BPB: hidden sectors */
- if (opt.sethid) {
+ unsigned int off;
+ int type = bpb_detect(data->data);
+
+ /* BPB: hidden sectors 32bit*/
+ if (type >= bpbV34) {
if (iter->start_lba < ~0u)
*(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
else
/* won't really help much, but ... */
*(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
}
+ /* BPB: hidden sectors 16bit*/
+ if (bpbV30 <= type && type <= bpbV32) {
+ if (iter->start_lba < 0xFFFF)
+ *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)iter->start_lba;
+ else
+ /* won't really help much, but ... */
+ *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
+ }
/* BPB: legacy geometry */
- if (opt.setgeo) {
+ if (type >= bpbV30) {
if (iter->di.cbios)
*(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.sect);
else {
@@ -233,24 +259,91 @@ int mangles_bpb(const struct part_iter *iter, struct data_area *data)
}
}
/* BPB: drive */
- if (opt.setdrv)
- *(uint8_t *)((char *)data->data + opt.drvoff) = (uint8_t)
+ if (drvoff_detect(type, &off)) {
+ *(uint8_t *)((char *)data->data + off) = (uint8_t)
(opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
+ }
return 0;
}
+/*
+ * Adjust BPB of a BPB-compatible file
+ */
int manglef_bpb(const struct part_iter *iter, struct data_area *data)
{
- if (!opt.filebpb)
+ if (!(opt.file && opt.filebpb))
+ return 0;
+
+ return mangle_bpb(iter, data);
+}
+
+/*
+ * Adjust BPB of a sector
+ */
+int mangles_bpb(const struct part_iter *iter, struct data_area *data)
+{
+ if (!(opt.sect && opt.setbpb))
+ return 0;
+
+ return mangle_bpb(iter, data);
+}
+
+/*
+ * This function performs full BPB patching, analogously to syslinux's
+ * native BSS. opt.drv is prereq
+ */
+int manglesf_bss(struct data_area *sec, struct data_area *fil)
+{
+ int type1, type2;
+ unsigned int cnt = 0;
+
+ if (!(opt.sect && opt.file && opt.bss))
return 0;
- return mangles_bpb(iter, data);
+ type1 = bpb_detect(fil->data);
+ type2 = bpb_detect(sec->data);
+
+ if (type1 < 0 || type2 < 0) {
+ error("Option 'bss' can't determine BPB type.\n");
+ goto bail;
+ }
+ if (type1 != type2) {
+ error("Option 'bss' can't be used,\n"
+ "when a sector and a file have incompatible BPBs.\n");
+ goto bail;
+ }
+
+ /* Copy common 2.0 data */
+ memcpy((char *)fil->data + 0x0B, (char *)sec->data + 0x0B, 0x0D);
+
+ /* Copy 3.0+ data */
+ if (type1 <= bpbV30) {
+ cnt = 0x06;
+ } else if (type1 <= bpbV32) {
+ cnt = 0x08;
+ } else if (type1 <= bpbV34) {
+ cnt = 0x0C;
+ } else if (type1 <= bpbV40) {
+ cnt = 0x2E;
+ } else if (type1 <= bpbVNT) {
+ cnt = 0x3C;
+ } else if (type1 <= bpbV70) {
+ cnt = 0x42;
+ }
+ memcpy((char *)fil->data + 0x18, (char *)sec->data + 0x18, cnt);
+
+ return 0;
+bail:
+ return -1;
}
+/*
+ * Save sector.
+ */
int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org)
{
- if (!opt.save)
+ if (!(opt.sect && opt.save))
return 0;
if (memcmp(org, data->data, data->size)) {
@@ -258,12 +351,11 @@ int mangles_save(const struct part_iter *iter, const struct data_area *data, voi
error("Cannot write the updated sector.\n");
goto bail;
}
- /* function is ready do be called again */
+ /* function can be called again */
memcpy(org, data->data, data->size);
}
return 0;
-
bail:
return -1;
}
@@ -275,44 +367,66 @@ bail:
*/
int mangles_cmldr(struct data_area *data)
{
- if (!opt.cmldr)
+ if (!(opt.sect && opt.cmldr))
return 0;
memcpy((char *)data->data + 3, cmldr_signature, sizeof(cmldr_signature));
return 0;
}
-#if 0
-/*
- * Dell's DRMK chainloading.
- */
-int manglef_drmk(struct data_area *data)
+/* Set common registers */
+int mangler_common(const struct part_iter *iter)
{
- /*
- * DRMK entry is different than MS-DOS/PC-DOS
- * A new size, aligned to 16 bytes to ease use of ds:[bp+28].
- * We only really need 4 new, usable bytes at the end.
- */
+ /* 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.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
+ opt.regs.ip = (uint16_t)opt.sip;
+ }
- if (!opt.drmk)
- return 0;
+ if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
+ opt.regs.esp.l = 0x7C00;
- uint32_t tsize = (data->size + 19) & 0xfffffff0;
- opt.regs.ss = opt.regs.fs = opt.regs.gs = 0; /* Used before initialized */
- if (!realloc(data->data, tsize)) {
- error("Failed to realloc for DRMK.\n");
- 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;
+
+ return 0;
+}
+
+/* ds:si & ds:bp */
+int mangler_handover(const struct part_iter *iter, const struct data_area *data)
+{
+ if (opt.sect && opt.file && 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 (opt.hand) {
+ /* base is really 0x7be */
+ opt.regs.esi.l = opt.regs.ebp.l = data->base;
+ opt.regs.ds = 0;
+ if (iter->type == typegpt)
+ opt.regs.eax.l = 0x54504721; /* '!GPT' */
+ else
+ opt.regs.eax.l = 0;
}
- data->size = tsize;
- /* ds:[bp+28] must be 0x0000003f */
- 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;
return 0;
-bail:
- return -1;
}
-#endif
+
+/*
+ * GRLDR of GRUB4DOS wants the partition number in DH:
+ * -1: whole drive (default)
+ * 0-3: primary partitions
+ * 4-*: logical partitions
+ */
+int mangler_grldr(const struct part_iter *iter)
+{
+ if (opt.grldr)
+ opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
+
+ return 0;
+}
/* vim: set ts=8 sts=4 sw=4 noet: */