Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 0/8] MultiFS suppport for BIOS and EFI
So last week I was wondering if XFS was still working -- even with its
last on-disk structure changes -- and it _suprisingly_ worked as
expected. Right, now I can finally get rid of GRUB and use Syslinux to
boot my Linux on EFI from a rootfs with xfs. Shit, I have two
partitions (the first one being the required ESP) so there is no way to
access the other partitions since because Syslinux does not support
multiple disk and/or partitions -- yet.
I completly refused to accept that and then looked at the current status
of MultiFS support; its original implementation only worked on BIOS.
Therefore I started working on EFI support and -- luckily enough -- I
also had Raphael to help me with development and testing.
(I'm really glad to hack Syslinux again. What a great project...)
The MultiFS syntax is basically "(hdX,Y)/path/to/file", where X is
disk
number and Y is partition number.
Please test it and report to us if any issue found.
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
The following changes since commit 8702009fc7a6689432d17d4ea05d9c878452c57a:
  efi: rename pxe_handle to image_device_handle (2015-07-19 08:09:10 -0400)
are available in the git repository at:
  git://git.zytor.com/users/pcacjr/syslinux.git multifs-for-upstream
for you to fetch changes up to b8ca887baec49b6375e12a2ef5847dd4f2017232:
  efi/multifs: fix misuse of static private information (2015-07-22 19:20:43
-0300)
----------------------------------------------------------------
Paulo Alcantara (5):
      ldlinux/kernel: contemplate multifs path syntax
      efi: add MultiFS support
      sys/common: handle multifs paths in findpath()
      multifs: add support for both UEFI and BIOS firmware
      efi/multifs: fix misuse of static private information
Raphael S. Carvalho (3):
      Move partiter from com32/chain to com32/lib/syslinux
      core: MultiFS infrastructure added.
      Wire up MultiFS support.
 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/elflink/ldlinux/kernel.c               |   9 ++
 com32/elflink/ldlinux/ldlinux.c              |   9 ++
 com32/include/syslinux/multifs_utils.h       |  32 ++++
 com32/{chain => include/syslinux}/partiter.h |   0
 com32/{chain => include/syslinux}/utility.h  |   3 +-
 com32/lib/sys/module/common.c                |   7 +-
 com32/lib/syslinux/multifs_utils.c           |  91 +++++++++++
 com32/{chain => lib/syslinux}/partiter.c     |   6 +-
 com32/{chain => lib/syslinux}/utility.c      |   2 +-
 core/bios.c                                  |  11 ++
 core/fs/cache.c                              |   2 +-
 core/fs/diskio.c                             |  28 +++-
 core/fs/diskio_bios.c                        |  40 ++---
 core/fs/fs.c                                 |  21 ++-
 core/fs/readdir.c                            |   8 +-
 core/include/multifs.h                       |  50 ++++++
 core/multifs.c                               | 221 +++++++++++++++++++++++++++
 core/multifs_bios.c                          |  75 +++++++++
 efi/diskio.c                                 |  32 ++--
 efi/main.c                                   |  26 +++-
 efi/multifs.c                                | 166 ++++++++++++++++++++
 efi/multifs_utils.h                          |  52 +++++++
 mk/lib.mk                                    |   3 +-
 28 files changed, 845 insertions(+), 65 deletions(-)
 create mode 100644 com32/include/syslinux/multifs_utils.h
 rename com32/{chain => include/syslinux}/partiter.h (100%)
 rename com32/{chain => include/syslinux}/utility.h (97%)
 create mode 100644 com32/lib/syslinux/multifs_utils.c
 rename com32/{chain => lib/syslinux}/partiter.c (99%)
 rename com32/{chain => lib/syslinux}/utility.c (99%)
 create mode 100644 core/include/multifs.h
 create mode 100644 core/multifs.c
 create mode 100644 core/multifs_bios.c
 create mode 100644 efi/multifs.c
 create mode 100644 efi/multifs_utils.h
-- 
2.1.0
Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 1/8] Move partiter from com32/chain to com32/lib/syslinux
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
Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 2/8] core: MultiFS infrastructure added.
From: "Raphael S. Carvalho" <raphael.scarv at gmail.com>
MULTIFS SYNTAX:
(hd[disk number],[partition number])/path/to/file
The meaning of this_fs was changed to improve the flexibility of the support.
Now, this_fs means the file system being currently used.
root_fs was created to save the context of the main file system (where
ldlinux.sys lives in).
get_fs_info is a function pointer that will be later hooked to a function from
ldlinux.c32.
get_fs_info is expected to return a fs_info structure given the MultiFS path.
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>
---
 core/fs/cache.c        |  2 +-
 core/fs/diskio.c       | 28 ++++++++++++++-----
 core/fs/diskio_bios.c  | 40 ++++++++++++++------------
 core/fs/fs.c           | 22 +++++++++++----
 core/fs/readdir.c      |  9 +++++-
 core/include/multifs.h | 61 ++++++++++++++++++++++++++++++++++++++++
 core/multifs.c         | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 206 insertions(+), 32 deletions(-)
 create mode 100644 core/include/multifs.h
 create mode 100644 core/multifs.c
diff --git a/core/fs/cache.c b/core/fs/cache.c
index 8da75bc..31a5db3 100644
--- a/core/fs/cache.c
+++ b/core/fs/cache.c
@@ -15,7 +15,7 @@
  * the block size, which is 512 byte for FAT fs of the current 
  * implementation since the block(cluster) size in FAT is a bit big.
  */
-void cache_init(struct device *dev, int block_size_shift)
+__export void cache_init(struct device *dev, int block_size_shift)
 {
     struct cache *prev, *cur;
     char *data = dev->cache_data;
diff --git a/core/fs/diskio.c b/core/fs/diskio.c
index e9a4c1d..94cc351 100644
--- a/core/fs/diskio.c
+++ b/core/fs/diskio.c
@@ -21,14 +21,28 @@ void getoneblk(struct disk *disk, char *buf, block_t block,
int block_size)
 /*
  * Initialize the device structure.
  */
-struct device * device_init(void *args)
+__export struct device *device_init(void *args)
 {
-    static struct device dev;
+    struct device *dev;
 
-    dev.disk = firmware->disk_init(args);
-    dev.cache_size = 128*1024;
-    dev.cache_data = malloc(dev.cache_size);
-    dev.cache_init = 0; /* Explicitly set cache as uninitialized */
+    dev = malloc(sizeof(struct device));
+    if (!dev)
+        return NULL;
 
-    return &dev;
+    dev->disk = firmware->disk_init(args);
+    if (!dev->disk)
+	goto out;
+
+    dev->cache_size = 128*1024;
+    dev->cache_data = malloc(dev->cache_size);
+    if (!dev->cache_data)
+	goto out_disk;
+    dev->cache_init = 0;
+
+    return dev;
+out_disk:
+    free(dev->disk);
+out:
+    free(dev);
+    return NULL;
 }
diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c
index 7feb7fc..621896f 100644
--- a/core/fs/diskio_bios.c
+++ b/core/fs/diskio_bios.c
@@ -287,7 +287,7 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf,
 
 struct disk *bios_disk_init(void *private)
 {
-    static struct disk disk;
+    struct disk *disk;
     struct bios_disk_private *priv = (struct bios_disk_private *)private;
     com32sys_t *regs = priv->regs;
     static __lowmem struct edd_disk_params edd_params;
@@ -302,6 +302,10 @@ struct disk *bios_disk_init(void *private)
     int sector_size;
     unsigned int hard_max_transfer;
 
+    disk = malloc(sizeof(struct disk));
+    if (!disk)
+        return NULL;
+
     memset(&ireg, 0, sizeof ireg);
     ireg.edx.b[0] = devno;
 
@@ -319,18 +323,18 @@ struct disk *bios_disk_init(void *private)
 	hard_max_transfer = 63;
 
 	/* CBIOS parameters */
-	disk.h = bsHeads;
-	disk.s = bsSecPerTrack;
+	disk->h = bsHeads;
+	disk->s = bsSecPerTrack;
 
 	if ((int8_t)devno < 0) {
 	    /* Get hard disk geometry from BIOS */
-	    
+
 	    ireg.eax.b[1] = 0x08;
 	    __intcall(0x13, &ireg, &oreg);
-	    
+
 	    if (!(oreg.eflags.l & EFLAGS_CF)) {
-		disk.h = oreg.edx.b[1] + 1;
-		disk.s = oreg.ecx.b[0] & 63;
+		disk->h = oreg.edx.b[1] + 1;
+		disk->s = oreg.ecx.b[0] & 63;
 	    }
 	}
 
@@ -374,24 +378,24 @@ struct disk *bios_disk_init(void *private)
 
     }
 
-    disk.disk_number   = devno;
-    disk.sector_size   = sector_size;
-    disk.sector_shift  = ilog2(sector_size);
-    disk.part_start    = part_start;
-    disk.secpercyl     = disk.h * disk.s;
-    disk.rdwr_sectors  = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
+    disk->disk_number   = devno;
+    disk->sector_size   = sector_size;
+    disk->sector_shift  = ilog2(sector_size);
+    disk->part_start    = part_start;
+    disk->secpercyl     = disk->h * disk->s;
+    disk->rdwr_sectors  = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
 
     if (!MaxTransfer || MaxTransfer > hard_max_transfer)
 	MaxTransfer = hard_max_transfer;
 
-    disk.maxtransfer   = MaxTransfer;
+    disk->maxtransfer   = MaxTransfer;
 
     dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit
%u\n",
-	    devno, cdrom, ebios, sector_size, disk.sector_shift,
-	    part_start, disk.maxtransfer);
+	    devno, cdrom, ebios, sector_size, disk->sector_shift,
+	    part_start, disk->maxtransfer);
 
-    disk.private = private;
-    return &disk;
+    disk->private = private;
+    return disk;
 }
 
 void pm_fs_init(com32sys_t *regs)
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 4161848..a5d8db4 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -10,9 +10,14 @@
 #include "dev.h"
 #include "fs.h"
 #include "cache.h"
+#include "multifs.h"
 
-/* The currently mounted filesystem */
-__export struct fs_info *this_fs = NULL;		/* Root filesystem */
+/* root_fs means the file system where ldlinux.sys lives in. */
+__export struct fs_info *root_fs = NULL;
+/* this_fs means the file system being currently used. */
+__export struct fs_info *this_fs = NULL;
+/* export p_ops to be used outside the core */
+__export const struct fs_ops **p_ops = NULL;
 
 /* Actual file structures (we don't have malloc yet...) */
 __export struct file files[MAX_OPEN];
@@ -345,6 +350,9 @@ __export int open_file(const char *name, int flags, struct
com32_filedata *filed
 
     dprintf("open_file %s\n", name);
 
+    if (switch_fs(&name))
+	return -1;
+
     mangle_name(mangled_name, name);
     rv = searchdir(mangled_name, flags);
 
@@ -362,6 +370,9 @@ __export int open_file(const char *name, int flags, struct
com32_filedata *filed
     filedata->blocklg2	= SECTOR_SHIFT(file->fs);
     filedata->handle	= rv;
 
+    restore_fs();
+    restore_chdir_start();
+
     return rv;
 }
 
@@ -403,6 +414,7 @@ void fs_init(const struct fs_ops **ops, void *priv)
 
     /* Default name for the root directory */
     fs.cwd_name[0] = '/';
+    p_ops = ops;
 
     while ((blk_shift < 0) && *ops) {
 	/* set up the fs stucture */
@@ -428,7 +440,7 @@ void fs_init(const struct fs_ops **ops, void *priv)
 	while (1)
 		;
     }
-    this_fs = &fs;
+    root_fs = this_fs = &fs;
 
     /* initialize the cache only if it wasn't already initialized
      * by the fs driver */
@@ -443,8 +455,8 @@ void fs_init(const struct fs_ops **ops, void *priv)
     }
 
     if (fs.fs_ops->chdir_start) {
-	    if (fs.fs_ops->chdir_start() < 0)
-		    printf("Failed to chdir to start directory\n");
+	if (fs.fs_ops->chdir_start() < 0)
+	    printf("Failed to chdir to start directory\n");
     }
 
     SectorShift = fs.sector_shift;
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index 546a704..2a1efde 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -4,6 +4,7 @@
 #include <sys/dirent.h>
 #include "fs.h"
 #include "core.h"
