Index: bootcd/isolinux/syslinux-6.03/com32/chain/Makefile
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/Makefile	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/Makefile	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,43 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
+##   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+##   Copyright 2010 Shao Miller
+##   Copyright 2010-2012 Michal Soltys
+##
+##   This program is free software; you can redistribute it and/or modify
+##   it under the terms of the GNU General Public License as published by
+##   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+##   Boston MA 02111-1307, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+VPATH = $(SRC)
+include $(MAKEDIR)/elf.mk
+
+OBJS = chain.o partiter.o utility.o options.o mangle.o
+CFLAGS += -fno-strict-aliasing
+
+all: chain.c32
+
+chain.elf: $(OBJS) $(C_LIBS)
+	$(LD) $(LDFLAGS) -o $@ $^
+
+%.o: %.c
+	$(CC) $(MAKEDEPS) $(CFLAGS) $(CHAINEXTOPT) -c -o $@ $<
+
+tidy dist:
+	rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+	rm -f *.lnx
+
+spotless: clean
+	rm -f *.lss *.c32 *.com
+	rm -f *~ \#*
+
+install:
+
+
+-include .*.d
Index: bootcd/isolinux/syslinux-6.03/com32/chain/chain.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/chain.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/chain.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,643 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * Please see doc/chain.txt for the detailed documentation.
+ */
+
+#include <com32.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <console.h>
+#include <consoles.h>
+#include <minmax.h>
+#include <stdbool.h>
+#include <dprintf.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslinux/loadfile.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/config.h>
+#include <syslinux/disk.h>
+#include <syslinux/video.h>
+#include "chain.h"
+#include "utility.h"
+#include "options.h"
+#include "partiter.h"
+#include "mangle.h"
+
+static int fixed_cnt = 128;   /* see comments in main() */
+
+static int overlap(const struct data_area *a, const struct data_area *b)
+{
+    return
+	a->base + a->size > b->base &&
+	b->base + b->size > a->base;
+}
+
+static int is_phys(uint8_t sdifs)
+{
+    return
+	sdifs == SYSLINUX_FS_SYSLINUX ||
+	sdifs == SYSLINUX_FS_EXTLINUX ||
+	sdifs == SYSLINUX_FS_ISOLINUX;
+}
+
+/*
+ * Search for a specific drive, based on the MBR signature.
+ * Return drive and iterator at 0th position.
+ */
+static int find_by_sig(uint32_t mbr_sig,
+			struct part_iter **_boot_part)
+{
+    struct part_iter *iter = NULL;
+    struct disk_info diskinfo;
+    int drive;
+
+    for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+	if (disk_get_params(drive, &diskinfo))
+	    continue;		/* Drive doesn't exist */
+	if (!(iter = pi_begin(&diskinfo, opt.piflags)))
+	    continue;
+	/* Check for a matching MBR disk */
+	if (iter->type == typedos && iter->dos.disk_sig == mbr_sig)
+	    goto ok;
+	pi_del(&iter);
+    }
+    drive = -1;
+ok:
+    *_boot_part = iter;
+    return drive;
+}
+
+/*
+ * Search for a specific drive/partition, based on the GPT GUID.
+ * Return drive and iterator at proper position.
+ */
+static int find_by_guid(const struct guid *gpt_guid,
+			struct part_iter **_boot_part)
+{
+    struct part_iter *iter = NULL;
+    struct disk_info diskinfo;
+    int drive;
+
+    for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+	if (disk_get_params(drive, &diskinfo))
+	    continue;		/* Drive doesn't exist */
+	if (!(iter = pi_begin(&diskinfo, opt.piflags)))
+	    continue;
+	/* Check for a matching GPT disk/partition guid */
+	if (iter->type == typegpt)
+	    do {
+		if (!memcmp(&iter->gpt.part_guid, gpt_guid, sizeof *gpt_guid))
+		    goto ok;
+	    } while (!pi_next(iter));
+	pi_del(&iter);
+    }
+    drive = -1;
+ok:
+    *_boot_part = iter;
+    return drive;
+}
+
+/*
+ * Search for a specific drive/partition, based on the GPT label.
+ * Return drive and iterator at proper position.
+ */
+static int find_by_label(const char *label, struct part_iter **_boot_part)
+{
+    struct part_iter *iter = NULL;
+    struct disk_info diskinfo;
+    int drive;
+
+    for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) {
+	if (disk_get_params(drive, &diskinfo))
+	    continue;		/* Drive doesn't exist */
+	if (!(iter = pi_begin(&diskinfo, opt.piflags)))
+	    continue;
+	/* Check for a matching GPT partition label */
+	if (iter->type == typegpt)
+	    while (!pi_next(iter)) {
+		if (!strcmp(label, iter->gpt.part_label))
+		    goto ok;
+	    }
+	pi_del(&iter);
+    }
+    drive = -1;
+ok:
+    *_boot_part = iter;
+    return drive;
+}
+
+static void do_boot(struct data_area *data, int ndata)
+{
+    struct syslinux_memmap *mmap;
+    struct syslinux_movelist *mlist = NULL;
+    addr_t endimage;
+    uint8_t driveno = opt.regs.edx.b[0];
+    uint8_t swapdrive = driveno & 0x80;
+    int i;
+
+    mmap = syslinux_memory_map();
+
+    if (!mmap) {
+	error("Cannot read system memory map.");
+	return;
+    }
+
+    endimage = 0;
+    for (i = 0; i < ndata; i++) {
+	if (data[i].base + data[i].size > endimage)
+	    endimage = data[i].base + data[i].size;
+    }
+    if (endimage > dosmax)
+	goto too_big;
+
+    for (i = 0; i < ndata; i++) {
+	if (syslinux_add_movelist(&mlist, data[i].base,
+				  (addr_t) data[i].data, data[i].size))
+	    goto enomem;
+    }
+
+    if (opt.swap && driveno != swapdrive) {
+	static const uint8_t swapstub_master[] = {
+	    /* The actual swap code */
+	    0x53,		/* 00: push bx */
+	    0x0f, 0xb6, 0xda,	/* 01: movzx bx,dl */
+	    0x2e, 0x8a, 0x57, 0x60,	/* 04: mov dl,[cs:bx+0x60] */
+	    0x5b,		/* 08: pop bx */
+	    0xea, 0, 0, 0, 0,	/* 09: jmp far 0:0 */
+	    0x90, 0x90,		/* 0E: nop; nop */
+	    /* Code to install this in the right location */
+	    /* Entry with DS = CS; ES = SI = 0; CX = 256 */
+	    0x26, 0x66, 0x8b, 0x7c, 0x4c,	/* 10: mov edi,[es:si+4*0x13] */
+	    0x66, 0x89, 0x3e, 0x0a, 0x00,	/* 15: mov [0x0A],edi */
+	    0x26, 0x8b, 0x3e, 0x13, 0x04,	/* 1A: mov di,[es:0x413] */
+	    0x4f,		/* 1F: dec di */
+	    0x26, 0x89, 0x3e, 0x13, 0x04,	/* 20: mov [es:0x413],di */
+	    0x66, 0xc1, 0xe7, 0x16,	/* 25: shl edi,16+6 */
+	    0x26, 0x66, 0x89, 0x7c, 0x4c,	/* 29: mov [es:si+4*0x13],edi */
+	    0x66, 0xc1, 0xef, 0x10,	/* 2E: shr edi,16 */
+	    0x8e, 0xc7,		/* 32: mov es,di */
+	    0x31, 0xff,		/* 34: xor di,di */
+	    0xf3, 0x66, 0xa5,	/* 36: rep movsd */
+	    0xbe, 0, 0,		/* 39: mov si,0 */
+	    0xbf, 0, 0,		/* 3C: mov di,0 */
+	    0x8e, 0xde,		/* 3F: mov ds,si */
+	    0x8e, 0xc7,		/* 41: mov es,di */
+	    0x66, 0xb9, 0, 0, 0, 0,	/* 43: mov ecx,0 */
+	    0x66, 0xbe, 0, 0, 0, 0,	/* 49: mov esi,0 */
+	    0x66, 0xbf, 0, 0, 0, 0,	/* 4F: mov edi,0 */
+	    0xea, 0, 0, 0, 0,	/* 55: jmp 0:0 */
+	    /* pad out to segment boundary */
+	    0x90, 0x90,		/* 5A: ... */
+	    0x90, 0x90, 0x90, 0x90,	/* 5C: ... */
+	};
+	static uint8_t swapstub[1024];
+	uint8_t *p;
+
+	/* Note: we can't rely on either INT 13h nor the dosmax
+	   vector to be correct at this stage, so we have to use an
+	   installer stub to put things in the right place.
+	   Round the installer location to a 1K boundary so the only
+	   possible overlap is the identity mapping. */
+	endimage = (endimage + 1023u) & ~1023u;
+
+	/* Create swap stub */
+	memcpy(swapstub, swapstub_master, sizeof swapstub_master);
+	*(uint16_t *) & swapstub[0x3a] = opt.regs.ds;
+	*(uint16_t *) & swapstub[0x3d] = opt.regs.es;
+	*(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l;
+	*(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l;
+	*(uint32_t *) & swapstub[0x51] = opt.regs.edi.l;
+	*(uint16_t *) & swapstub[0x56] = opt.regs.ip;
+	*(uint16_t *) & swapstub[0x58] = opt.regs.cs;
+	p = &swapstub[sizeof swapstub_master];
+
+	/* Mapping table; start out with identity mapping everything */
+	for (i = 0; i < 256; i++)
+	    p[i] = i;
+
+	/* And the actual swap */
+	p[driveno] = swapdrive;
+	p[swapdrive] = driveno;
+
+	/* Adjust registers */
+	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 */
+	opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive;
+
+	if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub,
+				  sizeof swapstub))
+	    goto enomem;
+
+	endimage += sizeof swapstub;
+    }
+
+    /* Tell the shuffler not to muck with this area... */
+    syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED);
+
+    /* Force text mode */
+    syslinux_force_text_mode();
+
+    puts("Booting...");
+    syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs);
+    error("Chainboot failed !");
+    return;
+
+too_big:
+    error("Loader file too large.");
+    return;
+
+enomem:
+    error("Out of memory.");
+    return;
+}
+
+int find_dp(struct part_iter **_iter)
+{
+    struct part_iter *iter = NULL;
+    struct disk_info diskinfo;
+    struct guid gpt_guid;
+    uint64_t fs_lba;
+    int drive, hd, partition;
+    const union syslinux_derivative_info *sdi;
+
+    sdi = syslinux_derivative_info();
+
+    if (!strncmp(opt.drivename, "mbr", 3)) {
+	if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) {
+	    error("Unable to find requested MBR signature.");
+	    goto bail;
+	}
+    } else if (!strncmp(opt.drivename, "guid", 4)) {
+	if (str_to_guid(opt.drivename + 5, &gpt_guid))
+	    goto bail;
+	if (find_by_guid(&gpt_guid, &iter) < 0) {
+	    error("Unable to find requested GPT disk or partition by guid.");
+	    goto bail;
+	}
+    } else if (!strncmp(opt.drivename, "label", 5)) {
+	if (!opt.drivename[6]) {
+	    error("No label specified.");
+	    goto bail;
+	}
+	if (find_by_label(opt.drivename + 6, &iter) < 0) {
+	    error("Unable to find requested GPT partition by label.");
+	    goto bail;
+	}
+    } else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') &&
+	       opt.drivename[1] == 'd') {
+	hd = opt.drivename[0] == 'h' ? 0x80 : 0;
+	opt.drivename += 2;
+	drive = hd | strtol(opt.drivename, NULL, 0);
+
+	if (disk_get_params(drive, &diskinfo))
+	    goto bail;
+	/* this will start iteration over FDD, possibly raw */
+	if (!(iter = pi_begin(&diskinfo, opt.piflags)))
+	    goto bail;
+
+    } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) {
+	if (!is_phys(sdi->c.filesystem)) {
+	    error("When syslinux is not booted from physical disk (or its emulation),\n"
+		   "'boot' and 'fs' are meaningless.");
+	    goto bail;
+	}
+	/* offsets match, but in case it changes in the future */
+	if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) {
+	    drive = sdi->iso.drive_number;
+	    fs_lba = *sdi->iso.partoffset;
+	} else {
+	    drive = sdi->disk.drive_number;
+	    fs_lba = *sdi->disk.partoffset;
+	}
+	if (disk_get_params(drive, &diskinfo))
+	    goto bail;
+	/* this will start iteration over disk emulation, possibly raw */
+	if (!(iter = pi_begin(&diskinfo, opt.piflags)))
+	    goto bail;
+
+	/* 'fs' => we should lookup the syslinux partition number and use it */
+	if (!strcmp(opt.drivename, "fs")) {
+	    do {
+		if (iter->abs_lba == fs_lba)
+		    break;
+	    } while (!pi_next(iter));
+	    /* broken part structure or other problems */
+	    if (iter->status) {
+		error("Unable to find partition with syslinux (fs).");
+		goto bail;
+	    }
+	}
+    } else {
+	error("Unparsable drive specification.");
+	goto bail;
+    }
+    /* main options done - only thing left is explicit partition specification,
+     * if we're still at the disk stage with the iterator AND user supplied
+     * partition number (including disk pseudo-partition).
+     */
+    if (!iter->index && opt.partition) {
+	partition = strtol(opt.partition, NULL, 0);
+	/* search for matching part#, including disk */
+	do {
+	    if (iter->index == partition)
+		break;
+	} while (!pi_next(iter));
+	if (iter->status) {
+	    error("Unable to find requested disk / partition combination.");
+	    goto bail;
+	}
+    }
+
+    if (!(iter->di.disk & 0x80) && iter->index) {
+	warn("Partitions on floppy devices may not work.");
+    }
+
+    *_iter = iter;
+
+    return 0;
+
+bail:
+    pi_del(&iter);
+    return -1;
+}
+
+static int setup_handover(const struct part_iter *iter,
+		   struct data_area *data)
+{
+    struct disk_dos_part_entry *ha;
+    uint32_t synth_size = sizeof *ha;
+
+    /*
+     * 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 */
+	ha = malloc(synth_size);
+	if (!ha) {
+	    critm();
+	    goto bail;
+	}
+	len = ~0u;
+	if (iter->length < len)
+	    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 *plen + iter->gpt.pe_size;
+	ha = malloc(synth_size);
+	if (!ha) {
+	    critm();
+	    goto bail;
+	}
+	lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD);
+	lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD);
+	ha->active_flag = 0x80;
+	ha->ostype = 0xED;
+	/* All bits set by default */
+	ha->start_lba = ~0u;
+	ha->length = ~0u;
+	/* If these fit the precision, pass them on */
+	if (iter->abs_lba < ha->start_lba)
+	    ha->start_lba = iter->abs_lba;
+	if (iter->length < ha->length)
+	    ha->length = iter->length;
+	/* Next comes the GPT partition record length */
+	plen = (uint32_t *)(ha + 1);
+	plen[0] = iter->gpt.pe_size;
+	/* Next comes the GPT partition record copy */
+	memcpy(plen + 1, iter->record, plen[0]);
+#ifdef DEBUG
+	dprintf("GPT handover:\n");
+	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 */
+	ha = malloc(synth_size);
+	if (!ha) {
+	    critm();
+	    goto bail;
+	}
+	memcpy(ha, iter->record, synth_size);
+	/* make sure these match bios imaginations and are ebr agnostic */
+	lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD);
+	lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD);
+	ha->start_lba = iter->abs_lba;
+	ha->length = iter->length;
+
+#ifdef DEBUG
+	dprintf("MBR handover:\n");
+	disk_dos_part_dump(ha);
+#endif
+    } else {
+	/* shouldn't ever happen */
+	goto bail;
+    }
+
+    data->base = 0x7be;
+    data->size = synth_size;
+    data->data = (void *)ha;
+
+    return 0;
+bail:
+    return -1;
+}
+
+int main(int argc, char *argv[])
+{
+    struct part_iter *iter = NULL;
+    void *sbck = NULL;
+    struct data_area fdat, hdat, sdat, data[3];
+    int ndata = 0;
+
+    console_ansi_raw();
+
+    memset(&fdat, 0, sizeof fdat);
+    memset(&hdat, 0, sizeof hdat);
+    memset(&sdat, 0, sizeof sdat);
+
+    opt_set_defs();
+    if (opt_parse_args(argc, argv))
+	goto bail;
+
+#if 0
+    /* Get max fixed disk number */
+    fixed_cnt = *(uint8_t *)(0x475);
+
+    /*
+     * hmm, looks like we can't do that -
+     * some bioses/vms just set it to 1
+     * and go on living happily
+     * any better options than hardcoded 0x80 - 0xFF ?
+     */
+#endif
+
+    /* Get disk/part iterator matching user supplied options */
+    if (find_dp(&iter))
+	goto bail;
+
+    /* Perform initial partition entry mangling */
+    if (manglepe_fixchs(iter))
+	goto bail;
+    if (manglepe_hide(iter))
+	goto bail;
+
+    /* Load the boot file */
+    if (opt.file) {
+	fdat.base = (opt.fseg << 4) + opt.foff;
+
+	if (loadfile(opt.file, &fdat.data, &fdat.size)) {
+	    error("Couldn't read the boot file.");
+	    goto bail;
+	}
+	if (fdat.base + fdat.size > dosmax) {
+	    error("The boot file is too big to load at this address.");
+	    goto bail;
+	}
+    }
+
+    /* Load the sector */
+    if (opt.sect) {
+	sdat.base = (opt.sseg << 4) + opt.soff;
+	sdat.size = iter->di.bps;
+
+	if (sdat.base + sdat.size > dosmax) {
+	    error("The sector cannot be loaded at such high address.");
+	    goto bail;
+	}
+	if (!(sdat.data = disk_read_sectors(&iter->di, iter->abs_lba, 1))) {
+	    error("Couldn't read the sector.");
+	    goto bail;
+	}
+	if (opt.save) {
+	    if (!(sbck = malloc(sdat.size))) {
+		critm();
+		goto bail;
+	    }
+	    memcpy(sbck, sdat.data, sdat.size);
+	}
+	if (opt.file && opt.maps && overlap(&fdat, &sdat)) {
+	    warn("The sector won't be mmapped, as it would conflict with the boot file.");
+	    opt.maps = false;
+	}
+    }
+
+    /* Prep the handover */
+    if (opt.hand) {
+	if (setup_handover(iter, &hdat))
+	    goto bail;
+	/* Verify possible conflicts */
+	if ( ( opt.file && overlap(&fdat, &hdat)) ||
+	     ( opt.maps && overlap(&sdat, &hdat)) ) {
+	    warn("Handover area won't be prepared,\n"
+		  "as it would conflict with the boot file and/or the sector.");
+	    opt.hand = false;
+	}
+    }
+
+    /* Adjust registers */
+
+    mangler_init(iter);
+    mangler_handover(iter, &hdat);
+    mangler_grldr(iter);
+
+    /* Patching functions */
+
+    if (manglef_isolinux(&fdat))
+	goto bail;
+
+    if (manglef_grub(iter, &fdat))
+	goto bail;
+#if 0
+    if (manglef_drmk(&fdat))
+	goto bail;
+#endif
+    if (manglef_bpb(iter, &fdat))
+	goto bail;
+
+    if (mangles_bpb(iter, &sdat))
+	goto bail;
+
+    if (mangles_save(iter, &sdat, sbck))
+	goto bail;
+
+    if (manglesf_bss(&sdat, &fdat))
+	goto bail;
+
+    /* This *must* be after BPB saving or copying */
+    if (mangles_cmldr(&sdat))
+	goto bail;
+
+    /*
+     * Prepare boot-time mmap data. We should to it here, as manglers could
+     * potentially alter some of the data.
+     */
+
+    if (opt.file)
+	memcpy(data + ndata++, &fdat, sizeof fdat);
+    if (opt.maps)
+	memcpy(data + ndata++, &sdat, sizeof sdat);
+    if (opt.hand)
+	memcpy(data + ndata++, &hdat, sizeof hdat);
+
+#ifdef DEBUG
+    dprintf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n"
+	   "iter->di C, H, S: %u, %u, %u\n",
+	iter->di.disk, iter->di.bps,
+	iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt,
+	iter->di.cyl, iter->di.head, iter->di.spt);
+    dprintf("iter idx: %d\n", iter->index);
+    dprintf("iter lba: %"PRIu64"\n", iter->abs_lba);
+    if (opt.hand)
+	dprintf("hand lba: %u\n",
+		((struct disk_dos_part_entry *)hdat.data)->start_lba);
+#endif
+
+    if (opt.warn) {
+	puts("Press any key to continue booting...");
+	wait_key();
+    }
+
+    if (ndata && !opt.brkchain) /* boot only if we actually chainload */
+	do_boot(data, ndata);
+    else
+	puts("Service-only run completed, exiting.");
+bail:
+    pi_del(&iter);
+    /* Free allocated areas */
+    free(fdat.data);
+    free(sdat.data);
+    free(hdat.data);
+    free(sbck);
+    return 255;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/chain.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/chain.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/chain.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,29 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_CHAIN_H
+#define COM32_CHAIN_CHAIN_H
+
+#include <syslinux/movebits.h>
+
+struct data_area {
+    void *data;
+    addr_t base;
+    addr_t size;
+};
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/mangle.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/mangle.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/mangle.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,682 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <com32.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include <dprintf.h>
+#include <syslinux/config.h>
+#include "chain.h"
+#include "options.h"
+#include "utility.h"
+#include "partiter.h"
+#include "mangle.h"
+
+static const char cmldr_signature[8] = "cmdcons";
+
+/* Create boot info table: needed when you want to chainload
+ * another version of ISOLINUX (or another bootlaoder that needs
+ * the -boot-info-table switch of mkisofs)
+ * (will only work when run from ISOLINUX)
+ */
+int manglef_isolinux(struct data_area *data)
+{
+    const union syslinux_derivative_info *sdi;
+    unsigned char *isolinux_bin;
+    uint32_t *checksum, *chkhead, *chktail;
+    uint32_t file_lba = 0;
+
+    if (!(opt.file && opt.isolinux))
+	return 0;
+
+    sdi = syslinux_derivative_info();
+
+    if (sdi->c.filesystem != SYSLINUX_FS_ISOLINUX) {
+	error("The isolinux= option is only valid when run from ISOLINUX.");
+	goto bail;
+    }
+
+    /* Boot info table info (integers in little endian format)
+
+       Offset Name         Size      Meaning
+       8      bi_pvd       4 bytes   LBA of primary volume descriptor
+       12     bi_file      4 bytes   LBA of boot file
+       16     bi_length    4 bytes   Boot file length in bytes
+       20     bi_csum      4 bytes   32-bit checksum
+       24     bi_reserved  40 bytes  Reserved
+
+       The 32-bit checksum is the sum of all the 32-bit words in the
+       boot file starting at byte offset 64. All linear block
+       addresses (LBAs) are given in CD sectors (normally 2048 bytes).
+
+       LBA of primary volume descriptor should already be set to 16.
+       */
+
+    isolinux_bin = (unsigned char *)data->data;
+
+    /* Get LBA address of bootfile */
+    file_lba = get_file_lba(opt.file);
+
+    if (file_lba == 0) {
+	error("Failed to find LBA offset of the boot file.");
+	goto bail;
+    }
+    /* Set it */
+    *((uint32_t *) & isolinux_bin[12]) = file_lba;
+
+    /* Set boot file length */
+    *((uint32_t *) & isolinux_bin[16]) = data->size;
+
+    /* Calculate checksum */
+    checksum = (uint32_t *) & isolinux_bin[20];
+    chkhead = (uint32_t *) & isolinux_bin[64];
+    chktail = (uint32_t *) & isolinux_bin[data->size & ~3u];
+    *checksum = 0;
+    while (chkhead < chktail)
+	*checksum += *chkhead++;
+
+    /*
+     * Deal with possible fractional dword at the end;
+     * this *should* never happen...
+     */
+    if (data->size & 3) {
+	uint32_t xword = 0;
+	memcpy(&xword, chkhead, data->size & 3);
+	*checksum += xword;
+    }
+    return 0;
+bail:
+    return -1;
+}
+
+/*
+ * Legacy grub's stage2 chainloading
+ */
+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 {
+	/* 0x0 to 0x205 */
+	char unknown[0x206];
+	/* 0x206: compatibility version number major */
+	uint8_t compat_version_major;
+	/* 0x207: compatibility version number minor */
+	uint8_t compat_version_minor;
+
+	/* 0x208: install_partition variable */
+	struct {
+	    /* 0x208: sub-partition in sub-partition part2 */
+	    uint8_t part3;
+	    /* 0x209: sub-partition in top-level partition */
+	    uint8_t part2;
+	    /* 0x20a: top-level partiton number */
+	    uint8_t part1;
+	    /* 0x20b: BIOS drive number (must be 0) */
+	    uint8_t drive;
+	} __attribute__ ((packed)) install_partition;
+
+	/* 0x20c: deprecated (historical reason only) */
+	uint32_t saved_entryno;
+	/* 0x210: stage2_ID: will always be STAGE2_ID_STAGE2 = 0 in stage2 */
+	uint8_t stage2_id;
+	/* 0x211: force LBA */
+	uint8_t force_lba;
+	/* 0x212: version string (will probably be 0.97) */
+	char version_string[5];
+	/* 0x217: config filename */
+	char config_file[89];
+	/* 0x270: start of code (after jump from 0x200) */
+	char codestart[1];
+    } __attribute__ ((packed)) *stage2;
+
+    if (!(opt.file && opt.grub))
+	return 0;
+
+    if (data->size < sizeof *stage2) {
+	error("The file specified by grub=<loader> is too small to be stage2 of GRUB Legacy.");
+	goto bail;
+    }
+    stage2 = data->data;
+
+    /*
+     * Check the compatibility version number to see if we loaded a real
+     * stage2 file or a stage2 file that we support.
+     */
+    if (stage2->compat_version_major != 3
+	    || stage2->compat_version_minor != 2) {
+	error("The file specified by grub=<loader> is not a supported stage2 GRUB Legacy binary.");
+	goto bail;
+    }
+
+    /*
+     * GRUB Legacy wants the partition number in the install_partition
+     * variable, located at offset 0x208 of stage2.
+     * When GRUB Legacy is loaded, it is located at memory address 0x8208.
+     *
+     * It looks very similar to the "boot information format" of the
+     * Multiboot specification:
+     *   http://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format
+     *
+     *   0x208 = part3: sub-partition in sub-partition part2
+     *   0x209 = part2: sub-partition in top-level partition
+     *   0x20a = part1: top-level partition number
+     *   0x20b = drive: BIOS drive number (must be 0)
+     *
+     * GRUB Legacy doesn't store the BIOS drive number at 0x20b, but at
+     * another location.
+     *
+     * Partition numbers always start from zero.
+     * Unused partition bytes must be set to 0xFF.
+     *
+     * We only care about top-level partition, so we only need to change
+     * "part1" to the appropriate value:
+     *   -1:   whole drive (default) (-1 = 0xFF)
+     *   0-3:  primary partitions
+     *   4-*:  logical partitions
+     */
+    stage2->install_partition.part1 = iter->index - 1;
+
+    /*
+     * Grub Legacy reserves 89 bytes (from 0x8217 to 0x826f) for the
+     * config filename. The filename passed via grubcfg= will overwrite
+     * the default config filename "/boot/grub/menu.lst".
+     */
+    if (opt.grubcfg) {
+	if (strlen(opt.grubcfg) >= sizeof stage2->config_file) {
+	    error("The config filename length can't exceed 88 characters.");
+	    goto bail;
+	}
+
+	strcpy((char *)stage2->config_file, opt.grubcfg);
+    }
+
+    return 0;
+bail:
+    return -1;
+}
+#if 0
+/*
+ * Dell's DRMK chainloading.
+ */
+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;
+    const union syslinux_derivative_info *sdi;
+    uint64_t fs_lba;
+
+    sdi = syslinux_derivative_info();
+    /* We should lookup the Syslinux partition offset and use it */
+    fs_lba = *sdi->disk.partoffset;
+
+    /*
+     * fs_lba should be verified against the disk as some DRMK
+     * variants will check and fail if it does not match
+     */
+    dprintf("  fs_lba offset is %d\n", fs_lba);
+    /* DRMK only uses a DWORD */
+    if (fs_lba > 0xffffffff) {
+	error("LBA very large; Only using lower 32 bits; DRMK will probably fail.");
+    }
+    opt.regs.ss = opt.regs.fs = opt.regs.gs = 0;	/* Used before initialized */
+    if (!realloc(data->data, tsize)) {
+	error("Failed to realloc for DRMK.");
+	goto bail;
+    }
+    data->size = tsize;
+    /* ds:bp is assumed by DRMK to be the boot sector */
+    /* offset 28 is the FAT HiddenSectors value */
+    opt.regs.ds = (tsize >> 4) + (opt.fseg - 2);
+    /* "Patch" into tail of the new space */
+    *(uint32_t *)((char*)data->data + tsize - 4) = fs_lba;
+
+    return 0;
+bail:
+    return -1;
+}
+#endif
+/* Adjust BPB common function */
+static int mangle_bpb(const struct part_iter *iter, struct data_area *data, const char *tag)
+{
+    int type = bpb_detect(data->data, tag);
+    int off = drvoff_detect(type);
+
+    /* BPB: hidden sectors 64bit - exFAT only for now */
+    if (type == bpbEXF)
+	    *(uint64_t *) ((char *)data->data + 0x40) = iter->abs_lba;
+    /* BPB: hidden sectors 32bit*/
+    else if (bpbV34 <= type && type <= bpbV70) {
+	if (iter->abs_lba < ~0u)
+	    *(uint32_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
+	else
+	    /* won't really help much, but ... */
+	    *(uint32_t *) ((char *)data->data + 0x1c) = ~0u;
+    /* BPB: hidden sectors 16bit*/
+    } else if (bpbV30 <= type && type <= bpbV32) {
+	if (iter->abs_lba < 0xFFFF)
+	    *(uint16_t *) ((char *)data->data + 0x1c) = iter->abs_lba;
+	else
+	    /* won't really help much, but ... */
+	    *(uint16_t *) ((char *)data->data + 0x1c) = (uint16_t)~0u;
+    }
+
+    /* BPB: legacy geometry */
+    if (bpbV30 <= type && type <= bpbV70) {
+	if (iter->di.cbios)
+	    *(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;
+	    else
+		*(uint32_t *)((char *)data->data + 0x18) = 0x00020012;
+	}
+    }
+    /* BPB: drive */
+    if (off >= 0) {
+	*(uint8_t *)((char *)data->data + off) = (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.file && opt.filebpb))
+	return 0;
+
+    return mangle_bpb(iter, data, "file");
+}
+
+/*
+ * 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, "sect");
+}
+
+/*
+ * This function performs full BPB patching, analogously to syslinux's
+ * native BSS.
+ */
+int manglesf_bss(struct data_area *sec, struct data_area *fil)
+{
+    int type1, type2;
+    size_t cnt = 0;
+
+    if (!(opt.sect && opt.file && opt.bss))
+	return 0;
+
+    type1 = bpb_detect(fil->data, "bss/file");
+    type2 = bpb_detect(sec->data, "bss/sect");
+
+    if (!type1 || !type2) {
+	error("Couldn't determine the BPB type for option 'bss'.");
+	goto bail;
+    }
+    if (type1 != type2) {
+	error("Option 'bss' can't be used,\n"
+		"when a sector and a file have incompatible BPBs.");
+	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;
+    } else if (type1 <= bpbEXF) {
+	cnt = 0x60;
+    }
+    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.sect && opt.save))
+	return 0;
+
+    if (memcmp(org, data->data, data->size)) {
+	if (disk_write_sectors(&iter->di, iter->abs_lba, data->data, 1)) {
+	    error("Cannot write the updated sector.");
+	    goto bail;
+	}
+	/* function can be called again */
+	memcpy(org, data->data, data->size);
+    }
+
+    return 0;
+bail:
+    return -1;
+}
+
+/*
+ * To boot the Recovery Console of Windows NT/2K/XP we need to write
+ * the string "cmdcons\0" to memory location 0000:7C03.
+ * Memory location 0000:7C00 contains the bootsector of the partition.
+ */
+int mangles_cmldr(struct data_area *data)
+{
+    if (!(opt.sect && opt.cmldr))
+	return 0;
+
+    memcpy((char *)data->data + 3, cmldr_signature, sizeof cmldr_signature);
+    return 0;
+}
+
+/* Set common registers */
+int mangler_init(const struct part_iter *iter)
+{
+    /* Set initial registry values */
+    if (opt.file) {
+	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 = 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] = iter->di.disk;
+
+    return 0;
+}
+
+/* ds:si & ds:bp */
+int mangler_handover(const struct part_iter *iter, const struct data_area *data)
+{
+    if (opt.file && opt.maps && !opt.hptr) {
+	opt.regs.esi.l = opt.regs.ebp.l = opt.soff;
+	opt.regs.ds = 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->index && iter->type == typegpt)   /* must be iterated and GPT */
+	    opt.regs.eax.l = 0x54504721;	/* '!GPT' */
+	else
+	    opt.regs.eax.l = 0;
+    }
+
+    return 0;
+}
+
+/*
+ * 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] = iter->index - 1;
+
+    return 0;
+}
+
+/*
+ * try to copy values from temporary iterator, if positions match
+ */
+static void mbrcpy(struct part_iter *diter, struct part_iter *siter)
+{
+    if (diter->dos.cebr_lba == siter->dos.cebr_lba &&
+	    diter->di.disk == siter->di.disk) {
+	memcpy(diter->data, siter->data, sizeof(struct disk_dos_mbr));
+    }
+}
+
+static int fliphide(struct part_iter *iter, struct part_iter *miter)
+{
+    struct disk_dos_part_entry *dp;
+    static const uint16_t mask =
+	(1 << 0x01) | (1 << 0x04) | (1 << 0x06) |
+	(1 << 0x07) | (1 << 0x0b) | (1 << 0x0c) | (1 << 0x0e);
+    uint8_t t;
+
+    dp = (struct disk_dos_part_entry *)iter->record;
+    t = dp->ostype;
+
+    if ((t <= 0x1f) && ((mask >> (t & ~0x10u)) & 1)) {
+	/* It's a hideable partition type */
+	if (miter->index == iter->index || opt.hide & HIDE_REV)
+	    t &= ~0x10u;	/* unhide */
+	else
+	    t |= 0x10u;	/* hide */
+    }
+    if (dp->ostype != t) {
+	dp->ostype = t;
+	return -1;
+    }
+    return 0;
+}
+
+/*
+ * miter - iterator we match against
+ * hide bits meaning:
+ * ..| - enable (1) / disable (0)
+ * .|. - all (1) / pri (0)
+ * |.. - unhide (1) / hide (0)
+ */
+int manglepe_hide(struct part_iter *miter)
+{
+    int wb = 0, werr = 0;
+    struct part_iter *iter = NULL;
+    int ridx;
+
+    if (!(opt.hide & HIDE_ON))
+	return 0;
+
+    if (miter->type != typedos) {
+	error("Option '[un]hide[all]' works only for legacy (DOS) partition scheme.");
+	return -1;
+    }
+
+    if (miter->index > 4 && !(opt.hide & HIDE_EXT))
+	warn("Specified partition is logical, so it can't be unhidden without 'unhideall'.");
+
+    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
+	return -1;
+
+    while (!pi_next(iter) && !werr) {
+	ridx = iter->index0;
+	if (!(opt.hide & HIDE_EXT) && ridx > 3)
+	    break;  /* skip when we're constrained to pri only */
+
+	if (iter->index != -1)
+	    wb |= fliphide(iter, miter);
+
+	/*
+	 * we have to update mbr and each extended partition, but only if
+	 * changes (wb) were detected and there was no prior write error (werr)
+	 */
+	if (ridx >= 3 && wb && !werr) {
+	    mbrcpy(miter, iter);
+	    werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
+	    wb = 0;
+	}
+    }
+
+    if (iter->status < 0)
+	goto bail;
+
+    /* last update */
+    if (wb && !werr) {
+	mbrcpy(miter, iter);
+	werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
+    }
+    if (werr)
+	warn("Failed to write E/MBR during '[un]hide[all]'.");
+
+bail:
+    pi_del(&iter);
+    return 0;
+}
+
+static int updchs(struct part_iter *iter, int ext)
+{
+    struct disk_dos_part_entry *dp;
+    uint32_t ochs1, ochs2, lba;
+
+    dp = (struct disk_dos_part_entry *)iter->record;
+    if (!ext) {
+	/* primary or logical */
+	lba = (uint32_t)iter->abs_lba;
+    } else {
+	/* extended */
+	dp += 1;
+	lba = iter->dos.nebr_lba;
+    }
+    ochs1 = *(uint32_t *)dp->start;
+    ochs2 = *(uint32_t *)dp->end;
+
+    /*
+     * We have to be a bit more careful here in case of 0 start and/or length;
+     * start = 0 would be converted to the beginning of the disk (C/H/S =
+     * 0/0/1) or the [B]EBR, length = 0 would actually set the end CHS to be
+     * lower than the start CHS.
+     *
+     * Both are harmless in case of a hole (and in non-hole case will make
+     * partiter complain about corrupt layout if PIF_STRICT is set), but it
+     * makes everything look silly and not really correct.
+     *
+     * Thus the approach as seen below.
+     */
+
+    if (dp->start_lba || iter->index != -1) {
+	lba2chs(&dp->start, &iter->di, lba, L2C_CADD);
+    } else {
+	memset(&dp->start, 0, sizeof dp->start);
+    }
+
+    if ((dp->start_lba || iter->index != -1) && dp->length) {
+	lba2chs(&dp->end, &iter->di, lba + dp->length - 1, L2C_CADD);
+    } else {
+	memset(&dp->end, 0, sizeof dp->end);
+    }
+
+    return
+	*(uint32_t *)dp->start != ochs1 ||
+	*(uint32_t *)dp->end != ochs2;
+}
+
+/*
+ * miter - iterator we match against
+ */
+int manglepe_fixchs(struct part_iter *miter)
+{
+    int wb = 0, werr = 0;
+    struct part_iter *iter = NULL;
+    int ridx;
+
+    if (!opt.fixchs)
+	return 0;
+
+    if (miter->type != typedos) {
+	error("Option 'fixchs' works only for legacy (DOS) partition scheme.");
+	return -1;
+    }
+
+    if (!(iter = pi_begin(&miter->di, PIF_STEPALL | opt.piflags)))
+	return -1;
+
+    while (!pi_next(iter) && !werr) {
+	ridx = iter->index0;
+
+	wb |= updchs(iter, 0);
+	if (ridx > 3)
+	    wb |= updchs(iter, 1);
+
+	/*
+	 * we have to update mbr and each extended partition, but only if
+	 * changes (wb) were detected and there was no prior write error (werr)
+	 */
+	if (ridx >= 3 && wb && !werr) {
+	    mbrcpy(miter, iter);
+	    werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
+	    wb = 0;
+	}
+    }
+
+    if (iter->status < 0)
+	goto bail;
+
+    /* last update */
+    if (wb && !werr) {
+	mbrcpy(miter, iter);
+	werr |= disk_write_sectors(&iter->di, iter->dos.cebr_lba, iter->data, 1);
+    }
+    if (werr)
+	warn("Failed to write E/MBR during 'fixchs'.");
+
+bail:
+    pi_del(&iter);
+    return 0;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/mangle.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/mangle.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/mangle.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,62 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_MANGLE_H
+#define COM32_CHAIN_MANGLE_H
+
+#include "chain.h"
+#include "partiter.h"
+
+/* file's manglers */
+int manglef_isolinux(struct data_area *data);
+int manglef_grub(const struct part_iter *iter, struct data_area *data);
+int manglef_bpb(const struct part_iter *iter, struct data_area *data);
+/* int manglef_drmk(struct data_area *data);*/
+
+/* sector's manglers */
+int mangles_bpb(const struct part_iter *iter, struct data_area *data);
+int mangles_save(const struct part_iter *iter, const struct data_area *data, void *org);
+int mangles_cmldr(struct data_area *data);
+
+/* sector + file's manglers */
+int manglesf_bss(struct data_area *sec, struct data_area *fil);
+
+/* registers' manglers */
+int mangler_init(const struct part_iter *iter);
+int mangler_handover(const struct part_iter *iter, const struct data_area *data);
+int mangler_grldr(const struct part_iter *iter);
+
+/* partition layout's manglers */
+int manglepe_fixchs(struct part_iter *miter);
+int manglepe_hide(struct part_iter *miter);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/options.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/options.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/options.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,436 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <syslinux/movebits.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include "chain.h"
+#include "partiter.h"
+#include "utility.h"
+#include "options.h"
+
+struct options opt;
+
+static int soi_s2n(char *ptr,
+			addr_t *seg,
+			addr_t *off,
+			addr_t *ip,
+			addr_t def)
+{
+    addr_t segval, offval, ipval, val;
+    char *p;
+
+    /* defaults */
+    segval = 0;
+    offval = def;
+    ipval = def;
+
+    segval = strtoul(ptr, &p, 0);
+    if (p[0] == ':' && p[1] && p[1] != ':')
+	offval = strtoul(p+1, &p, 0);
+    if (p[0] == ':' && p[1] && p[1] != ':')
+	ipval = strtoul(p+1, NULL, 0);
+
+    /* verify if load address is within [dosmin, dosmax) */
+    val = (segval << 4) + offval;
+
+    if (val < dosmin || val >= dosmax) {
+	error("Invalid seg:off:* address specified.");
+	goto bail;
+    }
+
+    /*
+     * verify if jump address is within [dosmin, dosmax) and offset is 16bit
+     * sane
+     */
+    val = (segval << 4) + ipval;
+
+    if (ipval > 0xFFFE || val < dosmin || val >= dosmax) {
+	error("Invalid seg:*:ip address specified.");
+	goto bail;
+    }
+
+    if (seg)
+	*seg = segval;
+    if (off)
+	*off = offval;
+    if (ip)
+	*ip  = ipval;
+
+    return 0;
+bail:
+    return -1;
+}
+
+static void usage(void)
+{
+    size_t i;
+    static const char *const usage[] = {
+"Usage:",
+"",
+"  disk + partition selection:",
+"        chain.c32 [options]",
+"        chain.c32 hd#[,#] [options]",
+"        chain.c32 fd#[,#] [options]",
+"        chain.c32 mbr=<id>[,#] [options]",
+"        chain.c32 guid=<guid>[,#] [options]",
+"        chain.c32 boot[,#] [options]",
+"",
+"  direct partition selection:",
+"        chain.c32 guid=<guid> [options]",
+"        chain.c32 label=<label> [options]",
+"        chain.c32 fs [options]",
+"",
+"You can use ':' instead of '=' and ' ' instead of ','.",
+"The default is 'boot,0'.",
+"",
+"Options:",
+"  sect[=<s[:o[:i]]>]   Load sector at <s:o>, jump to <s:i>",
+"                       - defaults to 0:0x7C00:0x7C00",
+"                       - omitted o/i values default to 0",
+"  maps                 Map loaded sector into real memory",
+"  setbpb               Fix BPB fields in loaded sector",
+"  filebpb              Apply 'setbpb' to loaded file",
+"  save                 Write adjusted sector back to disk",
+"  hand                 Prepare handover area",
+"  hptr                 Force ds:si and ds:bp to point to handover area",
+"  swap                 Swap drive numbers, if bootdisk is not fd0/hd0",
+"  nohide               Disable all hide variations (default)",
+"  hide                 Hide primary partitions, unhide selected partition",
+"  hideall              Hide *all* partitions, unhide selected partition",
+"  unhide               Unhide primary partitions",
+"  unhideall            Unhide *all* partitions",
+"  fixchs               Walk *all* partitions and fix E/MBRs' CHS values",
+"  keeppxe              Keep the PXE and UNDI stacks in memory (PXELINUX)",
+"  warn                 Wait for a keypress to continue chainloading",
+"  break                Don't chainload",
+"  strict[=<0|1|2>]     Set the level of strictness in sanity checks",
+"                       - strict w/o any value is the same as strict=2",
+"  relax                The same as strict=0",
+"  prefmbr              On hybrid MBR/GPT disks, prefer legacy layout",
+"",
+"  file=<file>          Load and execute <file>",
+"  seg=<s[:o[:i]]>      Load file at <s:o>, jump to <s:i>",
+"                       - defaults to 0:0x7C00:0x7C00",
+"                       - omitted o/i values default to 0",
+"  isolinux=<loader>    Load another version of ISOLINUX",
+"  ntldr=<loader>       Load Windows NTLDR, SETUPLDR.BIN or BOOTMGR",
+"  reactos=<loader>     Load ReactOS's loader",
+"  cmldr=<loader>       Load Recovery Console of Windows NT/2K/XP/2003",
+"  freedos=<loader>     Load FreeDOS KERNEL.SYS",
+"  msdos=<loader>       Load MS-DOS 2.xx - 6.xx IO.SYS",
+"  msdos7=<loader>      Load MS-DOS 7+ IO.SYS",
+"  pcdos=<loader>       Load PC-DOS IBMBIO.COM",
+"  drmk=<loader>        Load DRMK DELLBIO.BIN",
+"  grub=<loader>        Load GRUB Legacy stage2",
+"  grubcfg=<config>     Set alternative config filename for GRUB Legacy",
+"  grldr=<loader>       Load GRUB4DOS grldr",
+"  bss=<sectimage>      Emulate syslinux's BSS",
+"  bs=<sectimage>       Emulate syslinux's BS",
+"",
+"Please see doc/chain.txt for the detailed documentation."
+};
+    for (i = 0; i < sizeof(usage)/sizeof(usage[0]); i++) {
+	if (i % 20 == 19) {
+	    puts("Press any key...");
+	    wait_key();
+	}
+	puts(usage[i]);
+    }
+}
+
+void opt_set_defs(void)
+{
+    memset(&opt, 0, sizeof opt);
+    opt.sect = true;	    /* by def. load sector */
+    opt.maps = true;	    /* by def. map sector */
+    opt.hand = true;	    /* by def. prepare handover */
+    opt.brkchain = false;   /* by def. do chainload */
+    opt.piflags = PIF_STRICT;	/* by def. be strict, but ignore disk sizes */
+    opt.foff = opt.soff = opt.fip = opt.sip = 0x7C00;
+    opt.drivename = "boot";
+#ifdef DEBUG
+    opt.warn = true;
+#endif
+}
+
+int opt_parse_args(int argc, char *argv[])
+{
+    int i;
+    size_t v;
+    char *p;
+
+    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, 0))
+		goto bail;
+	} else if (!strncmp(argv[i], "bss=", 4)) {
+	    opt.file = argv[i] + 4;
+	    opt.bss = true;
+	    opt.maps = false;
+	    opt.setbpb = true;
+	} else if (!strncmp(argv[i], "bs=", 3)) {
+	    opt.file = argv[i] + 3;
+	    opt.sect = false;
+	    opt.filebpb = true;
+	} else if (!strncmp(argv[i], "isolinux=", 9)) {
+	    opt.file = argv[i] + 9;
+	    opt.isolinux = true;
+	    opt.hand = false;
+	    opt.sect = false;
+	} else if (!strncmp(argv[i], "ntldr=", 6)) {
+	    opt.fseg = 0x2000;  /* NTLDR wants this address */
+	    opt.foff = 0;
+	    opt.fip = 0;
+	    opt.file = argv[i] + 6;
+	    opt.setbpb = true;
+	    opt.hand = false;
+	} else if (!strncmp(argv[i], "reactos=", 8)) {
+	    /*
+	     * settings based on commit
+	     *   ad4cf1470977f648ee1dd45e97939589ccb0393c
+	     * note, conflicts with:
+	     *   http://reactos.freedoors.org/Reactos%200.3.13/ReactOS-0.3.13-REL-src/boot/freeldr/notes.txt
+	     */
+	    opt.fseg = 0;
+	    opt.foff = 0x8000;
+	    opt.fip = 0x8100;
+	    opt.file = argv[i] + 8;
+	    opt.setbpb = true;
+	    opt.hand = false;
+	} else if (!strncmp(argv[i], "cmldr=", 6)) {
+	    opt.fseg = 0x2000;  /* CMLDR wants this address */
+	    opt.foff = 0;
+	    opt.fip = 0;
+	    opt.file = argv[i] + 6;
+	    opt.cmldr = true;
+	    opt.setbpb = true;
+	    opt.hand = false;
+	} else if (!strncmp(argv[i], "freedos=", 8)) {
+	    opt.fseg = 0x60;    /* FREEDOS wants this address */
+	    opt.foff = 0;
+	    opt.fip = 0;
+	    opt.sseg = 0x1FE0;
+	    opt.file = argv[i] + 8;
+	    opt.setbpb = true;
+	    opt.hand = false;
+	} else if ( (v = 6, !strncmp(argv[i], "msdos=", v) ||
+		     !strncmp(argv[i], "pcdos=", v)) ||
+		    (v = 7, !strncmp(argv[i], "msdos7=", v)) ) {
+	    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 = 0x8000;
+	    opt.file = argv[i] + v;
+	    opt.setbpb = true;
+	    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.setbpb = true;
+	    opt.hand = false;
+	} else if (!strncmp(argv[i], "grub=", 5)) {
+	    opt.fseg = 0x800;	/* stage2 wants this address */
+	    opt.foff = 0;
+	    opt.fip = 0x200;
+	    opt.file = argv[i] + 5;
+	    opt.grub = true;
+	    opt.hand = false;
+	    opt.sect = false;
+	} else if (!strncmp(argv[i], "grubcfg=", 8)) {
+	    opt.grubcfg = argv[i] + 8;
+	} else if (!strncmp(argv[i], "grldr=", 6)) {
+	    opt.file = argv[i] + 6;
+	    opt.grldr = true;
+	    opt.hand = false;
+	    opt.sect = false;
+	} else if (!strcmp(argv[i], "keeppxe")) {
+	    opt.keeppxe = 3;
+	} else if (!strcmp(argv[i], "nokeeppxe")) {
+	    opt.keeppxe = 0;
+	} else if (!strcmp(argv[i], "maps")) {
+	    opt.maps = true;
+	} else if (!strcmp(argv[i], "nomaps")) {
+	    opt.maps = false;
+	} else if (!strcmp(argv[i], "hand")) {
+	    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")) {
+	    opt.swap = false;
+	} else if (!strcmp(argv[i], "nohide")) {
+	    opt.hide = HIDE_OFF;
+	} else if (!strcmp(argv[i], "hide")) {
+	    opt.hide = HIDE_ON;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strcmp(argv[i], "hideall")) {
+	    opt.hide = HIDE_ON | HIDE_EXT;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strcmp(argv[i], "unhide")) {
+	    opt.hide = HIDE_ON | HIDE_REV;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strcmp(argv[i], "unhideall")) {
+	    opt.hide = HIDE_ON | HIDE_EXT | HIDE_REV;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strcmp(argv[i], "setbpb")) {
+	    opt.setbpb = true;
+	} else if (!strcmp(argv[i], "nosetbpb")) {
+	    opt.setbpb = false;
+	} else if (!strcmp(argv[i], "filebpb")) {
+	    opt.filebpb = true;
+	} else if (!strcmp(argv[i], "nofilebpb")) {
+	    opt.filebpb = false;
+	} else if (!strncmp(argv[i], "sect=", 5) ||
+		   !strcmp(argv[i], "sect")) {
+	    if (argv[i][4]) {
+		if (soi_s2n(argv[i] + 5, &opt.sseg, &opt.soff, &opt.sip, 0))
+		    goto bail;
+	    }
+	    opt.sect = true;
+	} else if (!strcmp(argv[i], "nosect")) {
+	    opt.sect = false;
+	    opt.maps = false;
+	} else if (!strcmp(argv[i], "save")) {
+	    opt.save = true;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strcmp(argv[i], "nosave")) {
+	    opt.save = false;
+	} else if (!strcmp(argv[i], "fixchs")) {
+	    opt.fixchs = true;
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strcmp(argv[i], "nofixchs")) {
+	    opt.fixchs = false;
+	} else if (!strcmp(argv[i], "relax") || !strcmp(argv[i], "nostrict")) {
+	    opt.piflags &= ~(PIF_STRICT | PIF_STRICTER);
+	} else if (!strcmp(argv[i], "norelax") || !strcmp(argv[i], "strict")) {
+	    opt.piflags |= PIF_STRICT | PIF_STRICTER;
+	} else if (!strncmp(argv[i], "strict=", 7)) {
+	    if (argv[i][7] < '0' || argv[i][7] > '2' || !argv[i][8]) {
+		error("Strict level must be 0, 1 or 2.");
+		goto bail;
+	    }
+	    opt.piflags &= ~(PIF_STRICT | PIF_STRICTER);
+	    switch (argv[i][7]) {
+		case '2': opt.piflags |= PIF_STRICTER;
+		case '1': opt.piflags |= PIF_STRICT; break;
+		default:;
+	    }
+	} else if (!strcmp(argv[i], "warn")) {
+	    opt.warn = true;
+	} else if (!strcmp(argv[i], "nowarn")) {
+	    opt.warn = false;
+	} else if (!strcmp(argv[i], "prefmbr")) {
+	    opt.piflags |= PIF_PREFMBR;
+	} else if (!strcmp(argv[i], "noprefmbr")) {
+	    opt.piflags &= ~PIF_PREFMBR;
+	} else if (!strcmp(argv[i], "nobreak")) {
+	    opt.brkchain = false;
+	} else if (!strcmp(argv[i], "break")) {
+	    opt.brkchain = true;
+	    opt.file = NULL;
+	    opt.maps = false;
+	    opt.hand = false;
+	} else if (((argv[i][0] == 'h' || argv[i][0] == 'f')
+		    && argv[i][1] == 'd')
+		   || !strncmp(argv[i], "mbr:", 4)
+		   || !strncmp(argv[i], "mbr=", 4)
+		   || !strncmp(argv[i], "guid:", 5)
+		   || !strncmp(argv[i], "guid=", 5)
+		   || !strncmp(argv[i], "label:", 6)
+		   || !strncmp(argv[i], "label=", 6)
+		   || !strcmp(argv[i], "boot")
+		   || !strncmp(argv[i], "boot,", 5)
+		   || !strcmp(argv[i], "fs")) {
+	    opt.drivename = argv[i];
+	    if (strncmp(argv[i], "label", 5))
+		p = strchr(opt.drivename, ',');
+	    else
+		p = NULL;
+	    if (p) {
+		*p = '\0';
+		opt.partition = p + 1;
+	    } else if (argv[i + 1] && argv[i + 1][0] >= '0'
+		    && argv[i + 1][0] <= '9') {
+		opt.partition = argv[++i];
+	    }
+	} else {
+	    usage();
+	    goto bail;
+	}
+    }
+
+    if (opt.grubcfg && !opt.grub) {
+	error("grubcfg=<filename> must be used together with grub=<loader>.");
+	goto bail;
+    }
+
+    if (opt.filebpb && !opt.file) {
+	error("Option 'filebpb' requires a file.");
+	goto bail;
+    }
+
+    if (opt.save && !opt.sect) {
+	error("Option 'save' requires a sector.");
+	goto bail;
+    }
+
+    if (opt.setbpb && !opt.sect) {
+	error("Option 'setbpb' requires a sector.");
+	goto bail;
+    }
+
+    if (opt.maps && !opt.sect) {
+	error("Option 'maps' requires a sector.");
+	goto bail;
+    }
+
+    return 0;
+bail:
+    return -1;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/options.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/options.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/options.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,81 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_OPTIONS_H
+#define COM32_CHAIN_OPTIONS_H
+
+#include <stdint.h>
+#include <syslinux/bootrm.h>
+#include <syslinux/movebits.h>
+
+enum {HIDE_OFF = 0, HIDE_ON = 1, HIDE_EXT = 2, HIDE_REV = 4};
+
+struct options {
+    const char *drivename;
+    const char *partition;
+    const char *file;
+    const char *grubcfg;
+    addr_t fseg;
+    addr_t foff;
+    addr_t fip;
+    addr_t sseg;
+    addr_t soff;
+    addr_t sip;
+    int hide;
+    int piflags;
+    uint16_t keeppxe;
+    bool isolinux;
+    bool cmldr;
+    bool drmk;
+    bool grub;
+    bool grldr;
+    bool maps;
+    bool hand;
+    bool hptr;
+    bool swap;
+    bool sect;
+    bool save;
+    bool bss;
+    bool setbpb;
+    bool filebpb;
+    bool fixchs;
+    bool warn;
+    bool brkchain;
+    struct syslinux_rm_regs regs;
+};
+
+extern struct options opt;
+
+void opt_set_defs(void);
+int opt_parse_args(int argc, char *argv[]);
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/partiter.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/partiter.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/partiter.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,714 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.c
+ *
+ * Provides disk / partition iteration.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <zlib.h>
+#include <syslinux/disk.h>
+#include "partiter.h"
+#include "utility.h"
+
+#define ost_is_ext(type) ((type) == 0x05 || (type) == 0x0F || (type) == 0x85)
+#define ost_is_nondata(type) (ost_is_ext(type) || (type) == 0x00)
+#define sane(s,l) ((s)+(l) > (s))
+
+/* virtual forwards */
+
+static void pi_dtor_(struct part_iter *);
+static int  pi_next_(struct part_iter *);
+static int  pi_dos_next(struct part_iter *);
+static int  pi_gpt_next(struct part_iter *);
+
+/* vtab and types */
+
+static struct itertype types[] = {
+   [0] = {
+	.dtor = &pi_dtor_,
+	.next = &pi_dos_next,
+}, [1] = {
+	.dtor = &pi_dtor_,
+	.next = &pi_gpt_next,
+}, [2] = {
+	.dtor = &pi_dtor_,
+	.next = &pi_next_,
+}};
+
+const struct itertype * const typedos = types;
+const struct itertype * const typegpt = types+1;
+const struct itertype * const typeraw = types+2;
+
+/* pi_dtor_() - common/raw iterator cleanup */
+static void pi_dtor_(struct part_iter *iter)
+{
+    /* syslinux's free is null resilient */
+    free(iter->data);
+}
+
+/* pi_ctor() - common/raw iterator initialization */
+static int pi_ctor(struct part_iter *iter,
+	const struct disk_info *di, int flags
+)
+{
+    memcpy(&iter->di, di, sizeof *di);
+    iter->flags = flags;
+    iter->index0 = -1;
+    iter->length = di->lbacnt;
+
+    iter->type = typeraw;
+    return 0;
+}
+
+/* pi_dos_ctor() - MBR/EBR iterator specific initialization */
+static int pi_dos_ctor(struct part_iter *iter,
+	const struct disk_info *di, int flags,
+	const struct disk_dos_mbr *mbr
+)
+{
+    if (pi_ctor(iter, di, flags))
+	return -1;
+
+    if (!(iter->data = malloc(sizeof *mbr))) {
+	critm();
+	goto bail;
+    }
+
+    memcpy(iter->data, mbr, sizeof *mbr);
+
+    iter->dos.bebr_index0 = -1;
+    iter->dos.disk_sig = mbr->disk_sig;
+
+    iter->type = typedos;
+    return 0;
+bail:
+    pi_dtor_(iter);
+    return -1;
+}
+
+/* pi_gpt_ctor() - GPT iterator specific initialization */
+static int pi_gpt_ctor(struct part_iter *iter,
+	const struct disk_info *di, int flags,
+	const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl
+)
+{
+    uint64_t siz;
+
+    if (pi_ctor(iter, di, flags))
+	return -1;
+
+    siz = (uint64_t)gpth->part_count * gpth->part_size;
+
+    if (!(iter->data = malloc((size_t)siz))) {
+	critm();
+	goto bail;
+    }
+
+    memcpy(iter->data, gptl, (size_t)siz);
+
+    iter->gpt.pe_count = (int)gpth->part_count;
+    iter->gpt.pe_size = (int)gpth->part_size;
+    iter->gpt.ufirst = gpth->lba_first_usable;
+    iter->gpt.ulast = gpth->lba_last_usable;
+
+    memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+    memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid);
+
+    iter->type = typegpt;
+    return 0;
+bail:
+    pi_dtor_(iter);
+    return -1;
+}
+
+/* Logical partition must be sane, meaning:
+ * - must be data or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside current EBR frame
+ */
+
+static int notsane_logical(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    uint32_t end_log;
+
+    dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+    if (!dp[0].ostype)
+	return 0;
+
+    if (ost_is_ext(dp[0].ostype)) {
+	error("The 1st EBR entry must be data or empty.");
+	return -1;
+    }
+
+    if (!(iter->flags & PIF_STRICT))
+	return 0;
+
+    end_log = dp[0].start_lba + dp[0].length;
+
+    if (!dp[0].start_lba ||
+	!dp[0].length ||
+	!sane(dp[0].start_lba, dp[0].length) ||
+	end_log > iter->dos.nebr_siz) {
+
+	error("Logical partition (in EBR) with invalid offset and/or length.");
+	return -1;
+    }
+
+    return 0;
+}
+
+/* Extended partition must be sane, meaning:
+ * - must be extended or empty
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ * - must be inside base EBR frame
+ */
+
+static int notsane_extended(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    uint32_t end_ebr;
+
+    dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+    if (!dp[1].ostype)
+	return 0;
+
+    if (!ost_is_nondata(dp[1].ostype)) {
+	error("The 2nd EBR entry must be extended or empty.");
+	return -1;
+    }
+
+    if (!(iter->flags & PIF_STRICT))
+	return 0;
+
+    end_ebr = dp[1].start_lba + dp[1].length;
+
+    if (!dp[1].start_lba ||
+	!dp[1].length ||
+	!sane(dp[1].start_lba, dp[1].length) ||
+	end_ebr > iter->dos.bebr_siz) {
+
+	error("Extended partition (EBR) with invalid offset and/or length.");
+	return -1;
+    }
+
+    return 0;
+}
+
+/* Primary partition must be sane, meaning:
+ * - must have non-0 start and length
+ * - values must not wrap around 32bit
+ */
+
+static int notsane_primary(const struct part_iter *iter)
+{
+    const struct disk_dos_part_entry *dp;
+    dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+    if (!dp->ostype)
+	return 0;
+
+    if (!(iter->flags & PIF_STRICT))
+	return 0;
+
+    if (!dp->start_lba ||
+	!dp->length ||
+	!sane(dp->start_lba, dp->length) ||
+	((iter->flags & PIF_STRICTER) && (dp->start_lba + dp->length > iter->di.lbacnt))) {
+	error("Primary partition (in MBR) with invalid offset and/or length.");
+	return -1;
+    }
+
+    return 0;
+}
+
+static int notsane_gpt(const struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gp;
+    gp = (const struct disk_gpt_part_entry *)
+	(iter->data + iter->index0 * iter->gpt.pe_size);
+
+    if (guid_is0(&gp->type))
+	return 0;
+
+    if (!(iter->flags & PIF_STRICT))
+	return 0;
+
+    if (gp->lba_first < iter->gpt.ufirst ||
+	gp->lba_last > iter->gpt.ulast) {
+	error("LBA sectors of GPT partition are beyond the range allowed in GPT header.");
+	return -1;
+    }
+
+    return 0;
+}
+
+static int dos_next_mbr(struct part_iter *iter, uint32_t *lba,
+			    struct disk_dos_part_entry **_dp)
+{
+    struct disk_dos_part_entry *dp;
+
+    while (++iter->index0 < 4) {
+	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->index0;
+
+	if (notsane_primary(iter)) {
+	    iter->status = PI_INSANE;
+	    return -1;
+	}
+
+	if (ost_is_ext(dp->ostype)) {
+	    if (iter->dos.bebr_index0 >= 0) {
+		error("More than 1 extended partition.");
+		iter->status = PI_INSANE;
+		return -1;
+	    }
+	    /* record base EBR index */
+	    iter->dos.bebr_index0 = iter->index0;
+	}
+	if (!ost_is_nondata(dp->ostype) || (iter->flags & PIF_STEPALL)) {
+	    *lba = dp->start_lba;
+	    *_dp = dp;
+	    break;
+	}
+    }
+
+    return 0;
+}
+
+static int prep_base_ebr(struct part_iter *iter)
+{
+    struct disk_dos_part_entry *dp;
+
+    if (iter->dos.bebr_index0 < 0)	/* if we don't have base extended partition at all */
+	return -1;
+    else if (!iter->dos.bebr_lba) { /* if not initialized yet */
+	dp = ((struct disk_dos_mbr *)iter->data)->table + iter->dos.bebr_index0;
+
+	iter->dos.bebr_lba = dp->start_lba;
+	iter->dos.bebr_siz = dp->length;
+
+	iter->dos.nebr_lba = dp->start_lba;
+	iter->dos.nebr_siz = dp->length;
+
+	iter->index0--;
+    }
+    return 0;
+}
+
+static int dos_next_ebr(struct part_iter *iter, uint32_t *lba,
+			    struct disk_dos_part_entry **_dp)
+{
+    struct disk_dos_part_entry *dp;
+
+    if (prep_base_ebr(iter) < 0) {
+	iter->status = PI_DONE;
+	return -1;
+    }
+
+    while (++iter->index0 < 1024 && iter->dos.nebr_lba) {
+	free(iter->data);
+	if (!(iter->data =
+		    disk_read_sectors(&iter->di, iter->dos.nebr_lba, 1))) {
+	    error("Couldn't load EBR.");
+	    iter->status = PI_ERRLOAD;
+	    return -1;
+	}
+
+	/* check sanity of loaded data */
+	if (notsane_logical(iter) || notsane_extended(iter)) {
+	    iter->status = PI_INSANE;
+	    return -1;
+	}
+
+	dp = ((struct disk_dos_mbr *)iter->data)->table;
+
+	iter->dos.cebr_lba = iter->dos.nebr_lba;
+	iter->dos.cebr_siz = iter->dos.nebr_siz;
+
+	/* setup next frame values */
+	if (dp[1].ostype) {
+	    iter->dos.nebr_lba = iter->dos.bebr_lba + dp[1].start_lba;
+	    iter->dos.nebr_siz = dp[1].length;
+	} else {
+	    iter->dos.nebr_lba = 0;
+	    iter->dos.nebr_siz = 0;
+	}
+
+	if (!dp[0].ostype)
+	    iter->dos.logskipcnt++;
+
+	if (dp[0].ostype || (iter->flags & PIF_STEPALL)) {
+	    *lba = dp[0].start_lba ? iter->dos.cebr_lba + dp[0].start_lba : 0;
+	    *_dp = dp;
+	    return 0;
+	}
+	/*
+	 * This way it's possible to continue, if some crazy soft left a "hole"
+	 * - EBR with a valid extended partition without a logical one. In
+	 * such case, linux will not reserve a number for such hole - so we
+	 * don't increase index0. If PIF_STEPALL flag is set, we will never
+	 * reach this place.
+	 */
+    }
+    iter->status = PI_DONE;
+    return -1;
+}
+
+static void gpt_conv_label(struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gp;
+    const int16_t *orig_lab;
+
+    gp = (const struct disk_gpt_part_entry *)
+	(iter->data + iter->index0 * iter->gpt.pe_size);
+    orig_lab = (const int16_t *)gp->name;
+
+    /* caveat: this is very crude conversion */
+    for (int i = 0; i < PI_GPTLABSIZE/2; i++) {
+	iter->gpt.part_label[i] = (char)orig_lab[i];
+    }
+    iter->gpt.part_label[PI_GPTLABSIZE/2] = 0;
+}
+
+static inline int valid_crc(uint32_t crc, const uint8_t *buf, unsigned int siz)
+{
+    return crc == crc32(crc32(0, NULL, 0), buf, siz);
+}
+
+static int valid_crc_hdr(void *buf)
+{
+    struct disk_gpt_header *gh = buf;
+    uint32_t crc = gh->chksum;
+    int valid;
+
+    gh->chksum = 0;
+    valid = crc == crc32(crc32(0, NULL, 0), buf, gh->hdr_size);
+    gh->chksum = crc;
+    return valid;
+}
+
+static int pi_next_(struct part_iter *iter)
+{
+    iter->status = PI_DONE;
+    return iter->status;
+}
+
+static int pi_dos_next(struct part_iter *iter)
+{
+    uint32_t abs_lba = 0;
+    struct disk_dos_part_entry *dos_part = NULL;
+
+    if (iter->status)
+	return iter->status;
+
+    /* look for primary partitions */
+    if (iter->index0 < 4 &&
+	    dos_next_mbr(iter, &abs_lba, &dos_part) < 0)
+	return iter->status;
+
+    /* look for logical partitions */
+    if (iter->index0 >= 4 &&
+	    dos_next_ebr(iter, &abs_lba, &dos_part) < 0)
+	return iter->status;
+
+    /*
+     * note special index handling:
+     * in case PIF_STEPALL is set - this makes the index consistent with
+     * non-PIF_STEPALL iterators
+     */
+
+    if (!dos_part->ostype)
+	iter->index = -1;
+    else
+	iter->index = iter->index0 + 1 - iter->dos.logskipcnt;
+    iter->abs_lba = abs_lba;
+    iter->length = dos_part->length;
+    iter->record = (char *)dos_part;
+
+#ifdef DEBUG
+    disk_dos_part_dump(dos_part);
+#endif
+
+    return iter->status;
+}
+
+static int pi_gpt_next(struct part_iter *iter)
+{
+    const struct disk_gpt_part_entry *gpt_part = NULL;
+
+    if (iter->status)
+	return iter->status;
+
+    while (++iter->index0 < iter->gpt.pe_count) {
+	gpt_part = (const struct disk_gpt_part_entry *)
+	    (iter->data + iter->index0 * iter->gpt.pe_size);
+
+	if (notsane_gpt(iter)) {
+	    iter->status = PI_INSANE;
+	    return iter->status;
+	}
+
+	if (!guid_is0(&gpt_part->type) || (iter->flags & PIF_STEPALL))
+	    break;
+    }
+    /* no more partitions ? */
+    if (iter->index0 == iter->gpt.pe_count) {
+	iter->status = PI_DONE;
+	return iter->status;
+    }
+    /* gpt_part is guaranteed to be valid here */
+    iter->index = iter->index0 + 1;
+    iter->abs_lba = gpt_part->lba_first;
+    iter->length = gpt_part->lba_last - gpt_part->lba_first + 1;
+    iter->record = (char *)gpt_part;
+    memcpy(&iter->gpt.part_guid, &gpt_part->uid, sizeof(struct guid));
+    gpt_conv_label(iter);
+
+#ifdef DEBUG
+    disk_gpt_part_dump(gpt_part);
+#endif
+
+    return iter->status;
+}
+
+static struct part_iter *pi_alloc(void)
+{
+    struct part_iter *iter;
+    if (!(iter = malloc(sizeof *iter)))
+	critm();
+    else
+	memset(iter, 0, sizeof *iter);
+    return iter;
+}
+
+/* pi_del() - delete iterator */
+void pi_del(struct part_iter **_iter)
+{
+    if(!_iter || !*_iter)
+	return;
+    pi_dtor(*_iter);
+    free(*_iter);
+    *_iter = NULL;
+}
+
+static void try_gpt_we(const char *str, int sec)
+{
+    if (sec)
+	error(str);
+    else
+	warn(str);
+}
+
+static struct disk_gpt_header *try_gpt_hdr(const struct disk_info *di, int sec)
+{
+    const char *desc = sec ? "backup" : "primary";
+    uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1;
+    struct disk_gpt_header *gpth;
+    char errbuf[64];
+
+    gpth = disk_read_sectors(di, gpt_cur, 1);
+    if (!gpth) {
+	sprintf(errbuf, "Unable to read %s GPT header.", desc);
+	try_gpt_we(errbuf, sec);
+	return NULL;
+    }
+    if(!valid_crc_hdr(gpth)) {
+	sprintf(errbuf, "Invalid checksum of %s GPT header.", desc);
+	try_gpt_we(errbuf, sec);
+	free(gpth);
+	return NULL;
+    }
+    return gpth;
+}
+
+static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt)
+{
+    int pri = gpth->lba_cur < gpth->lba_alt;
+    const char *desc = alt ? "alternative" : "main";
+    struct disk_gpt_part_entry *gptl;
+    char errbuf[64];
+    uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
+    uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
+    uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
+
+    gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
+    gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
+    if (!alt) {
+	/* prefer header value for partition table if not asking for alternative */
+	gpt_loff = gpth->lba_table;
+    } else {
+	/* try to read alternative, we have to calculate its position */
+	if (!pri)
+	    gpt_loff = gpth->lba_alt + 1;
+	else
+	    gpt_loff = gpth->lba_alt - gpt_lcnt;
+    }
+
+    gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt);
+    if (!gptl) {
+	sprintf(errbuf, "Unable to read %s GPT partition list.", desc);
+	try_gpt_we(errbuf, alt);
+	return NULL;
+    }
+    if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) {
+	sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc);
+	try_gpt_we(errbuf, alt);
+	free(gptl);
+	return NULL;
+    }
+    return gptl;
+}
+
+static int notsane_gpt_hdr(const struct disk_info *di, const struct disk_gpt_header *gpth, int flags)
+{
+    uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
+    uint64_t gpt_lsiz;	    /* size of GPT partition list in bytes */
+    uint64_t gpt_lcnt;	    /* size of GPT partition in sectors */
+    uint64_t gpt_sec;	    /* secondary gpt header */
+
+    if (!(flags & PIF_STRICT))
+	return 0;
+
+    if (gpth->lba_alt < gpth->lba_cur)
+	gpt_sec = gpth->lba_cur;
+    else
+	gpt_sec = gpth->lba_alt;
+    gpt_loff = gpth->lba_table;
+    gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count;
+    gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps;
+
+    /*
+     * disk_read_sectors allows reading of max 255 sectors, so we use
+     * it as a sanity check base. EFI doesn't specify max (AFAIK).
+     */
+    if (gpt_loff < 2 || !gpt_lsiz || gpt_lcnt > 255u ||
+	    gpth->lba_first_usable > gpth->lba_last_usable ||
+	    !sane(gpt_loff, gpt_lcnt) ||
+	    (gpt_loff + gpt_lcnt > gpth->lba_first_usable && gpt_loff <= gpth->lba_last_usable) ||
+	     gpt_loff + gpt_lcnt > gpt_sec ||
+	    ((flags & PIF_STRICTER) && (gpt_sec >= di->lbacnt)) ||
+	    gpth->part_size < sizeof(struct disk_gpt_part_entry))
+	return -1;
+
+    return 0;
+}
+
+/* pi_begin() - validate and and get proper iterator for a disk described by di */
+struct part_iter *pi_begin(const struct disk_info *di, int flags)
+{
+    int isgpt = 0, ret = -1;
+    struct part_iter *iter;
+    struct disk_dos_mbr *mbr = NULL;
+    struct disk_gpt_header *gpth = NULL;
+    struct disk_gpt_part_entry *gptl = NULL;
+
+    /* Preallocate iterator */
+    if (!(iter = pi_alloc()))
+	goto out;
+
+    /* Read MBR */
+    if (!(mbr = disk_read_sectors(di, 0, 1))) {
+	error("Unable to read the first disk sector.");
+	goto out;
+    }
+
+    /* Check for MBR magic */
+    if (mbr->sig != disk_mbr_sig_magic) {
+	warn("No MBR magic, treating disk as raw.");
+	/* looks like RAW */
+	ret = pi_ctor(iter, di, flags);
+	goto out;
+    }
+
+    /* Check for GPT protective MBR */
+    for (size_t i = 0; i < 4; i++)
+	isgpt |= (mbr->table[i].ostype == 0xEE);
+    isgpt = isgpt && !(flags & PIF_PREFMBR);
+
+    /* Try to read GPT header */
+    if (isgpt) {
+	gpth = try_gpt_hdr(di, 0);
+	if (!gpth)
+	    /*
+	     * this read might fail if bios reports different disk size (different vm/pc)
+	     * not much we can do here to avoid it
+	     */
+	    gpth = try_gpt_hdr(di, 1);
+	if (!gpth)
+	    goto out;
+    }
+
+    if (gpth && gpth->rev.uint32 == 0x00010000 &&
+	    !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) {
+	/* looks like GPT v1.0 */
+#ifdef DEBUG
+	dprintf("Looks like a GPT v1.0 disk.\n");
+	disk_gpt_header_dump(gpth);
+#endif
+	if (notsane_gpt_hdr(di, gpth, flags)) {
+	    error("GPT header values are corrupted.");
+	    goto out;
+	}
+
+	gptl = try_gpt_list(di, gpth, 0);
+	if (!gptl)
+	    gptl = try_gpt_list(di, gpth, 1);
+	if (!gptl)
+	    goto out;
+
+	/* looks like GPT */
+	ret = pi_gpt_ctor(iter, di, flags, gpth, gptl);
+    } else {
+	/* looks like MBR */
+	ret = pi_dos_ctor(iter, di, flags, mbr);
+    }
+out:
+    if (ret < 0) {
+	free(iter);
+	iter = NULL;
+    }
+    free(mbr);
+    free(gpth);
+    free(gptl);
+
+    return iter;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/partiter.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/partiter.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/partiter.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,119 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * partiter.h
+ *
+ * Provides disk / partition iteration.
+ */
+
+#ifndef COM32_CHAIN_PARTITER_H
+#define COM32_CHAIN_PARTITER_H
+
+#include <stdint.h>
+#include <syslinux/disk.h>
+
+/* status */
+
+enum {PI_ERRLOAD = -31, PI_INSANE, PI_OK = 0, PI_DONE};
+
+/* flags */
+
+enum {PIF_STEPALL = 1, PIF_PREFMBR = 2, PIF_STRICT = 4, PIF_STRICTER = 8};
+
+struct itertype;
+struct part_iter;
+
+struct itertype {
+	void (*dtor)(struct part_iter *);
+	int  (*next)(struct part_iter *);
+};
+
+#define PI_GPTLABSIZE ((int)sizeof(((struct disk_gpt_part_entry *)0)->name))
+
+struct part_iter {
+    const struct itertype *type;
+    char *data;
+    char *record;
+    uint64_t abs_lba;
+    uint64_t length;
+    int index0;	    /* including holes, from -1 (disk, then parts from 0) */
+    int index;	    /* excluding holes, from  0 (disk, then parts from 1), -1 means hole, if PIF_STEPALL is set */
+    int flags;	    /* flags, see #defines above */
+    int status;	    /* current status, see enums above */
+    struct disk_info di;
+    union {
+	struct {
+	    uint32_t disk_sig;	  /* 32bit disk signature as stored in MBR */
+
+	    uint32_t bebr_lba;	  /* absolute lba of base extended partition */
+	    uint32_t bebr_siz;	  /* size of base extended partition */
+
+	    uint32_t cebr_lba;	  /* absolute lba of curr ext. partition */
+	    uint32_t cebr_siz;	  /* size of curr ext. partition */
+	    uint32_t nebr_lba;	  /* absolute lba of next ext. partition */
+	    uint32_t nebr_siz;	  /* size of next ext. partition */
+
+	    int bebr_index0;	  /* index of (0-3) of base ext. part., -1 if not present in MBR */
+	    int logskipcnt;	  /* how many logical holes were skipped */
+	} dos;
+	struct {
+	    struct guid disk_guid;
+	    struct guid part_guid;
+	    char part_label[PI_GPTLABSIZE/2+1];
+	    int pe_count;
+	    int pe_size;
+	    uint64_t ufirst;
+	    uint64_t ulast;
+	} gpt;
+    };
+};
+
+extern const struct itertype * const typedos;
+extern const struct itertype * const typegpt;
+extern const struct itertype * const typeraw;
+
+struct part_iter *pi_begin(const struct disk_info *, int flags);
+void pi_del(struct part_iter **);
+
+/* inline virtuals */
+static inline int pi_next(struct part_iter *iter)
+{
+    return iter->type->next(iter);
+}
+
+static inline void pi_dtor(struct part_iter *iter)
+{
+    iter->type->dtor(iter);
+}
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/utility.c
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/utility.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/utility.c	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,256 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <com32.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <fs.h>
+#include <syslinux/disk.h>
+#include <syslinux/pmapi.h>
+#include "utility.h"
+
+static const char *bpbtypes[] = {
+    [0] =  "unknown",
+    [1] =  "2.0",
+    [2] =  "3.0",
+    [3] =  "3.2",
+    [4] =  "3.4",
+    [5] =  "4.0",
+    [6] =  "8.0 (NT+)",
+    [7] =  "7.0",
+    [8] =  "exFAT",
+};
+
+void wait_key(void)
+{
+    int cnt;
+    char junk;
+
+    /* drain */
+    do {
+	errno = 0;
+	cnt = read(0, &junk, 1);
+    } while (cnt > 0 || (cnt < 0 && errno == EAGAIN));
+
+    /* wait */
+    do {
+	errno = 0;
+	cnt = read(0, &junk, 1);
+    } while (!cnt || (cnt < 0 && errno == EAGAIN));
+}
+
+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;
+
+    /*
+     * Not much reason here, but if we have no valid CHS geometry, we assume
+     * "typical" ones to have something to return.
+     */
+    if (di->cbios) {
+	cs = di->cyl;
+	hs = di->head;
+	ss = di->spt;
+	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) {
+	    cs = 1024;
+	    hs = 255;
+	    ss = 63;
+	} else {
+	    cs = 80;
+	    hs = 2;
+	    ss = 18;
+	}
+    }
+
+    if (lba >= cs*hs*ss) {
+	s = ss;
+	h = hs - 1;
+	c = cs - 1;
+    } else {
+	s = (lba % ss) + 1;
+	t = lba / ss;
+	h = t % hs;
+	c = t / hs;
+    }
+
+    (*dst)[0] = h;
+    (*dst)[1] = s | ((c & 0x300) >> 2);
+    (*dst)[2] = c;
+}
+
+uint32_t get_file_lba(const char *filename)
+{
+    struct com32_filedata fd;
+    uint32_t lba = 0;
+    int size = 65536;
+    char *buf;
+
+    buf = lmalloc(size);
+    if (!buf)
+	return 0;
+
+    /* Put the filename in the bounce buffer */
+    strlcpy(buf, filename, size);
+
+    if (open_file(buf, O_RDONLY, &fd) <= 0) {
+	goto fail;		/* Filename not found */
+    }
+
+    /* Since the first member is the LBA, we simply cast */
+    lba = *((uint32_t *) MK_PTR(0, fd.handle));
+
+    /* Call comapi_close() to free the structure */
+    close_file(fd.handle);
+
+fail:
+    lfree(buf);
+    return lba;
+}
+
+/* drive offset detection */
+int drvoff_detect(int type)
+{
+    if (bpbV40 <= type && type <= bpbVNT) {
+	return 0x24;
+    } else if (type == bpbV70) {
+	return 0x40;
+    } else if (type == bpbEXF) {
+	return 0x6F;
+    }
+
+    return -1;
+}
+
+/*
+ * heuristics could certainly be improved
+ */
+int bpb_detect(const uint8_t *sec, const char *tag)
+{
+    int a, b, c, jmp = -1, rev = 0;
+
+    /* exFAT mess first (media descriptor is 0 here) */
+    if (!memcmp(sec + 0x03, "EXFAT   ", 8)) {
+	rev = bpbEXF;
+	goto out;
+    }
+
+    /* media descriptor check */
+    if ((sec[0x15] & 0xF0) != 0xF0)
+	goto out;
+
+    if (sec[0] == 0xEB)	/* jump short */
+	jmp = 2 + *(int8_t *)(sec + 1);
+    else if (sec[0] == 0xE9) /* jump near */
+	jmp = 3 + *(int16_t *)(sec + 1);
+
+    if (jmp < 0)    /* no boot code at all ? */
+	goto nocode;
+
+    /* sanity */
+    if (jmp < 0x18 || jmp > 0x1F0)
+	goto out;
+
+    /* detect by jump */
+    if (jmp >= 0x18 && jmp < 0x1E)
+	rev = bpbV20;
+    else if (jmp >= 0x1E && jmp < 0x20)
+	rev = bpbV30;
+    else if (jmp >= 0x20 && jmp < 0x24)
+	rev = bpbV32;
+    else if (jmp >= 0x24 && jmp < 0x46)
+	rev = bpbV34;
+
+    /* TODO: some better V2 - V3.4 checks ? */
+
+    if (rev)
+	goto out;
+    /*
+     * BPB info:
+     * 2.0 ==       0x0B - 0x17
+     * 3.0 == 2.0 + 0x18 - 0x1D
+     * 3.2 == 3.0 + 0x1E - 0x1F
+     * 3.4 ==!2.0 + 0x18 - 0x23
+     * 4.0 == 3.4 + 0x24 - 0x45
+     *  NT ==~3.4 + 0x24 - 0x53
+     * 7.0 == 3.4 + 0x24 - 0x59
+     */
+
+nocode:
+    a = memcmp(sec + 0x03, "NTFS", 4);
+    b = memcmp(sec + 0x36, "FAT", 3);
+    c = memcmp(sec + 0x52, "FAT", 3);	/* ext. DOS 7+ bs */
+
+    if ((sec[0x26] & 0xFE) == 0x28 && !b) {
+	rev = bpbV40;
+    } else if (sec[0x26] == 0x80 && !a) {
+	rev = bpbVNT;
+    } else if ((sec[0x42] & 0xFE) == 0x28 && !c) {
+	rev = bpbV70;
+    }
+
+out:
+    printf("BPB detection (%s): %s\n", tag, bpbtypes[rev]);
+    return rev;
+}
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
Index: bootcd/isolinux/syslinux-6.03/com32/chain/utility.h
===================================================================
--- bootcd/isolinux/syslinux-6.03/com32/chain/utility.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
+++ bootcd/isolinux/syslinux-6.03/com32/chain/utility.h	(revision e16e8f2a41938d263af54a9fd6b4020d6c0d69fa)
@@ -0,0 +1,75 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2012 Michal Soltys
+ *
+ *   Permission is hereby granted, free of charge, to any person
+ *   obtaining a copy of this software and associated documentation
+ *   files (the "Software"), to deal in the Software without
+ *   restriction, including without limitation the rights to use,
+ *   copy, modify, merge, publish, distribute, sublicense, and/or
+ *   sell copies of the Software, and to permit persons to whom
+ *   the Software is furnished to do so, subject to the following
+ *   conditions:
+ *
+ *   The above copyright notice and this permission notice shall
+ *   be included in all copies or substantial portions of the Software.
+ *
+ *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *   OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#ifndef COM32_CHAIN_UTILITY_H
+#define COM32_CHAIN_UTILITY_H
+
+#include <stdint.h>
+#include <stdio.h>
+#include <syslinux/disk.h>
+#include <syslinux/movebits.h>
+
+/* most (all ?) bpb "types" known to humankind as of 2012 */
+enum {bpbUNK, bpbV20, bpbV30, bpbV32, bpbV34, bpbV40, bpbVNT, bpbV70, bpbEXF};
+
+/* see utility.c for details */
+enum {L2C_CNUL, L2C_CADD, L2C_CMAX};
+
+/* first usable and first unusable offsets */
+#define dosmin ((addr_t)0x500u)
+#define dosmax ((addr_t)(*(uint16_t *) 0x413 << 10))
+
+void wait_key(void);
+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);
+int bpb_detect(const uint8_t *bpb, const char *tag);
+int guid_is0(const struct guid *guid);
+
+static inline int warn(const char *x)
+{
+    return fprintf(stderr, "WARN: %s\n", x);
+}
+
+static inline int error(const char *x)
+{
+    return fprintf(stderr, "ERR: %s\n", x);
+}
+
+static inline int crit(const char *x)
+{
+    return fprintf(stderr, "CRIT: %s @%s:%d\n", x, __FILE__, __LINE__);
+}
+
+#define critm()  crit("Malloc failure.")
+
+#endif
+
+/* vim: set ts=8 sts=4 sw=4 noet: */
