diff options
Diffstat (limited to 'com32/chain/mangle.c')
-rw-r--r-- | com32/chain/mangle.c | 226 |
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: */ |