diff options
author | Paulo Alcantara <pcacjr@zytor.com> | 2015-07-22 02:36:28 -0300 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2016-01-31 18:35:19 -0200 |
commit | 82fc42338f58fb59b83e42ab117d40d081cb0115 (patch) | |
tree | 6d397b49cc6089a225b8e5b68326e9f47ddc76b2 | |
parent | 1526689e57e57a55f2de0d94fe938a09153608d1 (diff) | |
download | syslinux-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.c | 3 | ||||
-rw-r--r-- | com32/elflink/ldlinux/ldlinux.c | 9 | ||||
-rw-r--r-- | com32/include/syslinux/multifs_utils.h | 25 | ||||
-rw-r--r-- | com32/lib/syslinux/multifs_utils.c | 318 | ||||
-rw-r--r-- | core/bios.c | 11 | ||||
-rw-r--r-- | core/fs/fs.c | 4 | ||||
-rw-r--r-- | core/fs/readdir.c | 4 | ||||
-rw-r--r-- | core/include/multifs.h | 43 | ||||
-rw-r--r-- | core/multifs.c | 214 | ||||
-rw-r--r-- | core/multifs_bios.c | 75 | ||||
-rw-r--r-- | efi/main.c | 18 | ||||
-rw-r--r-- | efi/multifs.c | 162 | ||||
-rw-r--r-- | 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 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 = ®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 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__); +} @@ -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; -} |