+#include "multifs.h"
 
 /* 
  * Open a directory
@@ -13,6 +14,9 @@ __export DIR *opendir(const char *path)
     int rv;
     struct file *file;
 
+    if (switch_fs(&path))
+	return NULL;
+
     rv = searchdir(path, O_RDONLY|O_DIRECTORY);
     if (rv < 0)
 	return NULL;
@@ -24,6 +28,9 @@ __export DIR *opendir(const char *path)
 	return NULL;
     }
 
+    restore_fs();
+    restore_chdir_start();
+
     return (DIR *)file;
 }
 
@@ -35,7 +42,7 @@ __export struct dirent *readdir(DIR *dir)
     static struct dirent buf;
     struct file *dd_dir = (struct file *)dir;
     int rv = -1;
-    
+
     if (dd_dir) {
         if (dd_dir->fs->fs_ops->readdir) {
 	    rv = dd_dir->fs->fs_ops->readdir(dd_dir, &buf);
diff --git a/core/include/multifs.h b/core/include/multifs.h
new file mode 100644
index 0000000..861ca97
--- /dev/null
+++ b/core/include/multifs.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef MULTIFS_H
+#define MULTIFS_H
+
+/*
+ * MULTIFS SYNTAX:
+ * (hd[disk number],[partition number])/path/to/file
+ *
+ * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0.
+ * Disk and Partition numbering starts from 0 and 1 respectivelly.
+ */
+#include "fs.h"
+
+/*
+ * root_fs means the file system where ldlinux.sys lives in.
+ * this_fs means the file system being currently used.
+ */
+extern struct fs_info *this_fs, *root_fs;
+
+/*
+ * Set this_fs back to root_fs,
+ * otherwise unexpected behavior may occurs.
+ */
+static inline void restore_fs(void)
+{
+    this_fs = root_fs;
+}
+
+/*
+ * Basically restores the cwd of the underlying fs.
+ */
+static inline void restore_chdir_start(void)
+{
+    if (this_fs->fs_ops->chdir_start) {
+	if (this_fs->fs_ops->chdir_start() < 0)
+	    printf("Failed to chdir to start directory\n");
+    }
+}
+
+typedef	struct fs_info *(*get_fs_info_t)(const char **);
+extern int switch_fs(const char **);
+
+#endif /* MULTIFS_H */
diff --git a/core/multifs.c b/core/multifs.c
new file mode 100644
index 0000000..8951ef7
--- /dev/null
+++ b/core/multifs.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <klibc/compiler.h>
+#include <stdio.h>
+#include <assert.h>
+#include "multifs.h"
+
+static get_fs_info_t get_fs_info = NULL;
+
+/*
+ * Enable MultiFS support
+ * This function is called from ldlinux.c32 to enable MultiFS support.
+ *
+ * @addr: address of the get_fs_info function from ldlinux.c32.
+ */
+__export void enable_multifs(get_fs_info_t addr)
+{
+    if (addr) {
+	get_fs_info = addr;
+	dprintf("MultiFS: set get_fs_info to %p\n", get_fs_info);
+    }
+}
+
+/*
+ * The request is considered MultiFS if the path starts
+ * with an open parentheses.
+ *
+ * @ret: Upon success, set this_fs to the fs where the underlying file
+ * resides and returns 0. Upon failure, returns -1;
+ */
+int switch_fs(const char **path)
+{
+    struct fs_info *fs;
+
+    assert(path && *path);
+    if ((*path)[0] != '(') {
+	/* If so, don't need to restore chdir */
+	if (this_fs == root_fs)
+	    return 0;
+
+	fs = root_fs;
+	goto ret;
+    }
+
+    if (__unlikely(!get_fs_info)) {
+	printf("MultiFS support is not enabled!\n");
+	return -1;
+    }
+
+    fs = get_fs_info(path);
+    if (!fs) {
+	dprintf("MultiFS: It wasn't possible to get the proper fs!\n");
+	return -1;
+    }
+ret:
+    this_fs = fs;
+    restore_chdir_start();
+    return 0;
+}
-- 
2.1.0
From: "Raphael S. Carvalho" <raphael.scarv at gmail.com>
This patch finishes the MultiFS support.
init_multifs gets called in the main (startup) function of ldlinux.c32,
so MultiFS will be initialized automatically.
init_multifs calls enable_multifs (lives in the core) to hook get_fs_info.
Subsequent accesses will callback the get_fs_info living in ldlinux.c32.
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/elflink/ldlinux/ldlinux.c        |   2 +
 com32/include/syslinux/multifs_utils.h |  51 ++++++
 com32/lib/syslinux/multifs_utils.c     | 323 +++++++++++++++++++++++++++++++++
 mk/lib.mk                              |   1 +
 4 files changed, 377 insertions(+)
 create mode 100644 com32/include/syslinux/multifs_utils.h
 create mode 100644 com32/lib/syslinux/multifs_utils.c
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 9b01dd3..97b4be2 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -303,6 +303,8 @@ __export int main(int argc __unused, char **argv)
 	const char *cmdline;
 	size_t count = 0;
 
+	init_multifs(); /* Init MultiFS support */
+	
 	ldlinux_console_init();
 
 	parse_configs(&argv[1]);
diff --git a/com32/include/syslinux/multifs_utils.h
b/com32/include/syslinux/multifs_utils.h
new file mode 100644
index 0000000..90ef6d6
--- /dev/null
+++ b/com32/include/syslinux/multifs_utils.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
+ * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com>
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef MULTIDISK_UTILS_H
+#define MULTIDISK_UTILS_H
+
+#include <syslinux/partiter.h>
+#include "fs.h"
+
+struct part_node {
+    int partition;
+    struct fs_info *fs;
+    struct part_node *next;
+};
+
+struct queue_head {
+    struct part_node *first;
+    struct part_node *last;
+};
+
+/*
+ * Needs to keep ROOT_FS_OPS after fs_init()
+ * to be used by multidisk
+ */
+extern const struct fs_ops **p_ops;
+
+/*
+ * Used to initialize MultiFS support
+ */
+extern void enable_multifs(void *);
+extern void init_multifs(void);
+
+#endif /* MULTIDISK_UTILS_H */
diff --git a/com32/lib/syslinux/multifs_utils.c
b/com32/lib/syslinux/multifs_utils.c
new file mode 100644
index 0000000..d243ef2
--- /dev/null
+++ b/com32/lib/syslinux/multifs_utils.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
+ * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com>
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include <syslinux/multifs_utils.h>
+#include "core.h"
+#include "disk.h"
+#include "cache.h"
+#include "minmax.h"
+
+/* 0x80 - 0xFF
+ * BIOS limitation */
+#define DISK_ID_OFFSET 0x80
+#define DISKS_MAX 128
+
+/* MaxTransfer for MultiFS access */
+#define MAX_TRANSFER 127
+
+static struct queue_head *parts_info[DISKS_MAX];
+
+/*
+ * Store info about the FS into a specific queue to be used later.
+ *
+ * @ret: 0 on success, -1 on failure.
+ */
+static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition)
+{
+    struct queue_head *head = parts_info[disk];
+    struct part_node *node;
+
+    node = malloc(sizeof(struct part_node));
+    if (!node)
+        return -1;
+    node->fs = fs;
+    node->next = NULL;
+    node->partition = partition;
+
+    if (!head) {
+        head = malloc(sizeof(struct queue_head));
+        if (!head) {
+	    free(node);
+	    return -1;
+	}
+        head->first = head->last = node;
+        parts_info[disk] = head;
+        return 0;
+    }
+    head->last->next = node;
+    head->last = node;
+    return 0;
+}
+
+/*
+ * Check if the FS was previously allocated.
+ *
+ * @ret: return the fs on success, NULL on failure.
+ */
+static struct fs_info *get_fs(uint8_t disk, uint8_t partition)
+{
+    struct part_node *i;
+
+    for (i = parts_info[disk]->first; i; i = i->next) {
+        if (i->partition == partition)
+            return i->fs;
+    }
+    return NULL;
+}
+
+/*
+ * Attempt to find a partition based on drive and partition numbers.
+ *
+ * @ret: 0 on success, -1 on failure.
+ */
+static int find_partition(struct part_iter **_iter, struct disk_info *diskinfo,
+			  int partition)
+{
+    struct part_iter *iter = NULL;
+
+    if (!(iter = pi_begin(diskinfo, 0)))
+	return -1;
+
+    do {
+        if (iter->index == partition)
+            break;
+    } while (!pi_next(iter));
+
+    if (iter->status) {
+        dprintf("MultiFS: Request disk/partition combination not
found.\n");
+        goto bail;
+    }
+    dprintf("MultiFS: found 0x%llx at idex: %i and partition %i\n",
+	    iter->abs_lba, iter->index, partition);
+
+    *_iter = iter;
+    return 0;
+bail:
+    pi_del(&iter);
+    return -1;
+}
+
+/*
+ * Get a number till the delimiter is found.
+ *
+ * @ret: addr to delimiter+1 on success, NULL on failure.
+ */
+static const char *get_num(const char *p, char delimiter, uint8_t *data)
+{
+    uint32_t n = 0;
+
+    while (*p) {
+	if (*p < '0' || *p > '9')
+	    break;
+	
+	n = (n * 10) + (*p - '0');
+	p++;
+
+	if (*p == delimiter) {
+	    p++; /* Skip delimiter */
+	    *data = min(n, UINT8_MAX); /* Avoid overflow */
+	    return p;
+	}
+    }
+    return NULL;
+}
+
+/*
+ * Parse MultiFS path. Syntax:
+ * (hd[disk number],[partition number])/path/to/file
+ * 
+ * @ret: Returns syntax validity.
+ */
+static int parse_multifs_path(const char **path, uint8_t *hdd,
+			      uint8_t *partition)
+{
+    const char *p = *path;
+    static const char *cwd = ".";
+
+    *hdd = *partition = 0;
+    p++; /* Skip open parentheses */
+
+    /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */
+    if (*p != 'h' || *(p + 1) != 'd')
+	return -1; 
+
+    p += 2; /* Skip 'h' and 'd' */
+    p = get_num(p, ',', hdd);
+    if (!p)
+	return -1;
+    if (*hdd >= DISKS_MAX) {
+	printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX - 1);
+	return -1;
+    }
+
+    /* Get partition number (Range: 0 - 0xFF) */
+    p = get_num(p, ')', partition);
+    if (!p)
+	return -1;
+
+    if (*p == '\0') {
+	/* Assume it's a cwd request */
+	p = cwd;
+    }
+
+    *path = p;
+    dprintf("MultiFS: hdd: %u partition: %u path: %s\n",
+	    *hdd, *partition, *path);
+    return 0;
+}
+
+/*
+ * Set up private struct based on paramaters.
+ * This structure will be used later to set up a device
+ * to (disk x,partition y).
+ *
+ * @devno: Device number (range: 0 - (DISKS_MAX - 1)).
+ * @part_start: Start LBA.
+ * @bsHeads: Number of heads.
+ * @bsSecPerTrack: Sectors per track.
+ */
+static void *get_private(uint8_t devno, uint64_t part_start,
+			 uint16_t bsHeads, uint16_t bsSecPerTrack)
+{
+    static com32sys_t regs;
+    static struct bios_disk_private priv;
+
+    priv.regs = ®s;
+
+    regs.edx.b[0] = devno;
+    regs.edx.b[1] = 0; // TODO: cdrom ... always 0???
+    regs.ecx.l = part_start & 0xFFFFFFFF;
+    regs.ebx.l = part_start >> 32;
+    regs.esi.w[0] = bsHeads;
+    regs.edi.w[0] = bsSecPerTrack;
+    regs.ebp.l = MAX_TRANSFER; // TODO: should it be pre-defined???
+
+    return (void *) &priv;
+}
+
+/*
+ * 1) Set up a new device based on the disk and the partition.
+ * 2) Find which file system is installed in this device.
+ * 3) Set up fs_info based on the fs, add to queue, and return it.
+ * 4) Subsequent accesses to the same disk and partition will get
+ *    fs_info from the queue.
+ *
+ * It handles the important stuff to get the MultiFS support working.
+ */
+static struct fs_info *get_fs_info(const char **path)
+{
+    const struct fs_ops **ops;
+    struct fs_info *fsp;
+    struct disk_info diskinfo;
+    struct part_iter *iter = NULL;
+    struct device *dev = NULL;
+    void *private;
+    int blk_shift = -1;
+    uint8_t disk_devno, hdd, partition;
+
+    if (parse_multifs_path(path, &hdd, &partition)) {
+	printf("MultiFS: Syntax invalid: %s\n", *path);
+	return NULL;
+    }
+
+    fsp = get_fs(hdd, partition - 1);
+    if (fsp)
+        return fsp;
+
+    fsp = malloc(sizeof(struct fs_info));
+    if (!fsp)
+        return NULL;
+
+    disk_devno = DISK_ID_OFFSET + hdd;
+    if (disk_get_params(disk_devno, &diskinfo))
+        goto bail;
+
+    if (find_partition(&iter, &diskinfo, partition)) {
+        printf("MultiFS: Failed to get disk/partition: %s\n", *path);
+        goto bail;
+    }
+    private = get_private(disk_devno, iter->abs_lba, diskinfo.head,
+			  diskinfo.spt);
+
+    /* Default name for the root directory */
+    fsp->cwd_name[0] = '/';
+    fsp->cwd_name[1] = '\0';
+
+    ops = p_ops;
+    while ((blk_shift < 0) && *ops) {
+        /* set up the fs stucture */
+        fsp->fs_ops = *ops;
+
+        /*
+         * This boldly assumes that we don't mix FS_NODEV filesystems
+         * with FS_DEV filesystems...
+         */
+        if (fsp->fs_ops->fs_flags & FS_NODEV) {
+            fsp->fs_dev = NULL;
+        } else {
+	    if (!dev) {
+		dev = device_init(private);
+		if (!dev)
+		    goto bail;
+	    }
+	    fsp->fs_dev = dev;
+        }
+        /* invoke the fs-specific init code */
+        blk_shift = fsp->fs_ops->fs_init(fsp);
+        ops++;
+    }
+    if (blk_shift < 0) {
+	printf("MultiFS: No valid file system found!\n");
+        goto free_dev;
+    }
+
+    /* add fs_info into hdd queue  */
+    if (add_fs(fsp, hdd, partition - 1))
+	goto free_dev;
+
+    /* initialize the cache */
+    if (fsp->fs_dev && fsp->fs_dev->cache_data)
+        cache_init(fsp->fs_dev, blk_shift);
+
+    /* start out in the root directory */
+    if (fsp->fs_ops->iget_root) {
+        fsp->root = fsp->fs_ops->iget_root(fsp);
+        fsp->cwd = get_inode(fsp->root);
+    }
+
+    return fsp;
+free_dev:
+    free(dev->disk);
+    free(dev->cache_data);
+    free(dev);
+bail:
+    free(fsp);
+    return NULL;
+}
+
+/*
+ * Initialize MultiFS support
+ */
+void init_multifs(void)
+{
+    enable_multifs(&get_fs_info);
+    dprintf("MultiFS support was enabled successfully!\n");
+}
diff --git a/mk/lib.mk b/mk/lib.mk
index c56d3e3..d059ad5 100644
--- a/mk/lib.mk
+++ b/mk/lib.mk
@@ -107,6 +107,7 @@ LIBOTHER_OBJS = \
 	\
 	sys/x86_init_fpu.o math/pow.o math/strtod.o			\
 	syslinux/disk.o	syslinux/utility.o syslinux/partiter.o		\
