include $(MAKEDIR)/elf.mk
OBJS = chain.o partiter.o utility.o options.o mangle.o
+CFLAGS += -fno-strict-aliasing
all: chain.c32
/* Mapping table; start out with identity mapping everything */
for (i = 0; i < 256; i++)
- p[i] = (uint8_t)i;
+ p[i] = i;
/* And the actual swap */
p[driveno] = swapdrive;
p[swapdrive] = driveno;
/* Adjust registers */
- opt.regs.ds = opt.regs.cs = (uint16_t)(endimage >> 4);
+ opt.regs.ds = opt.regs.cs = endimage >> 4;
opt.regs.esi.l = opt.regs.es = 0;
opt.regs.ecx.l = sizeof swapstub >> 2;
opt.regs.ip = 0x10; /* Installer offset */
struct data_area *data)
{
struct disk_dos_part_entry *ha;
- uint32_t synth_size;
- uint32_t *plen;
+ uint32_t synth_size = sizeof *ha;
- if (!iter->index) { /* implies typeraw or non-iterated */
+ /*
+ * we have to cover both non-iterated but otherwise properly detected
+ * gpt/dos schemes as well as raw disks; checking index for 0 covers both
+ */
+ if (iter->index == 0) {
uint32_t len;
/* RAW handover protocol */
- synth_size = sizeof(struct disk_dos_part_entry);
ha = malloc(synth_size);
if (!ha) {
error("Could not build RAW hand-over record!\n");
}
len = ~0u;
if (iter->length < len)
- len = (uint32_t)iter->length;
- lba2chs(&ha->start, &iter->di, 0, l2c_cadd);
- lba2chs(&ha->end, &iter->di, len - 1, l2c_cadd);
+ len = iter->length;
+ lba2chs(&ha->start, &iter->di, 0, L2C_CADD);
+ lba2chs(&ha->end, &iter->di, len - 1, L2C_CADD);
ha->active_flag = 0x80;
ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */
ha->start_lba = 0;
ha->length = len;
} else if (iter->type == typegpt) {
+ uint32_t *plen;
/* GPT handover protocol */
- synth_size = sizeof(struct disk_dos_part_entry) +
- sizeof(uint32_t) + (uint32_t)iter->sub.gpt.pe_size;
+ synth_size += sizeof *plen + iter->sub.gpt.pe_size;
ha = malloc(synth_size);
if (!ha) {
error("Could not build GPT hand-over record!\n");
goto bail;
}
- lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
- lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
+ lba2chs(&ha->start, &iter->di, iter->start_lba, L2C_CADD);
+ lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, L2C_CADD);
ha->active_flag = 0x80;
ha->ostype = 0xED;
/* All bits set by default */
ha->length = ~0u;
/* If these fit the precision, pass them on */
if (iter->start_lba < ha->start_lba)
- ha->start_lba = (uint32_t)iter->start_lba;
+ ha->start_lba = iter->start_lba;
if (iter->length < ha->length)
- ha->length = (uint32_t)iter->length;
+ ha->length = iter->length;
/* Next comes the GPT partition record length */
- plen = (uint32_t *) (ha + 1);
- plen[0] = (uint32_t)iter->sub.gpt.pe_size;
+ plen = (uint32_t *)(ha + 1);
+ plen[0] = iter->sub.gpt.pe_size;
/* Next comes the GPT partition record copy */
memcpy(plen + 1, iter->record, plen[0]);
#ifdef DEBUG
disk_dos_part_dump(ha);
disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1));
#endif
+ /* the only possible case left is dos scheme */
} else if (iter->type == typedos) {
/* MBR handover protocol */
- synth_size = sizeof(struct disk_dos_part_entry);
ha = malloc(synth_size);
if (!ha) {
error("Could not build MBR hand-over record!\n");
}
memcpy(ha, iter->record, synth_size);
/* make sure these match bios imaginations and are ebr agnostic */
- lba2chs(&ha->start, &iter->di, iter->start_lba, l2c_cadd);
- lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, l2c_cadd);
- ha->start_lba = (uint32_t)iter->start_lba;
- ha->length = (uint32_t)iter->length;
+ lba2chs(&ha->start, &iter->di, iter->start_lba, L2C_CADD);
+ lba2chs(&ha->end, &iter->di, iter->start_lba + iter->length - 1, L2C_CADD);
+ ha->start_lba = iter->start_lba;
+ ha->length = iter->length;
#ifdef DEBUG
dprintf("MBR handover:\n");
* 0-3: primary partitions
* 4-*: logical partitions
*/
- stage2->install_partition.part1 = (uint8_t)(iter->index - 1);
+ stage2->install_partition.part1 = iter->index - 1;
/*
* Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
data->size = tsize;
/* ds:bp is assumed by DRMK to be the boot sector */
/* offset 28 is the FAT HiddenSectors value */
- opt.regs.ds = (uint16_t)((tsize >> 4) + (opt.fseg - 2));
+ opt.regs.ds = (tsize >> 4) + (opt.fseg - 2);
/* "Patch" into tail of the new space */
- *(uint32_t *)((char*)data->data + tsize - 4) = (uint32_t)fs_lba;
+ *(uint32_t *)((char*)data->data + tsize - 4) = fs_lba;
return 0;
bail:
/* BPB: hidden sectors 32bit*/
if (type >= bpbV34) {
if (iter->start_lba < ~0u)
- *(uint32_t *) ((char *)data->data + 0x1c) = (uint32_t)iter->start_lba;
+ *(uint32_t *) ((char *)data->data + 0x1c) = 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;
+ *(uint16_t *) ((char *)data->data + 0x1c) = iter->start_lba;
else
/* won't really help much, but ... */
*(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
/* BPB: legacy geometry */
if (type >= bpbV30) {
if (iter->di.cbios)
- *(uint32_t *)((char *)data->data + 0x18) = (uint32_t)((iter->di.head << 16) | iter->di.spt);
+ *(uint32_t *)((char *)data->data + 0x18) = (iter->di.head << 16) | iter->di.spt;
else {
if (iter->di.disk & 0x80)
*(uint32_t *)((char *)data->data + 0x18) = 0x00FF003F;
}
/* BPB: drive */
if (drvoff_detect(type, &off)) {
- *(uint8_t *)((char *)data->data + off) = (uint8_t)
- (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
+ *(uint8_t *)((char *)data->data + off) = (opt.swap ? iter->di.disk & 0x80 : iter->di.disk);
}
return 0;
{
/* 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;
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.fseg;
+ opt.regs.ip = opt.fip;
} else {
- opt.regs.cs = opt.regs.ds = opt.regs.ss = (uint16_t)opt.sseg;
- opt.regs.ip = (uint16_t)opt.sip;
+ opt.regs.cs = opt.regs.ds = opt.regs.ss = opt.sseg;
+ opt.regs.ip = opt.sip;
}
if (opt.regs.ip == 0x7C00 && !opt.regs.cs)
opt.regs.esp.l = 0x7C00;
/* 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;
+ opt.regs.ebx.b[0] = opt.regs.edx.b[0] = iter->di.disk;
return 0;
}
{
if (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.ds = opt.sseg;
opt.regs.eax.l = 0;
} else if (opt.hand) {
/* base is really 0x7be */
int mangler_grldr(const struct part_iter *iter)
{
if (opt.grldr)
- opt.regs.edx.b[1] = (uint8_t)(iter->index - 1);
+ opt.regs.edx.b[1] = iter->index - 1;
return 0;
}
if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
/* It's a hideable partition type */
if (miter->index == iter->index || opt.hide & 4)
- t &= (uint8_t)(~0x10u); /* unhide */
+ t &= ~0x10u; /* unhide */
else
t |= 0x10u; /* hide */
}
ochs1 = *(uint32_t *)dp->start;
ochs2 = *(uint32_t *)dp->end;
- lba2chs(&dp->start, di, lba1, l2c_cadd);
- lba2chs(&dp->end, di, lba1 + dp->length - 1, l2c_cadd);
+ lba2chs(&dp->start, di, lba1, L2C_CADD);
+ lba2chs(&dp->end, di, lba1 + dp->length - 1, L2C_CADD);
return
*(uint32_t *)dp->start != ochs1 ||
ridx = iter->rawindex;
dp = (struct disk_dos_part_entry *)iter->record;
- wb |= mpe_setchs(&iter->di, dp, (uint32_t)iter->start_lba);
+ wb |= mpe_setchs(&iter->di, dp, iter->start_lba);
if (ridx > 4)
wb |= mpe_setchs(&iter->di, dp + 1, iter->sub.dos.nebr_lba);
int opt_parse_args(int argc, char *argv[])
{
int i;
- unsigned int v;
+ size_t v;
char *p;
for (i = 1; i < argc; i++) {
opt.bss = true;
opt.maps = false;
opt.setbpb = true;
- /* opt.save = true; */
} else if (!strncmp(argv[i], "bs=", 3)) {
opt.file = argv[i] + 3;
opt.sect = false;
opt.fip = 0;
opt.file = argv[i] + 6;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "reactos=", 8)) {
/*
opt.fip = 0x8100;
opt.file = argv[i] + 8;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "cmldr=", 6)) {
opt.fseg = 0x2000; /* CMLDR wants this address */
opt.file = argv[i] + 6;
opt.cmldr = true;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "freedos=", 8)) {
opt.fseg = 0x60; /* FREEDOS wants this address */
opt.sseg = 0x1FE0;
opt.file = argv[i] + 8;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
!strncmp(argv[i], "pcdos=", v)) ||
opt.sseg = 0x8000;
opt.file = argv[i] + v;
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "drmk=", 5)) {
opt.fseg = 0x70; /* DRMK wants this address */
opt.file = argv[i] + 5;
/* opt.drmk = true; */
opt.setbpb = true;
- /* opt.save = true; */
opt.hand = false;
} else if (!strncmp(argv[i], "grub=", 5)) {
opt.fseg = 0x800; /* stage2 wants this address */
goto bail;
}
-#if 0
- if ((!opt.maps || !opt.sect) && !opt.file) {
- error("You have to load something.\n");
- goto bail;
- }
-#endif
-
if (opt.filebpb && !opt.file) {
error("Option 'filebpb' requires a file.\n");
goto bail;
error("Invalid GPT header's values.\n");
goto bail;
}
- if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) {
+ if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) {
error("Couldn't read GPT partition list.\n");
goto bail;
}
error("WARNING: GPT partition list checksum invalid, trying backup.\n");
free(gptl);
/* secondary array directly precedes secondary header */
- if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) {
+ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) {
error("Couldn't read backup GPT partition list.\n");
goto bail;
}
- if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) {
+ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
error("Backup GPT partition list checksum invalid.\n");
goto bail;
}
[7] = "7.0",
};
-void error(const char *msg)
-{
- fputs(msg, stderr);
-}
-
-int guid_is0(const struct guid *guid)
-{
- return !*(const uint64_t *)guid && !*((const uint64_t *)guid + 1);
-}
-
void wait_key(void)
{
int cnt;
} while (!cnt || (cnt < 0 && errno == EAGAIN));
}
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode)
+int guid_is0(const struct guid *guid)
+{
+ return
+ !(guid->data1 ||
+ guid->data2 ||
+ guid->data3 ||
+ guid->data4);
+}
+
+/*
+ * mode explanation:
+ *
+ * cnul - "strict" mode, never returning higher value than obtained from cbios
+ * cadd - if the disk is larger than reported geometry /and/ if the geometry has
+ * less cylinders than 1024 - it means that the total size is somewhere
+ * between cs and cs+1; in this particular case, we bump the cs to be able
+ * to return matching chs triplet
+ * cmax - assume we can use any cylinder value
+ *
+ * by default cadd seems most reasonable, giving consistent results with e.g.
+ * sfdisk's behavior
+ */
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode)
{
uint32_t c, h, s, t;
uint32_t cs, hs, ss;
cs = di->cyl;
hs = di->head;
ss = di->spt;
- if (mode == l2c_cadd && cs < 1024 && di->lbacnt > cs*hs*ss)
- cs++;
- else if (mode == l2c_cmax)
+ if (mode == L2C_CADD) {
+ if (cs < 1024 && di->lbacnt > cs*hs*ss)
+ cs++;
+ } else if (mode == L2C_CMAX)
cs = 1024;
} else {
if (di->disk & 0x80) {
h = hs - 1;
c = cs - 1;
} else {
- s = ((uint32_t)lba % ss) + 1;
- t = (uint32_t)lba / ss;
+ s = (lba % ss) + 1;
+ t = lba / ss;
h = t % hs;
c = t / hs;
}
#define COM32_CHAIN_UTILITY_H
#include <stdint.h>
+#include <stdio.h>
#include <syslinux/disk.h>
#define bpbUNK 0
#define bpbVNT 6
#define bpbV70 7
-#define l2c_cnul 0
-#define l2c_cadd 1
-#define l2c_cmax 2
+/* see utility.c for details */
+enum {L2C_CNUL, L2C_CADD, L2C_CMAX};
-void error(const char *msg);
-int guid_is0(const struct guid *guid);
void wait_key(void);
-void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, uint32_t mode);
+void lba2chs(disk_chs *dst, const struct disk_info *di, uint64_t lba, int mode);
uint32_t get_file_lba(const char *filename);
int drvoff_detect(int type, unsigned int *off);
int bpb_detect(const uint8_t *bpb, const char *tag);
+int guid_is0(const struct guid *guid);
+
+static inline
+void error(const char *msg)
+{
+ fputs(msg, stderr);
+}
#endif