aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2015-07-22 02:36:28 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2016-01-31 18:35:19 -0200
commit82fc42338f58fb59b83e42ab117d40d081cb0115 (patch)
tree6d397b49cc6089a225b8e5b68326e9f47ddc76b2
parent1526689e57e57a55f2de0d94fe938a09153608d1 (diff)
downloadsyslinux-82fc42338f58fb59b83e42ab117d40d081cb0115.tar.gz
syslinux-82fc42338f58fb59b83e42ab117d40d081cb0115.tar.xz
syslinux-82fc42338f58fb59b83e42ab117d40d081cb0115.zip
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@gmail.com> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--com32/elflink/ldlinux/execute.c3
-rw-r--r--com32/elflink/ldlinux/ldlinux.c9
-rw-r--r--com32/include/syslinux/multifs_utils.h25
-rw-r--r--com32/lib/syslinux/multifs_utils.c318
-rw-r--r--core/bios.c11
-rw-r--r--core/fs/fs.c4
-rw-r--r--core/fs/readdir.c4
-rw-r--r--core/include/multifs.h43
-rw-r--r--core/multifs.c214
-rw-r--r--core/multifs_bios.c75
-rw-r--r--efi/main.c18
-rw-r--r--efi/multifs.c162
-rw-r--r--efi/multifs_utils.c296
13 files changed, 514 insertions, 668 deletions
diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index fdfe88c1..39555715 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 0172117b..786f31c8 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 90ef6d69..4bf29a67 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@gmail.com>
- * Copyright (C) 2012 Paulo Cavalcanti <pcacjr@zytor.com>
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr@zytor.com>
* Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv@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 d243ef2c..1f15030a 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@gmail.com>
- * Copyright (C) 2012 Paulo Cavalcanti <pcacjr@zytor.com>
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr@zytor.com>
* Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv@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 = &regs;
-
- 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 7fb37fec..0ce31df0 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 1bea6b59..4feb798b 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 07fae5da..8acdd558 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 861ca97e..0d6bff19 100644
--- a/core/include/multifs.h
+++ b/core/include/multifs.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv@gmail.com>
+ * Copyright (C) 2015 Paulo Alcantara <pcacjr@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 aafce571..d979db6f 100644
--- a/core/multifs.c
+++ b/core/multifs.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv@gmail.com>
+ * Copyright (C) 2015 Paulo Alcantara <pcacjr@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 00000000..923773f9
--- /dev/null
+++ b/core/multifs_bios.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 Andre Ericson <de.ericson@gmail.com>
+ * Copyright (C) 2012-2015 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv@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 43b920b5..fe3d4931 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 00000000..418d0c2c
--- /dev/null
+++ b/efi/multifs.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2015 Paulo Alcantara <pcacjr@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 a4e3ff9c..00000000
--- a/efi/multifs_utils.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * Copyright (c) 2015 Paulo Alcantara <pcacjr@zytor.com>
- * Copyright (C) 2012 Andre Ericson <de.ericson@gmail.com>
- * Copyright (C) 2013 Raphael S. Carvalho <raphael.scarv@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;
-}