[syslinux:multifs] multifs: add support for both UEFI and BIOS firmware

syslinux-bot for Paulo Alcantara pcacjr at zytor.com
Mon Feb 1 03:18:08 PST 2016


Commit-ID:  82fc42338f58fb59b83e42ab117d40d081cb0115
Gitweb:     http://www.syslinux.org/commit/82fc42338f58fb59b83e42ab117d40d081cb0115
Author:     Paulo Alcantara <pcacjr at zytor.com>
AuthorDate: Wed, 22 Jul 2015 02:36:28 -0300
Committer:  Paulo Alcantara <pcacjr at zytor.com>
CommitDate: Sun, 31 Jan 2016 18:35:19 -0200

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(-)

diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index fdfe88c..3955571 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 },
@@ -150,8 +149,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 0172117..786f31c 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>
 
@@ -294,6 +296,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);
@@ -306,6 +313,8 @@ __export int main(int argc __unused, char **argv)
 	size_t count = 0;
 	int retval;
 
+	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 43b920b..fe3d493 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>
@@ -16,7 +17,6 @@
 #include "fio.h"
 #include "version.h"
 #include "efi_pxe.h"
-#include "multifs_utils.h"
 
 __export uint16_t PXERetry;
 __export char copyright_str[] = "Copyright (C) 2011-" YEAR_STR "\n";
@@ -202,6 +202,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 */
@@ -1261,9 +1262,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);
@@ -1357,12 +1367,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;
-}


More information about the Syslinux-commits mailing list