[syslinux] [PULL 1/8] Move partiter from com32/chain to com32/lib/syslinux

Paulo Alcantara pcacjr at gmail.com
Wed Jul 22 16:27:23 PDT 2015


From: "Raphael S. Carvalho" <raphael.scarv at gmail.com>

MultiFS depends on the availability of partiter to find a partition.

Cc: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: Raphael S. Carvalho <raphael.scarv at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 com32/chain/Makefile              |   2 +-
 com32/chain/chain.c               |   4 +-
 com32/chain/mangle.c              |   4 +-
 com32/chain/mangle.h              |   2 +-
 com32/chain/options.c             |   4 +-
 com32/chain/partiter.c            | 726 --------------------------------------
 com32/chain/partiter.h            | 119 -------
 com32/chain/utility.c             | 256 --------------
 com32/chain/utility.h             |  75 ----
 com32/include/syslinux/partiter.h | 119 +++++++
 com32/include/syslinux/utility.h  |  76 ++++
 com32/lib/syslinux/partiter.c     | 726 ++++++++++++++++++++++++++++++++++++++
 com32/lib/syslinux/utility.c      | 256 ++++++++++++++
 mk/lib.mk                         |   2 +-
 14 files changed, 1186 insertions(+), 1185 deletions(-)
 delete mode 100644 com32/chain/partiter.c
 delete mode 100644 com32/chain/partiter.h
 delete mode 100644 com32/chain/utility.c
 delete mode 100644 com32/chain/utility.h
 create mode 100644 com32/include/syslinux/partiter.h
 create mode 100644 com32/include/syslinux/utility.h
 create mode 100644 com32/lib/syslinux/partiter.c
 create mode 100644 com32/lib/syslinux/utility.c

diff --git a/com32/chain/Makefile b/com32/chain/Makefile
index d7b5aa8..a7d1f66 100644
--- a/com32/chain/Makefile
+++ b/com32/chain/Makefile
@@ -16,7 +16,7 @@
 VPATH = $(SRC)
 include $(MAKEDIR)/elf.mk
 
-OBJS = chain.o partiter.o utility.o options.o mangle.o
+OBJS = chain.o options.o mangle.o
 CFLAGS += -fno-strict-aliasing
 
 all: chain.c32
diff --git a/com32/chain/chain.c b/com32/chain/chain.c
index 4e9e32d..f9fe07e 100644
--- a/com32/chain/chain.c
+++ b/com32/chain/chain.c
@@ -35,9 +35,9 @@
 #include <syslinux/disk.h>
 #include <syslinux/video.h>
 #include "chain.h"
-#include "utility.h"
+#include <syslinux/utility.h>
 #include "options.h"
-#include "partiter.h"
+#include <syslinux/partiter.h>
 #include "mangle.h"
 
 static int fixed_cnt = 128;   /* see comments in main() */
diff --git a/com32/chain/mangle.c b/com32/chain/mangle.c
index 275d0aa..64d9c19 100644
--- a/com32/chain/mangle.c
+++ b/com32/chain/mangle.c
@@ -37,8 +37,8 @@
 #include <syslinux/config.h>
 #include "chain.h"
 #include "options.h"
-#include "utility.h"
-#include "partiter.h"
+#include <syslinux/utility.h>
+#include <syslinux/partiter.h>
 #include "mangle.h"
 
 static const char cmldr_signature[8] = "cmdcons";
diff --git a/com32/chain/mangle.h b/com32/chain/mangle.h
index 42f6c5b..98b2f2c 100644
--- a/com32/chain/mangle.h
+++ b/com32/chain/mangle.h
@@ -32,7 +32,7 @@
 #define COM32_CHAIN_MANGLE_H
 
 #include "chain.h"
-#include "partiter.h"
+#include <syslinux/partiter.h>
 
 /* file's manglers */
 int manglef_isolinux(struct data_area *data);
diff --git a/com32/chain/options.c b/com32/chain/options.c
index 2b51939..b3c986e 100644
--- a/com32/chain/options.c
+++ b/com32/chain/options.c
@@ -33,8 +33,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include "chain.h"
-#include "partiter.h"
-#include "utility.h"
+#include <syslinux/partiter.h>
+#include <syslinux/utility.h>
 #include "options.h"
 
 struct options opt;