+	syslinux/multifs_utils.o					\
 	\
 	syslinux/setup_data.o
 
-- 
2.1.0
Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 4/8] ldlinux/kernel: contemplate multifs path syntax
The initramfs path in the configuration file might come with multifs
path syntax (e.g. (hdX,Y)/initramfs...), so we must include it so
multifs will know how fs ops to switch to.
Cc: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 com32/elflink/ldlinux/kernel.c | 9 +++++++++
 1 file changed, 9 insertions(+)
diff --git a/com32/elflink/ldlinux/kernel.c b/com32/elflink/ldlinux/kernel.c
index f3ba37f..f9738a7 100644
--- a/com32/elflink/ldlinux/kernel.c
+++ b/com32/elflink/ldlinux/kernel.c
@@ -88,6 +88,15 @@ int new_linux_kernel(char *okernel, char *ocmdline)
 		    temp++;	/* Skip = or , */
 
 		    p = temp;
+		    if (*p == '(') {
+			/* handle MultiFS path syntax: e.g. (hdX,Y)... */
+			do {
+			    p++;
+			    n++;
+			} while (*p && *p != ')');
+			p++;
+			n++;
+		    }
 		    while (*p != ' ' && *p != ',' && *p) {
 			p++;
 			n++;
-- 
2.1.0
The system firmware will expose device handles of all MBR/GPT partitions
which support BlockIo and/or DiskIo protocols, so find them and pass
through MultiFS driver.
Even in EFI environment ldlinux will be loaded up, so to avoid
initialise multifs twice call init_multifs() earlier.
Cc: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 com32/elflink/ldlinux/execute.c |   3 +
 com32/elflink/ldlinux/ldlinux.c |   2 -
 core/fs/fs.c                    |   1 -
 core/fs/readdir.c               |   1 -
 core/multifs.c                  |   1 -
 efi/diskio.c                    |  32 +++--
 efi/main.c                      |  22 ++-
 efi/multifs_utils.c             | 296 ++++++++++++++++++++++++++++++++++++++++
 efi/multifs_utils.h             |  52 +++++++
 9 files changed, 387 insertions(+), 23 deletions(-)
 create mode 100644 efi/multifs_utils.c
 create mode 100644 efi/multifs_utils.h
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 653c880..da89305 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -30,6 +30,7 @@
 #include <syslinux/movebits.h>
 #include <syslinux/config.h>
 #include <syslinux/boot.h>
+#include <syslinux/multifs_utils.h>
 
 const struct image_types image_boot_types[] = {
     { "localboot", IMAGE_TYPE_LOCALBOOT },
@@ -147,6 +148,8 @@ __export void execute(const char *cmdline, uint32_t type,
bool sysappend)
 		if (!config)
 			goto out;
 
+		init_multifs();
+
 		realpath(config, kernel, FILENAME_MAX);
 
 		/* If we got anything on the command line, do a chdir */
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 97b4be2..9b01dd3 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -303,8 +303,6 @@ __export int main(int argc __unused, char **argv)
 	const char *cmdline;
 	size_t count = 0;
 
-	init_multifs(); /* Init MultiFS support */
-	
 	ldlinux_console_init();
 
 	parse_configs(&argv[1]);
diff --git a/core/fs/fs.c b/core/fs/fs.c
index a5d8db4..1bea6b5 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -371,7 +371,6 @@ __export int open_file(const char *name, int flags, struct
com32_filedata *filed
     filedata->handle	= rv;
 
     restore_fs();
-    restore_chdir_start();
 
     return rv;
 }
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index 2a1efde..07fae5d 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -29,7 +29,6 @@ __export DIR *opendir(const char *path)
     }
 
     restore_fs();
-    restore_chdir_start();
 
     return (DIR *)file;
 }
diff --git a/core/multifs.c b/core/multifs.c
index 8951ef7..aafce57 100644
--- a/core/multifs.c
+++ b/core/multifs.c
@@ -71,6 +71,5 @@ int switch_fs(const char **path)
     }
 ret:
     this_fs = fs;
-    restore_chdir_start();
     return 0;
 }
diff --git a/efi/diskio.c b/efi/diskio.c
index d6a160e..64014fe 100644
--- a/efi/diskio.c
+++ b/efi/diskio.c
@@ -43,7 +43,7 @@ static int efi_rdwr_sectors(struct disk *disk, void *buf,
 
 struct disk *efi_disk_init(void *private)
 {
-    static struct disk disk;
+    struct disk *disk;
     struct efi_disk_private *priv = (struct efi_disk_private *)private;
     EFI_HANDLE handle = priv->dev_handle;
     EFI_BLOCK_IO *bio;
@@ -60,33 +60,37 @@ struct disk *efi_disk_init(void *private)
     if (status != EFI_SUCCESS)
 	    return NULL;
 
+    disk = malloc(sizeof(*disk));
+    if (!disk)
+        return NULL;
+
     /*
      * XXX Do we need to map this to a BIOS disk number?
      */
-    disk.disk_number   = bio->Media->MediaId;
+    disk->disk_number   = bio->Media->MediaId;
 
-    disk.sector_size   = bio->Media->BlockSize;
-    disk.rdwr_sectors  = efi_rdwr_sectors;
-    disk.sector_shift  = ilog2(disk.sector_size);
+    disk->sector_size   = bio->Media->BlockSize;
+    disk->rdwr_sectors  = efi_rdwr_sectors;
+    disk->sector_shift  = ilog2(disk->sector_size);
 
-    dprintf("sector_size=%d, disk_number=%d\n", disk.sector_size,
-	    disk.disk_number);
+    dprintf("sector_size=%d, disk_number=%d\n", disk->sector_size,
+	    disk->disk_number);
 
     priv->bio = bio;
     priv->dio = dio;
-    disk.private = private;
+    disk->private = private;
 #if 0
 
-    disk.part_start    = part_start;
-    disk.secpercyl     = disk.h * disk.s;
+    disk->part_start    = part_start;
+    disk->secpercyl     = disk->h * disk->s;
 
 
-    disk.maxtransfer   = MaxTransfer;
+    disk->maxtransfer   = MaxTransfer;
 
     dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit
%u\n",
-	    media_id, cdrom, ebios, sector_size, disk.sector_shift,
-	    part_start, disk.maxtransfer);
+	    media_id, cdrom, ebios, sector_size, disk->sector_shift,
+	    part_start, disk->maxtransfer);
 #endif
 
-    return &disk;
+    return disk;
 }
diff --git a/efi/main.c b/efi/main.c
index 9c3c2f2..a165b05 100644
--- a/efi/main.c
+++ b/efi/main.c
@@ -15,6 +15,7 @@
 #include "efi.h"
 #include "fio.h"
 #include "version.h"
+#include "multifs_utils.h"
 
 __export uint16_t PXERetry;
 __export char copyright_str[] = "Copyright (C) 2011-" YEAR_STR
"\n";
@@ -1199,6 +1200,11 @@ static inline void syslinux_register_efi(void)
 
 extern void init(void);
 extern const struct fs_ops vfat_fs_ops;
+extern const struct fs_ops ext2_fs_ops;
+extern const struct fs_ops ntfs_fs_ops;
+extern const struct fs_ops xfs_fs_ops;
+extern const struct fs_ops btrfs_fs_ops;
+extern const struct fs_ops ufs_fs_ops;
 extern const struct fs_ops pxe_fs_ops;
 
 char free_high_memory[4096];
@@ -1206,6 +1212,11 @@ char free_high_memory[4096];
 extern char __bss_start[];
 extern char __bss_end[];
 
+static const struct fs_ops *fs_ops[] = {
+	&vfat_fs_ops, &ext2_fs_ops, &ntfs_fs_ops, &xfs_fs_ops,
&btrfs_fs_ops,
+	&ufs_fs_ops, &pxe_fs_ops, NULL,
+};
+
 static void efi_setcwd(CHAR16 *dp)
 {
 	CHAR16 *c16;
@@ -1242,7 +1253,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE
*table)
 	EFI_PXE_BASE_CODE *pxe;
 	EFI_LOADED_IMAGE *info;
 	EFI_STATUS status = EFI_SUCCESS;
-	const struct fs_ops *ops[] = { NULL, NULL };
 	unsigned long len = (unsigned long)__bss_end - (unsigned long)__bss_start;
 	static struct efi_disk_private priv;
 	SIMPLE_INPUT_INTERFACE *in;
@@ -1279,10 +1289,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE
*table)
 		}
 
 		efi_derivative(SYSLINUX_FS_SYSLINUX);
-		ops[0] = &vfat_fs_ops;
+		status = init_multifs();
+		if (EFI_ERROR(status)) {
+			Print(L"Failed to initialise multifs support: %r\n",
+			      status);
+			goto out;
+		}
 	} else {
 		efi_derivative(SYSLINUX_FS_PXELINUX);
-		ops[0] = &pxe_fs_ops;
 		image_device_handle = info->DeviceHandle;
 	}
 
