[syslinux] [PULL 3/8] Wire up MultiFS support.

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


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



More information about the Syslinux mailing list