diff --git a/com32/chain/partiter.c b/com32/chain/partiter.c
deleted file mode 100644
index 4937f0c..0000000
--- a/com32/chain/partiter.c
+++ /dev/null
@@ -1,726 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2015 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_gpth(struct disk_gpt_header *gh, int flags)
-{
-    uint32_t crc, crcc;
-
-    if (!(flags & PIF_GPTHCRC))
-	return 1;
-
-    crc = gh->chksum;
-    gh->chksum = 0;
-    crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gh, gh->hdr_size);
-    gh->chksum = crc;
-    return crc == crcc;
-}
-
-static int valid_crc_gptl(const struct disk_gpt_header *gh, const struct disk_gpt_part_entry *gl, int flags)
-{
-    uint32_t crcc;
-
-    if (!(flags & PIF_GPTLCRC))
-	return 1;
-
-    crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gl, gh->part_size * gh->part_count);
-    return gh->table_chksum == crcc;
-}
-
-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 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;
-}
-
-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, int flags)
-{
-    const char *desc = sec ? "backup" : "primary";
-    uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1;
-    struct disk_gpt_header *gpth;
-    char errbuf[96];
-
-    gpth = disk_read_sectors(di, gpt_cur, 1);
-    if (!gpth) {
-	sprintf(errbuf, "Unable to read %s GPT header.", desc);
-	goto out;
-    }
-    if(!valid_crc_gpth(gpth, flags)) {
-	sprintf(errbuf, "Invalid checksum of %s GPT header.", desc);
-	goto out;
-    }
-    if(notsane_gpt_hdr(di, gpth, flags)) {
-	sprintf(errbuf, "Checksum of %s GPT header is valid, but values fail sanity checks.", desc);
-	goto out;
-    }
-    return gpth;
-out:
-    try_gpt_we(errbuf, sec);
-    free(gpth);
-    return NULL;
-}
-
-static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt, int flags)
-{
-    int pri = gpth->lba_cur < gpth->lba_alt;
-    const char *desc = alt ? "alternative" : "main";
-    struct disk_gpt_part_entry *gptl;
-    char errbuf[64];
-    uint32_t gpt_lcnt;	    /* size of GPT partition in sectors */
-    uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
-
-    gpt_lcnt = (gpth->part_size * gpth->part_count + 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);
-	goto out;
-    }
-    if (!valid_crc_gptl(gpth, gptl, flags)) {
-	sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc);
-	goto out;
-    }
-    return gptl;
-out:
-    try_gpt_we(errbuf, alt);
-    free(gptl);
-    return NULL;
-}
-
-/* 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, flags);
-	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, flags);
-	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
-	gptl = try_gpt_list(di, gpth, 0, flags);
-	if (!gptl)
-	    gptl = try_gpt_list(di, gpth, 1, flags);
-	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: */
diff --git a/com32/chain/partiter.h b/com32/chain/partiter.h
deleted file mode 100644
index a48f8d6..0000000
--- a/com32/chain/partiter.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2015 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, PIF_GPTHCRC = 16, PIF_GPTLCRC = 32};
-
-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: */
diff --git a/com32/chain/utility.c b/com32/chain/utility.c
deleted file mode 100644
index 180749e..0000000
--- a/com32/chain/utility.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2015 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: */
diff --git a/com32/chain/utility.h b/com32/chain/utility.h
deleted file mode 100644
index f8e9c61..0000000
--- a/com32/chain/utility.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
- *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
- *   Copyright 2010 Shao Miller
- *   Copyright 2010-2015 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: */
diff --git a/com32/include/syslinux/partiter.h b/com32/include/syslinux/partiter.h
new file mode 100644
index 0000000..a48f8d6
--- /dev/null
+++ b/com32/include/syslinux/partiter.h
@@ -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-2015 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, PIF_GPTHCRC = 16, PIF_GPTLCRC = 32};
+
+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: */
diff --git a/com32/include/syslinux/utility.h b/com32/include/syslinux/utility.h
new file mode 100644
index 0000000..e2667a0
--- /dev/null
+++ b/com32/include/syslinux/utility.h
@@ -0,0 +1,76 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2015 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>
+#include <klibc/compiler.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 __unusedfunc 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: */
diff --git a/com32/lib/syslinux/partiter.c b/com32/lib/syslinux/partiter.c
new file mode 100644
index 0000000..3ae2583
--- /dev/null
+++ b/com32/lib/syslinux/partiter.c
@@ -0,0 +1,726 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
+ *   Copyright 2010 Shao Miller
+ *   Copyright 2010-2015 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 <syslinux/partiter.h>
+#include <syslinux/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 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_gpth(struct disk_gpt_header *gh, int flags)
+{
+    uint32_t crc, crcc;
+
+    if (!(flags & PIF_GPTHCRC))
+	return 1;
+
+    crc = gh->chksum;
+    gh->chksum = 0;
+    crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gh, gh->hdr_size);
+    gh->chksum = crc;
+    return crc == crcc;
+}
+
+static int valid_crc_gptl(const struct disk_gpt_header *gh, const struct disk_gpt_part_entry *gl, int flags)
+{
+    uint32_t crcc;
+
+    if (!(flags & PIF_GPTLCRC))
+	return 1;
+
+    crcc = crc32(crc32(0, NULL, 0), (const uint8_t *)gl, gh->part_size * gh->part_count);
+    return gh->table_chksum == crcc;
+}
+
+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 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;
+}
+
+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, int flags)
+{
+    const char *desc = sec ? "backup" : "primary";
+    uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1;
+    struct disk_gpt_header *gpth;
+    char errbuf[96];
+
+    gpth = disk_read_sectors(di, gpt_cur, 1);
+    if (!gpth) {
+	sprintf(errbuf, "Unable to read %s GPT header.", desc);
+	goto out;
+    }
+    if(!valid_crc_gpth(gpth, flags)) {
+	sprintf(errbuf, "Invalid checksum of %s GPT header.", desc);
+	goto out;
+    }
+    if(notsane_gpt_hdr(di, gpth, flags)) {
+	sprintf(errbuf, "Checksum of %s GPT header is valid, but values fail sanity checks.", desc);
+	goto out;
+    }
+    return gpth;
+out:
+    try_gpt_we(errbuf, sec);
+    free(gpth);
+    return NULL;
+}
+
+static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt, int flags)
+{
+    int pri = gpth->lba_cur < gpth->lba_alt;
+    const char *desc = alt ? "alternative" : "main";
+    struct disk_gpt_part_entry *gptl;
+    char errbuf[64];
+    uint32_t gpt_lcnt;	    /* size of GPT partition in sectors */
+    uint64_t gpt_loff;	    /* offset to GPT partition list in sectors */
+
+    gpt_lcnt = (gpth->part_size * gpth->part_count + 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);
+	goto out;
+    }
+    if (!valid_crc_gptl(gpth, gptl, flags)) {
+	sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc);
+	goto out;
+    }
+    return gptl;
+out:
+    try_gpt_we(errbuf, alt);
+    free(gptl);
+    return NULL;
+}
+
+/* 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, flags);
+	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, flags);
+	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
+	gptl = try_gpt_list(di, gpth, 0, flags);
+	if (!gptl)
+	    gptl = try_gpt_list(di, gpth, 1, flags);
+	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: */
diff --git a/com32/lib/syslinux/utility.c b/com32/lib/syslinux/utility.c
new file mode 100644
index 0000000..ecf5a37
--- /dev/null
+++ b/com32/lib/syslinux/utility.c
@@ -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-2015 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 <syslinux/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: */
diff --git a/mk/lib.mk b/mk/lib.mk
index ceb95bd..c56d3e3 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -106,7 +106,7 @@ LIBOTHER_OBJS = \
 	pci/writeb.o pci/writew.o pci/writel.o	\
 	\
 	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
-	syslinux/disk.o							\
+	syslinux/disk.o	syslinux/utility.o syslinux/partiter.o		\
 	\
 	syslinux/setup_data.o
 
-- 
2.1.0



More information about the Syslinux mailing list