@@ -1303,7 +1317,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE
*table)
 	 */
 	efi_setcwd(DevicePathToStr(info->FilePath));
 
-	fs_init(ops, (void *)&priv);
+	fs_init(fs_ops, (void *)&priv);
 
 	/*
 	 * There may be pending user input that wasn't processed by
diff --git a/efi/multifs_utils.c b/efi/multifs_utils.c
new file mode 100644
index 0000000..a4e3ff9
--- /dev/null
+++ b/efi/multifs_utils.c
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2015 Paulo Alcantara <pcacjr at zytor.com>
+ * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <fs.h>
+#include <ilog2.h>
+#include <disk.h>
+
+#include "cache.h"
+#include "minmax.h"
+#include "multifs_utils.h"
+#include "efi.h"
+
+#define DISKS_MAX 0xff
+
+static EFI_HANDLE *_logical_parts = NULL;
+static unsigned int _logical_parts_no = 0;
+static struct queue_head *parts_info[DISKS_MAX];
+
+/* Find all BlockIo device handles which is a logical partition */
+static EFI_STATUS find_all_logical_parts(void)
+{
+    EFI_STATUS status;
+    unsigned long len = 0;
+    EFI_HANDLE *handles = NULL;
+    unsigned long i;
+    EFI_BLOCK_IO *bio;
+
+    if (_logical_parts) {
+        status = EFI_SUCCESS;
+        goto out;
+    }
+
+    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
+                               &BlockIoProtocol, NULL, &len, NULL);
+    if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL)
+        goto out;
+
+    handles = malloc(len);
+    if (!handles) {
+        status = EFI_OUT_OF_RESOURCES;
+        goto out;
+    }
+
+    _logical_parts = malloc(len);
+    if (!_logical_parts) {
+        status = EFI_OUT_OF_RESOURCES;
+        goto out_free;
+    }
+
+    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
+                               &BlockIoProtocol, NULL, &len,
+                               (void **)handles);
+    if (EFI_ERROR(status))
+        goto out_free;
+
+    for (i = 0; i < len / sizeof(EFI_HANDLE); i++) {
+        status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+                                   &BlockIoProtocol, (void **)&bio);
+        if (EFI_ERROR(status))
+            goto out_free;
+        if (bio->Media->LogicalPartition) {
+            _logical_parts[_logical_parts_no++] = handles[i];
+        }
+    }
+
+    free(handles);
+    return status;
+
+out_free:
+    if (handles)
+        free(handles);
+    if (_logical_parts)
+        free(_logical_parts);
+out:
+    return status;
+}
+
+static inline EFI_HANDLE get_logical_part(unsigned int partno)
+{
+    if (!_logical_parts || partno > _logical_parts_no)
+        return NULL;
+    return _logical_parts[partno - 1];
+}
+
+static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition)
+{
+    struct queue_head *head = parts_info[disk];
+    struct part_node *node;
+
+    node = malloc(sizeof(struct part_node));
+    if (!node)
+        return -1;
+    node->fs = fs;
+    node->next = NULL;
+    node->partition = partition;
+
+    if (!head) {
+        head = malloc(sizeof(struct queue_head));
+        if (!head) {
+            free(node);
+            return -1;
+        }
+        head->first = head->last = node;
+        parts_info[disk] = head;
+        return 0;
+    }
+    head->last->next = node;
+    head->last = node;
+    return 0;
+}
+
+static struct fs_info *get_fs(uint8_t disk, uint8_t partition)
+{
+    struct part_node *i;
+
+    for (i = parts_info[disk]->first; i; i = i->next) {
+        if (i->partition == partition)
+            return i->fs;
+    }
+    return NULL;
+}
+
+static EFI_HANDLE find_partition(unsigned int diskno, unsigned int partno)
+{
+    return get_logical_part(partno);
+}
+
+static const char *get_num(const char *p, char delimiter, unsigned int *data)
+{
+    uint32_t n = 0;
+
+    while (*p) {
+        if (*p < '0' || *p > '9')
+            break;
+        n = (n * 10) + (*p - '0');
+        p++;
+        if (*p == delimiter) {
+            p++; /* skip delimiter */
+            *data = min(n, UINT8_MAX); /* avoid overflow */
+            return p;
+        }
+    }
+    return NULL;
+}
+
+static int parse_multifs_path(const char **path, unsigned int *hdd,
+                              unsigned int *partition)
+{
+    const char *p = *path;
+    static const char *cwd = ".";
+
+    *hdd = *partition = 0;
+    p++; /* Skip open parentheses */
+
+    /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */
+    if (*p != 'h' || *(p + 1) != 'd')
+        return -1;
+
+    p += 2; /* Skip 'h' and 'd' */
+    p = get_num(p, ',', hdd);
+    if (!p)
+        return -1;
+    if (*hdd >= DISKS_MAX) {
+        printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX -
1);
+        return -1;
+    }
+
+    /* Get partition number (Range: 0 - 0xFF) */
+    p = get_num(p, ')', partition);
+    if (!p)
+        return -1;
+
+    if (*p == '\0') {
+        /* Assume it's a cwd request */
+        p = cwd;
+    }
+
+    *path = p;
+    dprintf("MultiFS: hdd: %u partition: %u path: %s\n",
+            *hdd, *partition, *path);
+    return 0;
+}
+
+static inline void *get_private(EFI_HANDLE lpart)
+{
+    static struct efi_disk_private priv;
+    priv.dev_handle = lpart;
+    return (void *)&priv;
+}
+
+static struct fs_info *get_fs_info(const char **path)
+{
+    const struct fs_ops **ops;
+    struct fs_info *fsp;
+    EFI_HANDLE dh;
+    struct device *dev = NULL;
+    void *private;
+    int blk_shift = -1;
+    unsigned int hdd, partition;
+
+    if (parse_multifs_path(path, &hdd, &partition)) {
+        return NULL;
+    }
+
+    fsp = get_fs(hdd, partition - 1);
+    if (fsp)
+        return fsp;
+
+    fsp = malloc(sizeof(struct fs_info));
+    if (!fsp)
+        return NULL;
+
+    dh = find_partition(hdd, partition);
+    if (!dh)
+        goto bail;
+    dprintf("\nMultiFS: found partition %d\n", partition);
+    private = get_private(dh);
+
+    /* set default name for the root directory */
+    fsp->cwd_name[0] = '/';
+    fsp->cwd_name[1] = '\0';
+
+    ops = p_ops;
+    while ((blk_shift < 0) && *ops) {
+        /* set up the fs stucture */
+        fsp->fs_ops = *ops;
+
+        /*
+         * This boldly assumes that we don't mix FS_NODEV filesystems
+         * with FS_DEV filesystems...
+         */
+        if (fsp->fs_ops->fs_flags & FS_NODEV) {
+            fsp->fs_dev = NULL;
+        } else {
+            if (!dev) {
+                dev = device_init(private);
+                if (!dev)
+                    goto bail;
+            }
+            fsp->fs_dev = dev;
+        }
+        /* invoke the fs-specific init code */
+        blk_shift = fsp->fs_ops->fs_init(fsp);
+        ops++;
+    }
+    if (blk_shift < 0) {
+        dprintf("MultiFS: No valid file system found!\n");
+        goto free_dev;
+    }
+
+    if (add_fs(fsp, hdd, partition - 1))
+        goto free_dev;
+    if (fsp->fs_dev && fsp->fs_dev->cache_data &&
!fsp->fs_dev->cache_init)
+        cache_init(fsp->fs_dev, blk_shift);
+    if (fsp->fs_ops->iget_root) {
+        fsp->root = fsp->fs_ops->iget_root(fsp);
+        fsp->cwd = get_inode(fsp->root);
+    }
+    return fsp;
+
+free_dev:
+    free(dev->disk);
+    free(dev->cache_data);
+    free(dev);
+bail:
+    free(fsp);
+    return NULL;
+}
+
+EFI_STATUS init_multifs(void)
+{
+    EFI_STATUS status;
+
+    status = find_all_logical_parts();
+    enable_multifs(get_fs_info);
+    dprintf("MultiFS: initialised\n");
+
+    return status;
+}
diff --git a/efi/multifs_utils.h b/efi/multifs_utils.h
new file mode 100644
index 0000000..7ae5b43
--- /dev/null
+++ b/efi/multifs_utils.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com>
+ * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef MULTIDISK_UTILS_H
+#define MULTIDISK_UTILS_H
+
+#include <fs.h>
+
+#include "efi.h"
+
+struct part_node {
+    int partition;
+    struct fs_info *fs;
+    struct part_node *next;
+};
+
+struct queue_head {
+    struct part_node *first;
+    struct part_node *last;
+};
+
+/*
+ * Needs to keep ROOT_FS_OPS after fs_init()
+ * to be used by multidisk
+ */
+extern const struct fs_ops **p_ops;
+
+/*
+ * Used to initialize MultiFS support
+ */
+extern void enable_multifs(void *);
+extern EFI_STATUS init_multifs(void);
+
+#endif /* MULTIDISK_UTILS_H */
-- 
2.1.0
Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 6/8] sys/common: handle multifs paths in findpath()
By looking for PATH entries and trying to find multifs-like paths does
not make any sense. Only try to open it once.
Cc: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 com32/lib/sys/module/common.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 05a27e8..73155ad 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -59,12 +59,17 @@ void print_elf_symbols(struct elf_module *module) {
 
 FILE *findpath(char *name)
 {
+	int is_multifs_path = 0;
+	char *p;
 	struct path_entry *entry;
 	char path[FILENAME_MAX];
 	FILE *f;
 
+	/* NOTE: multifs already handle both relative and absolute paths */
+	if ((p = strchr(name, ')')) && strchr(p, ')'))
+		is_multifs_path = 1; /* assume multifs-like path */
 	f = fopen(name, "rb"); /* for full path */
-	if (f)
+	if (f || is_multifs_path)
 		return f;
 
 	list_for_each_entry(entry, &PATH, list) {
-- 
2.1.0
Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 7/8] multifs: add support for both UEFI and BIOS firmware
The previous MultiFS implementation only supported BIOS, so this patch
basically keeps common code in a single place and separate
firmware-specific functions that'll be exposed later.
A generic interface has been added to be able to switch among different
FSes regardless which firmware is being used. Although, each
implementation has to implement init() and get_is_info() functions, pass
through multifs_ops structure and they'll get called in starting of
ldlinux.
Cc: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 com32/elflink/ldlinux/execute.c        |   3 -
 com32/elflink/ldlinux/ldlinux.c        |   9 +
 com32/include/syslinux/multifs_utils.h |  25 +--
 com32/lib/syslinux/multifs_utils.c     | 318 +++++----------------------------
 core/bios.c                            |  11 ++
 core/fs/fs.c                           |   4 +-
 core/fs/readdir.c                      |   4 +-
 core/include/multifs.h                 |  43 ++---
 core/multifs.c                         | 214 ++++++++++++++++++----
 core/multifs_bios.c                    |  75 ++++++++
 efi/main.c                             |  18 +-
 efi/multifs.c                          | 162 +++++++++++++++++
 efi/multifs_utils.c                    | 296 ------------------------------
 13 files changed, 514 insertions(+), 668 deletions(-)
 create mode 100644 core/multifs_bios.c
 create mode 100644 efi/multifs.c
 delete mode 100644 efi/multifs_utils.c
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index da89305..653c880 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -30,7 +30,6 @@
 #include <syslinux/movebits.h>
 #include <syslinux/config.h>
 #include <syslinux/boot.h>
-#include <syslinux/multifs_utils.h>
 
 const struct image_types image_boot_types[] = {
     { "localboot", IMAGE_TYPE_LOCALBOOT },
@@ -148,8 +147,6 @@ __export void execute(const char *cmdline, uint32_t type,
bool sysappend)
 		if (!config)
 			goto out;
 
-		init_multifs();
-
 		realpath(config, kernel, FILENAME_MAX);
 
 		/* If we got anything on the command line, do a chdir */
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 9b01dd3..78da0e8 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -5,6 +5,7 @@
 #include <string.h>
 #include <core.h>
 #include <fs.h>
+#include <multifs.h>
 #include "cli.h"
 #include "console.h"
 #include "com32.h"
@@ -13,6 +14,7 @@
 #include "syslinux/adv.h"
 #include "syslinux/boot.h"
 #include "syslinux/config.h"
+#include "syslinux/multifs_utils.h"
 
 #include <sys/module.h>
 
@@ -292,6 +294,11 @@ static void __destructor close_console(void)
 		close(i);
 }
 
+void do_init_multifs(void)
+{
+	multifs_ops->init(bios_find_partition);
+}
+
 void ldlinux_console_init(void)
 {
 	openconsole(&dev_stdcon_r, &dev_ansiserial_w);
@@ -303,6 +310,8 @@ __export int main(int argc __unused, char **argv)
 	const char *cmdline;
 	size_t count = 0;
 
+	do_init_multifs();
+
 	ldlinux_console_init();
 
 	parse_configs(&argv[1]);
diff --git a/com32/include/syslinux/multifs_utils.h
b/com32/include/syslinux/multifs_utils.h
index 90ef6d6..4bf29a6 100644
--- a/com32/include/syslinux/multifs_utils.h
+++ b/com32/include/syslinux/multifs_utils.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
- * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com>
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com>
  * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -25,27 +25,8 @@
 #include <syslinux/partiter.h>
 #include "fs.h"
 
-struct part_node {
-    int partition;
-    struct fs_info *fs;
-    struct part_node *next;
-};
+typedef void *(*bios_find_partition_t)(uint8_t, uint8_t);
 
-struct queue_head {
-    struct part_node *first;
-    struct part_node *last;
-};
-
-/*
- * Needs to keep ROOT_FS_OPS after fs_init()
- * to be used by multidisk
- */
-extern const struct fs_ops **p_ops;
-
-/*
- * Used to initialize MultiFS support
- */
-extern void enable_multifs(void *);
-extern void init_multifs(void);
+void *bios_find_partition(uint8_t diskno, uint8_t partno);
 
 #endif /* MULTIDISK_UTILS_H */
diff --git a/com32/lib/syslinux/multifs_utils.c
b/com32/lib/syslinux/multifs_utils.c
index d243ef2..1f15030 100644
--- a/com32/lib/syslinux/multifs_utils.c
+++ b/com32/lib/syslinux/multifs_utils.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
- * Copyright (C) 2012 Paulo Cavalcanti <pcacjr at zytor.com>
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com>
  * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -18,306 +18,74 @@
  * Free Software Foundation, Inc.,
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
-
-#include <syslinux/multifs_utils.h>
 #include "core.h"
+#include "fs.h"
 #include "disk.h"
 #include "cache.h"
-#include "minmax.h"
+
+#include <syslinux/multifs_utils.h>
 
 /* 0x80 - 0xFF
  * BIOS limitation */
 #define DISK_ID_OFFSET 0x80
-#define DISKS_MAX 128
 
 /* MaxTransfer for MultiFS access */
 #define MAX_TRANSFER 127
 
-static struct queue_head *parts_info[DISKS_MAX];
-
-/*
- * Store info about the FS into a specific queue to be used later.
- *
- * @ret: 0 on success, -1 on failure.
- */
-static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition)
-{
-    struct queue_head *head = parts_info[disk];
-    struct part_node *node;
-
-    node = malloc(sizeof(struct part_node));
-    if (!node)
-        return -1;
-    node->fs = fs;
-    node->next = NULL;
-    node->partition = partition;
-
-    if (!head) {
-        head = malloc(sizeof(struct queue_head));
-        if (!head) {
-	    free(node);
-	    return -1;
-	}
-        head->first = head->last = node;
-        parts_info[disk] = head;
-        return 0;
-    }
-    head->last->next = node;
-    head->last = node;
-    return 0;
-}
-
-/*
- * Check if the FS was previously allocated.
- *
- * @ret: return the fs on success, NULL on failure.
- */
-static struct fs_info *get_fs(uint8_t disk, uint8_t partition)
+static void *get_private(uint8_t devno, uint64_t part_start,
+                         uint16_t bsHeads, uint16_t bsSecPerTrack)
 {
-    struct part_node *i;
+    com32sys_t *regs;
+    struct bios_disk_private *priv;
 
-    for (i = parts_info[disk]->first; i; i = i->next) {
-        if (i->partition == partition)
-            return i->fs;
+    regs = malloc(sizeof(*regs));
+    if (!regs)
+        return NULL;
+    memset(regs, 0, sizeof(*regs));
+
+    regs->edx.b[0] = devno;
+    regs->edx.b[1] = 0; /* XXX: cdrom ->->-> always 0? */
+    regs->ecx.l = part_start & 0xFFFFFFFF;
+    regs->ebx.l = part_start >> 32;
+    regs->esi.w[0] = bsHeads;
+    regs->edi.w[0] = bsSecPerTrack;
+    regs->ebp.l = MAX_TRANSFER; /* XXX: should it be pre-defined? */
+
+    priv = malloc(sizeof(*priv));
+    if (!priv) {
+        free(regs);
+        priv = NULL;
+    } else {
+        priv->regs = regs;
     }
-    return NULL;
+    return priv;
 }
 
-/*
- * Attempt to find a partition based on drive and partition numbers.
- *
- * @ret: 0 on success, -1 on failure.
- */
-static int find_partition(struct part_iter **_iter, struct disk_info *diskinfo,
-			  int partition)
+void *bios_find_partition(uint8_t diskno, uint8_t partno)
 {
+    uint8_t disk_devno;
     struct part_iter *iter = NULL;
+    struct disk_info diskinfo;
+
+    dprintf("%s: diskno %d partition %d\n", __func__, diskno,
partno);
 
-    if (!(iter = pi_begin(diskinfo, 0)))
-	return -1;
+    disk_devno = DISK_ID_OFFSET + diskno;
+    if (disk_get_params(disk_devno, &diskinfo))
+        return NULL;
+    if (!(iter = pi_begin(&diskinfo, 0)))
+        return NULL;
 
     do {
-        if (iter->index == partition)
+        if (iter->index == partno)
             break;
     } while (!pi_next(iter));
 
     if (iter->status) {
         dprintf("MultiFS: Request disk/partition combination not
found.\n");
-        goto bail;
-    }
-    dprintf("MultiFS: found 0x%llx at idex: %i and partition %i\n",
-	    iter->abs_lba, iter->index, partition);
-
-    *_iter = iter;
-    return 0;
-bail:
-    pi_del(&iter);
-    return -1;
-}
-
-/*
- * Get a number till the delimiter is found.
- *
- * @ret: addr to delimiter+1 on success, NULL on failure.
- */
-static const char *get_num(const char *p, char delimiter, uint8_t *data)
-{
-    uint32_t n = 0;
-
-    while (*p) {
-	if (*p < '0' || *p > '9')
-	    break;
-	
-	n = (n * 10) + (*p - '0');
-	p++;
-
-	if (*p == delimiter) {
-	    p++; /* Skip delimiter */
-	    *data = min(n, UINT8_MAX); /* Avoid overflow */
-	    return p;
-	}
-    }
-    return NULL;
-}
-
-/*
- * Parse MultiFS path. Syntax:
- * (hd[disk number],[partition number])/path/to/file
- * 
- * @ret: Returns syntax validity.
- */
-static int parse_multifs_path(const char **path, uint8_t *hdd,
-			      uint8_t *partition)
-{
-    const char *p = *path;
-    static const char *cwd = ".";
-
-    *hdd = *partition = 0;
-    p++; /* Skip open parentheses */
-
-    /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */
-    if (*p != 'h' || *(p + 1) != 'd')
-	return -1; 
-
-    p += 2; /* Skip 'h' and 'd' */
-    p = get_num(p, ',', hdd);
-    if (!p)
-	return -1;
-    if (*hdd >= DISKS_MAX) {
-	printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX - 1);
-	return -1;
-    }
-
-    /* Get partition number (Range: 0 - 0xFF) */
-    p = get_num(p, ')', partition);
-    if (!p)
-	return -1;
-
-    if (*p == '\0') {
-	/* Assume it's a cwd request */
-	p = cwd;
-    }
-
-    *path = p;
-    dprintf("MultiFS: hdd: %u partition: %u path: %s\n",
-	    *hdd, *partition, *path);
-    return 0;
-}
-
-/*
- * Set up private struct based on paramaters.
- * This structure will be used later to set up a device
- * to (disk x,partition y).
- *
- * @devno: Device number (range: 0 - (DISKS_MAX - 1)).
- * @part_start: Start LBA.
- * @bsHeads: Number of heads.
- * @bsSecPerTrack: Sectors per track.
- */
-static void *get_private(uint8_t devno, uint64_t part_start,
-			 uint16_t bsHeads, uint16_t bsSecPerTrack)
-{
-    static com32sys_t regs;
-    static struct bios_disk_private priv;
-
-    priv.regs = ®s;
-
-    regs.edx.b[0] = devno;
-    regs.edx.b[1] = 0; // TODO: cdrom ... always 0???
-    regs.ecx.l = part_start & 0xFFFFFFFF;
-    regs.ebx.l = part_start >> 32;
-    regs.esi.w[0] = bsHeads;
-    regs.edi.w[0] = bsSecPerTrack;
-    regs.ebp.l = MAX_TRANSFER; // TODO: should it be pre-defined???
-
-    return (void *) &priv;
-}
-
-/*
- * 1) Set up a new device based on the disk and the partition.
- * 2) Find which file system is installed in this device.
- * 3) Set up fs_info based on the fs, add to queue, and return it.
- * 4) Subsequent accesses to the same disk and partition will get
- *    fs_info from the queue.
- *
- * It handles the important stuff to get the MultiFS support working.
- */
-static struct fs_info *get_fs_info(const char **path)
-{
-    const struct fs_ops **ops;
-    struct fs_info *fsp;
-    struct disk_info diskinfo;
-    struct part_iter *iter = NULL;
-    struct device *dev = NULL;
-    void *private;
-    int blk_shift = -1;
-    uint8_t disk_devno, hdd, partition;
-
-    if (parse_multifs_path(path, &hdd, &partition)) {
-	printf("MultiFS: Syntax invalid: %s\n", *path);
-	return NULL;
-    }
-
-    fsp = get_fs(hdd, partition - 1);
-    if (fsp)
-        return fsp;
-
-    fsp = malloc(sizeof(struct fs_info));
-    if (!fsp)
+        pi_del(&iter);
         return NULL;
-
-    disk_devno = DISK_ID_OFFSET + hdd;
-    if (disk_get_params(disk_devno, &diskinfo))
-        goto bail;
-
-    if (find_partition(&iter, &diskinfo, partition)) {
-        printf("MultiFS: Failed to get disk/partition: %s\n", *path);
-        goto bail;
-    }
-    private = get_private(disk_devno, iter->abs_lba, diskinfo.head,
-			  diskinfo.spt);
-
-    /* Default name for the root directory */
-    fsp->cwd_name[0] = '/';
-    fsp->cwd_name[1] = '\0';
-
-    ops = p_ops;
-    while ((blk_shift < 0) && *ops) {
-        /* set up the fs stucture */
-        fsp->fs_ops = *ops;
-
-        /*
-         * This boldly assumes that we don't mix FS_NODEV filesystems
-         * with FS_DEV filesystems...
-         */
-        if (fsp->fs_ops->fs_flags & FS_NODEV) {
-            fsp->fs_dev = NULL;
-        } else {
-	    if (!dev) {
-		dev = device_init(private);
-		if (!dev)
-		    goto bail;
-	    }
-	    fsp->fs_dev = dev;
-        }
-        /* invoke the fs-specific init code */
-        blk_shift = fsp->fs_ops->fs_init(fsp);
-        ops++;
     }
-    if (blk_shift < 0) {
-	printf("MultiFS: No valid file system found!\n");
-        goto free_dev;
-    }
-
-    /* add fs_info into hdd queue  */
-    if (add_fs(fsp, hdd, partition - 1))
-	goto free_dev;
-
-    /* initialize the cache */
-    if (fsp->fs_dev && fsp->fs_dev->cache_data)
-        cache_init(fsp->fs_dev, blk_shift);
-
-    /* start out in the root directory */
-    if (fsp->fs_ops->iget_root) {
-        fsp->root = fsp->fs_ops->iget_root(fsp);
-        fsp->cwd = get_inode(fsp->root);
-    }
-
-    return fsp;
-free_dev:
-    free(dev->disk);
-    free(dev->cache_data);
-    free(dev);
-bail:
-    free(fsp);
-    return NULL;
-}
-
-/*
- * Initialize MultiFS support
- */
-void init_multifs(void)
-{
-    enable_multifs(&get_fs_info);
-    dprintf("MultiFS support was enabled successfully!\n");
+    dprintf("MultiFS: found 0x%llx at index: %i and partition %i\n",
+            iter->abs_lba, iter->index, partno);
+    return get_private(disk_devno, iter->abs_lba, diskinfo.head,
diskinfo.spt);
 }
diff --git a/core/bios.c b/core/bios.c
index 7fb37fe..0ce31df 100644
--- a/core/bios.c
+++ b/core/bios.c
@@ -1,6 +1,7 @@
 #include <sys/ansi.h>
 #include <sys/io.h>
 #include <fs.h>
+#include <multifs.h>
 #include <bios.h>
 #include <com32.h>
 #include <graphics.h>
@@ -15,6 +16,7 @@
 #include "core.h"
 
 __export struct firmware *firmware = NULL;
+__export const struct multifs_ops *multifs_ops = NULL;
 
 extern struct ansi_ops bios_ansi_ops;
 
@@ -713,7 +715,16 @@ struct firmware bios_fw = {
 	.mem = &bios_mem_ops,
 };
 
+struct fs_info *bios_multifs_get_fs_info(const char **path);
+extern void bios_multifs_init(void);
+
+const struct multifs_ops bios_multifs_ops = {
+	.get_fs_info = bios_multifs_get_fs_info,
+	.init = bios_multifs_init,
+};
+
 void syslinux_register_bios(void)
 {
 	firmware = &bios_fw;
+	multifs_ops = &bios_multifs_ops;
 }
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 1bea6b5..4feb798 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -350,7 +350,7 @@ __export int open_file(const char *name, int flags, struct
com32_filedata *filed
 
     dprintf("open_file %s\n", name);
 
-    if (switch_fs(&name))
+    if (multifs_switch_fs(&name))
 	return -1;
 
     mangle_name(mangled_name, name);
@@ -370,7 +370,7 @@ __export int open_file(const char *name, int flags, struct
com32_filedata *filed
     filedata->blocklg2	= SECTOR_SHIFT(file->fs);
     filedata->handle	= rv;
 
-    restore_fs();
+    multifs_restore_fs();
 
     return rv;
 }
diff --git a/core/fs/readdir.c b/core/fs/readdir.c
index 07fae5d..8acdd55 100644
--- a/core/fs/readdir.c
+++ b/core/fs/readdir.c
@@ -14,7 +14,7 @@ __export DIR *opendir(const char *path)
     int rv;
     struct file *file;
 
-    if (switch_fs(&path))
+    if (multifs_switch_fs(&path))
 	return NULL;
 
     rv = searchdir(path, O_RDONLY|O_DIRECTORY);
@@ -28,7 +28,7 @@ __export DIR *opendir(const char *path)
 	return NULL;
     }
 
-    restore_fs();
+    multifs_restore_fs();
 
     return (DIR *)file;
 }
diff --git a/core/include/multifs.h b/core/include/multifs.h
index 861ca97..0d6bff1 100644
--- a/core/include/multifs.h
+++ b/core/include/multifs.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ * Copyright (C) 2015 Paulo Alcantara <pcacjr at zytor.com>
  *
  * 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
@@ -20,6 +21,8 @@
 #ifndef MULTIFS_H
 #define MULTIFS_H
 
+#include "fs.h"
+
 /*
  * MULTIFS SYNTAX:
  * (hd[disk number],[partition number])/path/to/file
@@ -27,35 +30,21 @@
  * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0.
  * Disk and Partition numbering starts from 0 and 1 respectivelly.
  */
-#include "fs.h"
-
-/*
- * root_fs means the file system where ldlinux.sys lives in.
- * this_fs means the file system being currently used.
- */
-extern struct fs_info *this_fs, *root_fs;
 
-/*
- * Set this_fs back to root_fs,
- * otherwise unexpected behavior may occurs.
- */
-static inline void restore_fs(void)
-{
-    this_fs = root_fs;
-}
+struct multifs_ops {
+    struct fs_info *(*get_fs_info)(const char **);
+    void (*init)(void *);
+};
 
-/*
- * Basically restores the cwd of the underlying fs.
- */
-static inline void restore_chdir_start(void)
-{
-    if (this_fs->fs_ops->chdir_start) {
-	if (this_fs->fs_ops->chdir_start() < 0)
-	    printf("Failed to chdir to start directory\n");
-    }
-}
+extern struct fs_info *root_fs;
+extern const struct fs_ops **p_ops;
+extern const struct multifs_ops *multifs_ops;
 
-typedef	struct fs_info *(*get_fs_info_t)(const char **);
-extern int switch_fs(const char **);
+struct fs_info *multifs_get_fs(uint8_t diskno, uint8_t partno);
+int multifs_parse_path(const char **path, uint8_t *diskno, uint8_t *partno);
+int multifs_setup_fs_info(struct fs_info *fsp, uint8_t diskno, uint8_t partno,
+                          void *priv);
+void multifs_restore_fs(void);
+int multifs_switch_fs(const char **path);
 
 #endif /* MULTIFS_H */
diff --git a/core/multifs.c b/core/multifs.c
index aafce57..d979db6 100644
--- a/core/multifs.c
+++ b/core/multifs.c
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ * Copyright (C) 2015 Paulo Alcantara <pcacjr at zytor.com>
  *
  * 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
@@ -17,58 +18,203 @@
  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
-#include <klibc/compiler.h>
 #include <stdio.h>
 #include <assert.h>
+#include <fs.h>
+#include <ilog2.h>
+#include <disk.h>
+#include <cache.h>
+#include <minmax.h>
+
 #include "multifs.h"
 
-static get_fs_info_t get_fs_info = NULL;
+#define DISKS_MAX 0x7f
 
-/*
- * Enable MultiFS support
- * This function is called from ldlinux.c32 to enable MultiFS support.
- *
- * @addr: address of the get_fs_info function from ldlinux.c32.
- */
-__export void enable_multifs(get_fs_info_t addr)
+struct part_node {
+    int partition;
+    struct fs_info *fs;
+    struct part_node *next;
+};
+
+struct queue_head {
+    struct part_node *first;
+    struct part_node *last;
+};
+
+static struct queue_head *parts_info[DISKS_MAX];
+
+static int add_fs(struct fs_info *fs, uint8_t diskno, uint8_t partno)
 {
-    if (addr) {
-	get_fs_info = addr;
-	dprintf("MultiFS: set get_fs_info to %p\n", get_fs_info);
+    struct queue_head *head = parts_info[diskno];
+    struct part_node *node;
+
+    node = malloc(sizeof(struct part_node));
+    if (!node)
+        return -1;
+    node->fs = fs;
+    node->next = NULL;
+    node->partition = partno;
+
+    if (!head) {
+        head = malloc(sizeof(struct queue_head));
+        if (!head) {
+            free(node);
+            return -1;
+        }
+        head->first = head->last = node;
+        parts_info[diskno] = head;
+        return 0;
     }
+    head->last->next = node;
+    head->last = node;
+    return 0;
 }
 
-/*
- * The request is considered MultiFS if the path starts
- * with an open parentheses.
- *
- * @ret: Upon success, set this_fs to the fs where the underlying file
- * resides and returns 0. Upon failure, returns -1;
- */
-int switch_fs(const char **path)
+struct fs_info *multifs_get_fs(uint8_t diskno, uint8_t partno)
+{
+    struct part_node *i;
+
+    for (i = parts_info[diskno]->first; i; i = i->next) {
+        if (i->partition == partno)
+            return i->fs;
+    }
+    return NULL;
+}
+
+static const char *get_num(const char *p, char delimiter, uint8_t *data)
+{
+    uint32_t n = 0;
+
+    while (*p) {
+        if (*p < '0' || *p > '9')
+            break;
+        n = (n * 10) + (*p - '0');
+        p++;
+        if (*p == delimiter) {
+            p++; /* skip delimiter */
+            *data = min(n, UINT8_MAX); /* avoid overflow */
+            return p;
+        }
+    }
+    return NULL;
+}
+
+int multifs_parse_path(const char **path, uint8_t *diskno, uint8_t *partno)
+{
+    const char *p = *path;
+    static const char *cwd = ".";
+
+    *diskno = *partno = 0;
+    p++; /* Skip open parentheses */
+
+    /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */
+    if (*p != 'h' || *(p + 1) != 'd')
+        return -1;
+
+    p += 2; /* Skip 'h' and 'd' */
+    p = get_num(p, ',', diskno);
+    if (!p)
+        return -1;
+    if (*diskno >= DISKS_MAX) {
+        printf("MultiFS: disk number is out of range: 0-%d\n",
DISKS_MAX - 1);
+        return -1;
+    }
+
+    /* Get partition number (Range: 0 - 0xFF) */
+    p = get_num(p, ')', partno);
+    if (!p)
+        return -1;
+
+    if (*p == '\0') {
+        /* Assume it's a cwd request */
+        p = cwd;
+    }
+
+    *path = p;
+    dprintf("MultiFS: disk: %u partition: %u path: %s\n", *diskno,
*partno,
+            *path);
+    return 0;
+}
+
+int multifs_setup_fs_info(struct fs_info *fsp, uint8_t diskno, uint8_t partno,
+                          void *priv)
+{
+    const struct fs_ops **ops;
+    int blk_shift = -1;
+    struct device *dev = NULL;
+
+    /* set default name for the root directory */
+    fsp->cwd_name[0] = '/';
+    fsp->cwd_name[1] = '\0';
+
+    ops = p_ops;
+    while ((blk_shift < 0) && *ops) {
+        /* set up the fs stucture */
+        fsp->fs_ops = *ops;
+
+        /*
+         * This boldly assumes that we don't mix FS_NODEV filesystems
+         * with FS_DEV filesystems...
+         */
+        if (fsp->fs_ops->fs_flags & FS_NODEV) {
+            fsp->fs_dev = NULL;
+        } else {
+            if (!dev) {
+                dev = device_init(priv);
+                if (!dev)
+                    return -1;
+            }
+            fsp->fs_dev = dev;
+        }
+        /* invoke the fs-specific init code */
+        blk_shift = fsp->fs_ops->fs_init(fsp);
+        ops++;
+    }
+    if (blk_shift < 0) {
+        dprintf("%s: no valid file system found!\n", __func__);
+        goto out_free;
+    }
+
+    if (add_fs(fsp, diskno, partno - 1))
+        goto out_free;
+    if (fsp->fs_dev && fsp->fs_dev->cache_data)
+        cache_init(fsp->fs_dev, blk_shift);
+    if (fsp->fs_ops->iget_root) {
+        fsp->root = fsp->fs_ops->iget_root(fsp);
+        fsp->cwd = get_inode(fsp->root);
+    }
+    return 0;
+
+out_free:
+    free(dev->disk);
+    free(dev->cache_data);
+    free(dev);
+    return -1;
+}
+
+void multifs_restore_fs(void)
+{
+    this_fs = root_fs;
+}
+
+int multifs_switch_fs(const char **path)
 {
     struct fs_info *fs;
 
     assert(path && *path);
     if ((*path)[0] != '(') {
-	/* If so, don't need to restore chdir */
-	if (this_fs == root_fs)
-	    return 0;
+        /* If so, don't need to restore chdir */
+        if (this_fs == root_fs)
+            return 0;
 
-	fs = root_fs;
-	goto ret;
+        fs = root_fs;
+        goto ret;
     }
 
-    if (__unlikely(!get_fs_info)) {
-	printf("MultiFS support is not enabled!\n");
-	return -1;
-    }
+    fs = multifs_ops->get_fs_info(path);
+    if (!fs)
+        return -1;
 
-    fs = get_fs_info(path);
-    if (!fs) {
-	dprintf("MultiFS: It wasn't possible to get the proper fs!\n");
-	return -1;
-    }
 ret:
     this_fs = fs;
     return 0;
diff --git a/core/multifs_bios.c b/core/multifs_bios.c
new file mode 100644
index 0000000..923773f
--- /dev/null
+++ b/core/multifs_bios.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr at zytor.com>
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include "core.h"
+#include "fs.h"
+#include "disk.h"
+#include "cache.h"
+#include "multifs.h"
+
+#include <syslinux/multifs_utils.h>
+
+/* MaxTransfer for MultiFS access */
+#define MAX_TRANSFER 127
+
+static bios_find_partition_t find_partition = NULL;
+
+__export struct fs_info *bios_multifs_get_fs_info(const char **path)
+{
+    struct fs_info *fsp;
+    void *private;
+    uint8_t hdd, partition;
+    struct multifs_utils_part_info *pinfo;
+    int ret;
+
+    if (multifs_parse_path(path, &hdd, &partition)) {
+        printf("MultiFS: Syntax invalid: %s\n", *path);
+        return NULL;
+    }
+
+    fsp = multifs_get_fs(hdd, partition - 1);
+    if (fsp)
+        return fsp;
+
+    fsp = malloc(sizeof(struct fs_info));
+    if (!fsp)
+        return NULL;
+
+    private = find_partition(hdd, partition);
+    if (!private) {
+        printf("MultiFS: Failed to get disk/partition: %s\n", *path);
+        goto bail;
+    }
+    ret = multifs_setup_fs_info(fsp, hdd, partition, private);
+    if (ret) {
+        goto bail;
+    }
+    return fsp;
+
+bail:
+    free(fsp);
+    return NULL;
+}
+
+__export void bios_multifs_init(void *addr)
+{
+    find_partition = addr;
+    dprintf("%s: initialised MultiFS support\n", __func__);
+}
diff --git a/efi/main.c b/efi/main.c
index a165b05..b2c8b0c 100644
--- a/efi/main.c
+++ b/efi/main.c
@@ -5,6 +5,7 @@
 #include <codepage.h>
 #include <core.h>
 #include <fs.h>
+#include <multifs.h>
 #include <com32.h>
 #include <syslinux/memscan.h>
 #include <syslinux/firmware.h>
@@ -15,7 +16,6 @@
 #include "efi.h"
 #include "fio.h"
 #include "version.h"
-#include "multifs_utils.h"
 
 __export uint16_t PXERetry;
 __export char copyright_str[] = "Copyright (C) 2011-" YEAR_STR
"\n";
@@ -132,6 +132,7 @@ void __cdecl core_farcall(uint32_t c, const com32sys_t *a,
com32sys_t *b)
 __export struct firmware *firmware = NULL;
 __export void *__syslinux_adv_ptr;
 __export size_t __syslinux_adv_size;
+__export const struct multifs_ops *multifs_ops = NULL;
 char core_xfer_buf[65536];
 struct iso_boot_info {
 	uint32_t pvd;               /* LBA of primary volume descriptor */
@@ -1193,9 +1194,18 @@ struct firmware efi_fw = {
 	.mem = &efi_mem_ops,
 };
 
+extern struct fs_info *efi_multifs_get_fs_info(const char **path);
+extern void efi_multifs_init(void);
+
+const struct multifs_ops efi_multifs_ops = {
+	.get_fs_info = efi_multifs_get_fs_info,
+	.init = efi_multifs_init,
+};
+
 static inline void syslinux_register_efi(void)
 {
 	firmware = &efi_fw;
+	multifs_ops = &efi_multifs_ops;
 }
 
 extern void init(void);
@@ -1289,12 +1299,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE
*table)
 		}
 
 		efi_derivative(SYSLINUX_FS_SYSLINUX);
-		status = init_multifs();
-		if (EFI_ERROR(status)) {
-			Print(L"Failed to initialise multifs support: %r\n",
-			      status);
-			goto out;
-		}
 	} else {
 		efi_derivative(SYSLINUX_FS_PXELINUX);
 		image_device_handle = info->DeviceHandle;
diff --git a/efi/multifs.c b/efi/multifs.c
new file mode 100644
index 0000000..418d0c2
--- /dev/null
+++ b/efi/multifs.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015 Paulo Alcantara <pcacjr at zytor.com>
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+#include <fs.h>
+#include <multifs.h>
+
+#include "efi.h"
+
+static EFI_HANDLE *logical_parts = NULL;
+static unsigned int logical_parts_no = 0;
+
+/* Find all device handles which support EFI_BLOCK_IO_PROTOCOL and are logical
+ * partitions */
+static EFI_STATUS find_all_logical_parts(void)
+{
+    EFI_STATUS status;
+    unsigned long len = 0;
+    EFI_HANDLE *handles = NULL;
+    unsigned long i;
+    EFI_BLOCK_IO *bio;
+
+    if (logical_parts) {
+        status = EFI_SUCCESS;
+        goto out;
+    }
+
+    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
+                               &BlockIoProtocol, NULL, &len, NULL);
+    if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL)
+        goto out;
+
+    handles = malloc(len);
+    if (!handles) {
+        status = EFI_OUT_OF_RESOURCES;
+        goto out;
+    }
+
+    logical_parts = malloc(len);
+    if (!logical_parts) {
+        status = EFI_OUT_OF_RESOURCES;
+        goto out_free;
+    }
+
+    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
+                               &BlockIoProtocol, NULL, &len,
+                               (void **)handles);
+    if (EFI_ERROR(status))
+        goto out_free;
+
+    for (i = 0; i < len / sizeof(EFI_HANDLE); i++) {
+        status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
+                                   &BlockIoProtocol, (void **)&bio);
+        if (EFI_ERROR(status))
+            goto out_free;
+        if (bio->Media->LogicalPartition) {
+            logical_parts[logical_parts_no++] = handles[i];
+        }
+    }
+
+    free(handles);
+    return status;
+
+out_free:
+    if (handles)
+        free(handles);
+    if (logical_parts)
+        free(logical_parts);
+out:
+    return status;
+}
+
+static inline EFI_HANDLE get_logical_part(unsigned int partno)
+{
+    if (!logical_parts || partno > logical_parts_no)
+        return NULL;
+    return logical_parts[partno - 1];
+}
+
+static inline EFI_HANDLE find_device_handle(unsigned int diskno,
+                                            unsigned int partno)
+{
+    return get_logical_part(partno);
+}
+
+static inline void *get_dev_info_priv(EFI_HANDLE lpart)
+{
+    static struct efi_disk_private priv;
+    priv.dev_handle = lpart;
+    return (void *)&priv;
+}
+
+__export struct fs_info *efi_multifs_get_fs_info(const char **path)
+{
+    uint8_t diskno;
+    uint8_t partno;
+    struct fs_info *fsp;
+    EFI_HANDLE handle;
+    void *priv;
+    int ret;
+
+    if (multifs_parse_path(path, &diskno, &partno))
+        return NULL;
+
+    fsp = multifs_get_fs(diskno, partno - 1);
+    if (fsp)
+        return fsp;
+
+    fsp = malloc(sizeof(*fsp));
+    if (!fsp)
+        return NULL;
+
+    handle = find_device_handle(diskno, partno);
+    if (!handle)
+        goto free_fsp;
+    dprintf("%s: found partition %d\n", __func__, partno);
+
+    priv = get_dev_info_priv(handle);
+    if (!priv)
+        goto free_fsp;
+
+    ret = multifs_setup_fs_info(fsp, diskno, partno, priv);
+    if (ret) {
+        dprintf("%s: failed to set up fs info\n", __func__);
+        goto free_dev_info;
+    }
+    return fsp;
+
+free_dev_info:
+    free(priv);
+free_fsp:
+    free(fsp);
+    return NULL;
+}
+
+__export void efi_multifs_init(void *addr __attribute__((unused)))
+{
+    EFI_STATUS status;
+
+    status = find_all_logical_parts();
+    if (EFI_ERROR(status)) {
+        printf("%s: failed to locate device handles of logical
partitions\n",
+               __func__);
+        printf("%s: EFI status code: 0x%08X\n", __func__, status);
+        return;
+    }
+    dprintf("%s: initialised MultiFS support\n", __func__);
+}
diff --git a/efi/multifs_utils.c b/efi/multifs_utils.c
deleted file mode 100644
index a4e3ff9..0000000
--- a/efi/multifs_utils.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (c) 2015 Paulo Alcantara <pcacjr at zytor.com>
- * Copyright (C) 2012 Andre Ericson <de.ericson at gmail.com>
- * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv at gmail.com>
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-*/
-#include <fs.h>
-#include <ilog2.h>
-#include <disk.h>
-
-#include "cache.h"
-#include "minmax.h"
-#include "multifs_utils.h"
-#include "efi.h"
-
-#define DISKS_MAX 0xff
-
-static EFI_HANDLE *_logical_parts = NULL;
-static unsigned int _logical_parts_no = 0;
-static struct queue_head *parts_info[DISKS_MAX];
-
-/* Find all BlockIo device handles which is a logical partition */
-static EFI_STATUS find_all_logical_parts(void)
-{
-    EFI_STATUS status;
-    unsigned long len = 0;
-    EFI_HANDLE *handles = NULL;
-    unsigned long i;
-    EFI_BLOCK_IO *bio;
-
-    if (_logical_parts) {
-        status = EFI_SUCCESS;
-        goto out;
-    }
-
-    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
-                               &BlockIoProtocol, NULL, &len, NULL);
-    if (EFI_ERROR(status) && status != EFI_BUFFER_TOO_SMALL)
-        goto out;
-
-    handles = malloc(len);
-    if (!handles) {
-        status = EFI_OUT_OF_RESOURCES;
-        goto out;
-    }
-
-    _logical_parts = malloc(len);
-    if (!_logical_parts) {
-        status = EFI_OUT_OF_RESOURCES;
-        goto out_free;
-    }
-
-    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol,
-                               &BlockIoProtocol, NULL, &len,
-                               (void **)handles);
-    if (EFI_ERROR(status))
-        goto out_free;
-
-    for (i = 0; i < len / sizeof(EFI_HANDLE); i++) {
-        status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
-                                   &BlockIoProtocol, (void **)&bio);
-        if (EFI_ERROR(status))
-            goto out_free;
-        if (bio->Media->LogicalPartition) {
-            _logical_parts[_logical_parts_no++] = handles[i];
-        }
-    }
-
-    free(handles);
-    return status;
-
-out_free:
-    if (handles)
-        free(handles);
-    if (_logical_parts)
-        free(_logical_parts);
-out:
-    return status;
-}
-
-static inline EFI_HANDLE get_logical_part(unsigned int partno)
-{
-    if (!_logical_parts || partno > _logical_parts_no)
-        return NULL;
-    return _logical_parts[partno - 1];
-}
-
-static int add_fs(struct fs_info *fs, uint8_t disk, uint8_t partition)
-{
-    struct queue_head *head = parts_info[disk];
-    struct part_node *node;
-
-    node = malloc(sizeof(struct part_node));
-    if (!node)
-        return -1;
-    node->fs = fs;
-    node->next = NULL;
-    node->partition = partition;
-
-    if (!head) {
-        head = malloc(sizeof(struct queue_head));
-        if (!head) {
-            free(node);
-            return -1;
-        }
-        head->first = head->last = node;
-        parts_info[disk] = head;
-        return 0;
-    }
-    head->last->next = node;
-    head->last = node;
-    return 0;
-}
-
-static struct fs_info *get_fs(uint8_t disk, uint8_t partition)
-{
-    struct part_node *i;
-
-    for (i = parts_info[disk]->first; i; i = i->next) {
-        if (i->partition == partition)
-            return i->fs;
-    }
-    return NULL;
-}
-
-static EFI_HANDLE find_partition(unsigned int diskno, unsigned int partno)
-{
-    return get_logical_part(partno);
-}
-
-static const char *get_num(const char *p, char delimiter, unsigned int *data)
-{
-    uint32_t n = 0;
-
-    while (*p) {
-        if (*p < '0' || *p > '9')
-            break;
-        n = (n * 10) + (*p - '0');
-        p++;
-        if (*p == delimiter) {
-            p++; /* skip delimiter */
-            *data = min(n, UINT8_MAX); /* avoid overflow */
-            return p;
-        }
-    }
-    return NULL;
-}
-
-static int parse_multifs_path(const char **path, unsigned int *hdd,
-                              unsigned int *partition)
-{
-    const char *p = *path;
-    static const char *cwd = ".";
-
-    *hdd = *partition = 0;
-    p++; /* Skip open parentheses */
-
-    /* Get hd number (Range: 0 - (DISKS_MAX - 1)) */
-    if (*p != 'h' || *(p + 1) != 'd')
-        return -1;
-
-    p += 2; /* Skip 'h' and 'd' */
-    p = get_num(p, ',', hdd);
-    if (!p)
-        return -1;
-    if (*hdd >= DISKS_MAX) {
-        printf("MultiFS: hdd is out of range: 0-%d\n", DISKS_MAX -
1);
-        return -1;
-    }
-
-    /* Get partition number (Range: 0 - 0xFF) */
-    p = get_num(p, ')', partition);
-    if (!p)
-        return -1;
-
-    if (*p == '\0') {
-        /* Assume it's a cwd request */
-        p = cwd;
-    }
-
-    *path = p;
-    dprintf("MultiFS: hdd: %u partition: %u path: %s\n",
-            *hdd, *partition, *path);
-    return 0;
-}
-
-static inline void *get_private(EFI_HANDLE lpart)
-{
-    static struct efi_disk_private priv;
-    priv.dev_handle = lpart;
-    return (void *)&priv;
-}
-
-static struct fs_info *get_fs_info(const char **path)
-{
-    const struct fs_ops **ops;
-    struct fs_info *fsp;
-    EFI_HANDLE dh;
-    struct device *dev = NULL;
-    void *private;
-    int blk_shift = -1;
-    unsigned int hdd, partition;
-
-    if (parse_multifs_path(path, &hdd, &partition)) {
-        return NULL;
-    }
-
-    fsp = get_fs(hdd, partition - 1);
-    if (fsp)
-        return fsp;
-
-    fsp = malloc(sizeof(struct fs_info));
-    if (!fsp)
-        return NULL;
-
-    dh = find_partition(hdd, partition);
-    if (!dh)
-        goto bail;
-    dprintf("\nMultiFS: found partition %d\n", partition);
-    private = get_private(dh);
-
-    /* set default name for the root directory */
-    fsp->cwd_name[0] = '/';
-    fsp->cwd_name[1] = '\0';
-
-    ops = p_ops;
-    while ((blk_shift < 0) && *ops) {
-        /* set up the fs stucture */
-        fsp->fs_ops = *ops;
-
-        /*
-         * This boldly assumes that we don't mix FS_NODEV filesystems
-         * with FS_DEV filesystems...
-         */
-        if (fsp->fs_ops->fs_flags & FS_NODEV) {
-            fsp->fs_dev = NULL;
-        } else {
-            if (!dev) {
-                dev = device_init(private);
-                if (!dev)
-                    goto bail;
-            }
-            fsp->fs_dev = dev;
-        }
-        /* invoke the fs-specific init code */
-        blk_shift = fsp->fs_ops->fs_init(fsp);
-        ops++;
-    }
-    if (blk_shift < 0) {
-        dprintf("MultiFS: No valid file system found!\n");
-        goto free_dev;
-    }
-
-    if (add_fs(fsp, hdd, partition - 1))
-        goto free_dev;
-    if (fsp->fs_dev && fsp->fs_dev->cache_data &&
!fsp->fs_dev->cache_init)
-        cache_init(fsp->fs_dev, blk_shift);
-    if (fsp->fs_ops->iget_root) {
-        fsp->root = fsp->fs_ops->iget_root(fsp);
-        fsp->cwd = get_inode(fsp->root);
-    }
-    return fsp;
-
-free_dev:
-    free(dev->disk);
-    free(dev->cache_data);
-    free(dev);
-bail:
-    free(fsp);
-    return NULL;
-}
-
-EFI_STATUS init_multifs(void)
-{
-    EFI_STATUS status;
-
-    status = find_all_logical_parts();
-    enable_multifs(get_fs_info);
-    dprintf("MultiFS: initialised\n");
-
-    return status;
-}
-- 
2.1.0
Paulo Alcantara
2015-Jul-22  23:27 UTC
[syslinux] [PULL 8/8] efi/multifs: fix misuse of static private information
The get_dev_info_priv() function cannot return a reference of a static
variable since there might be multiple device handles and each one per
logical partition. A typical example of this failure is when a
configuration file contains multifs-path-syntax like, so multifs will
initialised to the first partition found (including its device handle)
and the other ones will be using the same partition to do I/O.
Cc: Gene Cumm <gene.cumm at gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr at zytor.com>
---
 efi/multifs.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/efi/multifs.c b/efi/multifs.c
index 418d0c2..63bf73e 100644
--- a/efi/multifs.c
+++ b/efi/multifs.c
@@ -97,11 +97,15 @@ static inline EFI_HANDLE find_device_handle(unsigned int
diskno,
     return get_logical_part(partno);
 }
 
-static inline void *get_dev_info_priv(EFI_HANDLE lpart)
+static inline void *get_dev_info_priv(EFI_HANDLE handle)
 {
-    static struct efi_disk_private priv;
-    priv.dev_handle = lpart;
-    return (void *)&priv;
+    struct efi_disk_private *priv;
+
+    priv = malloc(sizeof(*priv));
+    if (!priv)
+        return NULL;
+    priv->dev_handle = handle;
+    return priv;
 }
 
 __export struct fs_info *efi_multifs_get_fs_info(const char **path)
@@ -136,11 +140,11 @@ __export struct fs_info *efi_multifs_get_fs_info(const
char **path)
     ret = multifs_setup_fs_info(fsp, diskno, partno, priv);
     if (ret) {
         dprintf("%s: failed to set up fs info\n", __func__);
-        goto free_dev_info;
+        goto free_priv;
     }
     return fsp;
 
-free_dev_info:
+free_priv:
     free(priv);
 free_fsp:
     free(fsp);
-- 
2.1.0
> The MultiFS syntax is basically "(hdX,Y)/path/to/file", where X is disk > number and Y is partition number. >Thank you. As a reminder, please note: _ There was a syntax discussion about "multifs", so additional syntax forms should be allowed too (please read the whole email thread): http://www.syslinux.org/archives/2014-June/022173.html Examples: __ Space or comma should be valid alternatives (as chain.c32); __ Not only numbering, but also labels, uuid's and other forms of identification should be allowed / supported too (as chain.c32). _ And _please_ I beg you all to use the simple term "multifs", without unnecessary "fanciness": http://www.syslinux.org/archives/2014-July/022493.html TIA, Ady.
Raphael S Carvalho
2015-Jul-23  21:09 UTC
[syslinux] [PULL 0/8] MultiFS suppport for BIOS and EFI
On Wed, Jul 22, 2015 at 11:15 PM, Ady via Syslinux <syslinux at zytor.com> wrote:> > > The MultiFS syntax is basically "(hdX,Y)/path/to/file", where X is disk > > number and Y is partition number. > > > > Thank you. > > As a reminder, please note: > > _ There was a syntax discussion about "multifs", so additional syntax > forms should be allowed too (please read the whole email thread): > http://www.syslinux.org/archives/2014-June/022173.html > Examples: > __ Space or comma should be valid alternatives (as chain.c32); > __ Not only numbering, but also labels, uuid's and other forms of > identification should be allowed / supported too (as chain.c32). >My sincere opinion is to apply this patchset as-is, and incrementally improve multifs. Lack of alternatives (additional features) *should not* be a reason to block this patchset. Again, I really think that this patchset should be applied unless a technical reason, e.g. some deficiency introduced by one of the patches, says otherwise. HPA, what do you think?> > _ And _please_ I beg you all to use the simple term "multifs", without > unnecessary "fanciness": > http://www.syslinux.org/archives/2014-July/022493.html > > TIA, > Ady. > > _______________________________________________ > Syslinux mailing list > Submissions to Syslinux at zytor.com > Unsubscribe or set options at: > http://www.zytor.com/mailman/listinfo/syslinux >-- Raphael S. Carvalho
Michal Soltys
2015-Aug-08  10:49 UTC
[syslinux] [PULL 1/8] Move partiter from com32/chain to com32/lib/syslinux
On 2015-07-23 01:27, Paulo Alcantara via Syslinux wrote:> 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 ++++++++++++++For the record, moving utility.h (which is just a bunch of functions referenced in different chain files) is probably too much. And those functions are not that useful outside chain. Essentially, just: - move warn(), critm(), error() to partiter.h - redefine guid_is0() in partiter.c - remove references to utility.h Would be IMHO cleaner approach.
... Syslinux MultiFS test: - QEMU/KVM SeaBIOS: PASSED - Bare-metal BIOS: FAILED [1] - OVMF: FAILED [2] - Bare-metal UEFI: not tested [1] stalled: Loading (hd3,2)/vmlinuz-4.3.2-200.fc22.x86_64... [2] "failed: No such file or directory" http://git.zytor.com/users/pcacjr/syslinux.git/tree/core/include/multifs.h?h=multifs-for-upstream#n27 * MULTIFS SYNTAX: * (hd[disk number],[partition number])/path/to/file * * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. * Disk and Partition numbering starts from 0 and 1 respectivelly. */ ... # fdisk -l /dev/vdb | grep -w 83 /dev/vdb2 2099200 4194303 2095104 1023M 83 Linux # mount | grep vdb2 /dev/vdb2 on /data type ext4 ... # ls -1 /data initramfs-4.4.0-0.rc5.git0.1.fc24.x86_64.img lost+found vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64 BOOT: find_all_partitions: failed to set EFI disk info efi_multifs_init: failed to find disk partitions: Invalid Parameter No DEFAULT or UI configuration directive found! boot: 2 Loading (hd1,2)/vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64... failed: No such file o r directory boot: SW: qemu-2.5.0-1.fc24.x86_64 seabios-1.9.0-1.fc24.noarch edk2.git-ovmf-x64-0-20151218.b1388.g8873b17.noarch http://goo.gl/Gm4ffO /syslinux efi64 syslinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm syslinux-efi64-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm syslinux-extlinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm syslinux-extlinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm syslinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm
On 20.12.2015 09:55, poma wrote:> ... > > Syslinux MultiFS test: > > - QEMU/KVM SeaBIOS: PASSED > - Bare-metal BIOS: FAILED [1] > - OVMF: FAILED [2] > - Bare-metal UEFI: not tested > > > [1] stalled: > Loading (hd3,2)/vmlinuz-4.3.2-200.fc22.x86_64... > > > [2] "failed: No such file or directory" > > http://git.zytor.com/users/pcacjr/syslinux.git/tree/core/include/multifs.h?h=multifs-for-upstream#n27 > * MULTIFS SYNTAX: > * (hd[disk number],[partition number])/path/to/file > * > * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. > * Disk and Partition numbering starts from 0 and 1 respectivelly. > */ > ... > > > # fdisk -l /dev/vdb | grep -w 83 > /dev/vdb2 2099200 4194303 2095104 1023M 83 Linux > # mount | grep vdb2 > /dev/vdb2 on /data type ext4 ... > # ls -1 /data > initramfs-4.4.0-0.rc5.git0.1.fc24.x86_64.img > lost+found > vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64 > > > BOOT: > find_all_partitions: failed to set EFI disk info > efi_multifs_init: failed to find disk partitions: Invalid Parameter > No DEFAULT or UI configuration directive found! > boot: 2 > Loading (hd1,2)/vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64... failed: No such file o > r directory > boot: > > > SW: > qemu-2.5.0-1.fc24.x86_64 > seabios-1.9.0-1.fc24.noarch > edk2.git-ovmf-x64-0-20151218.b1388.g8873b17.noarch > > http://goo.gl/Gm4ffO > /syslinux efi64 > syslinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm > syslinux-efi64-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm > syslinux-extlinux-6.04-0.22.20151210git721a0af.fc24.x86_64.rpm > syslinux-extlinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm > syslinux-nonlinux-6.04-0.22.20151210git721a0af.fc24.noarch.rpm > >http://git.zytor.com/users/pcacjr/syslinux.git/log/?h=multifs-for-upstream without the last two patches: 0009-s-MultiFS-multifs.patch 0010-efi-multifs-correctly-enumerate-partitions-per-disk.patch OVMF MultiFS BOOT failed-stalled, the same as on Bare-metal BIOS No DEFAULT or UI configuration directive found! boot: 2 Loading (hd1,2)/vmlinuz-4.4.0-0.rc5.git0.1.fc24.x86_64... http://goo.gl/Gm4ffO /syslinux efi64/ttyS0-debug.txt