diff options
author | Raphael S. Carvalho <raphael.scarv@gmail.com> | 2013-10-18 02:06:41 -0300 |
---|---|---|
committer | Paulo Alcantara <pcacjr@zytor.com> | 2016-01-31 18:35:19 -0200 |
commit | 1713bbec496a98a847a03cc94b8c06a95d559caa (patch) | |
tree | 5422b8dea81f34f0f90bc017dbcbf410b155ba57 | |
parent | b5ff74ae43ec48da32f220ec677f586ac9221856 (diff) | |
download | syslinux-1713bbec496a98a847a03cc94b8c06a95d559caa.tar.gz syslinux-1713bbec496a98a847a03cc94b8c06a95d559caa.tar.xz syslinux-1713bbec496a98a847a03cc94b8c06a95d559caa.zip |
core: multifs infrastructure added.
multifs syntax:
(hd[disk number],[partition number])/path/to/file
The meaning of this_fs was changed to improve the flexibility of the support.
Now, this_fs means the file system being currently used.
root_fs was created to save the context of the main file system (where ldlinux.sys lives in).
get_fs_info is a function pointer that will be later hooked to a function from ldlinux.c32.
get_fs_info is expected to return a fs_info structure given the multifs path.
Cc: Gene Cumm <gene.cumm@gmail.com>
Signed-off-by: Raphael S. Carvalho <raphael.scarv@gmail.com>
Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r-- | core/fs/cache.c | 2 | ||||
-rw-r--r-- | core/fs/diskio.c | 28 | ||||
-rw-r--r-- | core/fs/diskio_bios.c | 40 | ||||
-rw-r--r-- | core/fs/fs.c | 22 | ||||
-rw-r--r-- | core/fs/readdir.c | 9 | ||||
-rw-r--r-- | core/include/multifs.h | 61 | ||||
-rw-r--r-- | core/multifs.c | 76 |
7 files changed, 206 insertions, 32 deletions
diff --git a/core/fs/cache.c b/core/fs/cache.c index 8da75bc4..31a5db30 100644 --- a/core/fs/cache.c +++ b/core/fs/cache.c @@ -15,7 +15,7 @@ * the block size, which is 512 byte for FAT fs of the current * implementation since the block(cluster) size in FAT is a bit big. */ -void cache_init(struct device *dev, int block_size_shift) +__export void cache_init(struct device *dev, int block_size_shift) { struct cache *prev, *cur; char *data = dev->cache_data; diff --git a/core/fs/diskio.c b/core/fs/diskio.c index e9a4c1da..94cc351e 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -21,14 +21,28 @@ void getoneblk(struct disk *disk, char *buf, block_t block, int block_size) /* * Initialize the device structure. */ -struct device * device_init(void *args) +__export struct device *device_init(void *args) { - static struct device dev; + struct device *dev; - dev.disk = firmware->disk_init(args); - dev.cache_size = 128*1024; - dev.cache_data = malloc(dev.cache_size); - dev.cache_init = 0; /* Explicitly set cache as uninitialized */ + dev = malloc(sizeof(struct device)); + if (!dev) + return NULL; - return &dev; + dev->disk = firmware->disk_init(args); + if (!dev->disk) + goto out; + + dev->cache_size = 128*1024; + dev->cache_data = malloc(dev->cache_size); + if (!dev->cache_data) + goto out_disk; + dev->cache_init = 0; + + return dev; +out_disk: + free(dev->disk); +out: + free(dev); + return NULL; } diff --git a/core/fs/diskio_bios.c b/core/fs/diskio_bios.c index 7feb7fc4..621896ff 100644 --- a/core/fs/diskio_bios.c +++ b/core/fs/diskio_bios.c @@ -287,7 +287,7 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, struct disk *bios_disk_init(void *private) { - static struct disk disk; + struct disk *disk; struct bios_disk_private *priv = (struct bios_disk_private *)private; com32sys_t *regs = priv->regs; static __lowmem struct edd_disk_params edd_params; @@ -302,6 +302,10 @@ struct disk *bios_disk_init(void *private) int sector_size; unsigned int hard_max_transfer; + disk = malloc(sizeof(struct disk)); + if (!disk) + return NULL; + memset(&ireg, 0, sizeof ireg); ireg.edx.b[0] = devno; @@ -319,18 +323,18 @@ struct disk *bios_disk_init(void *private) hard_max_transfer = 63; /* CBIOS parameters */ - disk.h = bsHeads; - disk.s = bsSecPerTrack; + disk->h = bsHeads; + disk->s = bsSecPerTrack; if ((int8_t)devno < 0) { /* Get hard disk geometry from BIOS */ - + ireg.eax.b[1] = 0x08; __intcall(0x13, &ireg, &oreg); - + if (!(oreg.eflags.l & EFLAGS_CF)) { - disk.h = oreg.edx.b[1] + 1; - disk.s = oreg.ecx.b[0] & 63; + disk->h = oreg.edx.b[1] + 1; + disk->s = oreg.ecx.b[0] & 63; } } @@ -374,24 +378,24 @@ struct disk *bios_disk_init(void *private) } - disk.disk_number = devno; - disk.sector_size = sector_size; - disk.sector_shift = ilog2(sector_size); - disk.part_start = part_start; - disk.secpercyl = disk.h * disk.s; - disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; + disk->disk_number = devno; + disk->sector_size = sector_size; + disk->sector_shift = ilog2(sector_size); + disk->part_start = part_start; + disk->secpercyl = disk->h * disk->s; + disk->rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors; if (!MaxTransfer || MaxTransfer > hard_max_transfer) MaxTransfer = hard_max_transfer; - disk.maxtransfer = MaxTransfer; + disk->maxtransfer = MaxTransfer; dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", - devno, cdrom, ebios, sector_size, disk.sector_shift, - part_start, disk.maxtransfer); + devno, cdrom, ebios, sector_size, disk->sector_shift, + part_start, disk->maxtransfer); - disk.private = private; - return &disk; + disk->private = private; + return disk; } void pm_fs_init(com32sys_t *regs) diff --git a/core/fs/fs.c b/core/fs/fs.c index 41618487..a5d8db4b 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -10,9 +10,14 @@ #include "dev.h" #include "fs.h" #include "cache.h" +#include "multifs.h" -/* The currently mounted filesystem */ -__export struct fs_info *this_fs = NULL; /* Root filesystem */ +/* root_fs means the file system where ldlinux.sys lives in. */ +__export struct fs_info *root_fs = NULL; +/* this_fs means the file system being currently used. */ +__export struct fs_info *this_fs = NULL; +/* export p_ops to be used outside the core */ +__export const struct fs_ops **p_ops = NULL; /* Actual file structures (we don't have malloc yet...) */ __export struct file files[MAX_OPEN]; @@ -345,6 +350,9 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed dprintf("open_file %s\n", name); + if (switch_fs(&name)) + return -1; + mangle_name(mangled_name, name); rv = searchdir(mangled_name, flags); @@ -362,6 +370,9 @@ __export int open_file(const char *name, int flags, struct com32_filedata *filed filedata->blocklg2 = SECTOR_SHIFT(file->fs); filedata->handle = rv; + restore_fs(); + restore_chdir_start(); + return rv; } @@ -403,6 +414,7 @@ void fs_init(const struct fs_ops **ops, void *priv) /* Default name for the root directory */ fs.cwd_name[0] = '/'; + p_ops = ops; while ((blk_shift < 0) && *ops) { /* set up the fs stucture */ @@ -428,7 +440,7 @@ void fs_init(const struct fs_ops **ops, void *priv) while (1) ; } - this_fs = &fs; + root_fs = this_fs = &fs; /* initialize the cache only if it wasn't already initialized * by the fs driver */ @@ -443,8 +455,8 @@ void fs_init(const struct fs_ops **ops, void *priv) } if (fs.fs_ops->chdir_start) { - if (fs.fs_ops->chdir_start() < 0) - printf("Failed to chdir to start directory\n"); + if (fs.fs_ops->chdir_start() < 0) + printf("Failed to chdir to start directory\n"); } SectorShift = fs.sector_shift; diff --git a/core/fs/readdir.c b/core/fs/readdir.c index 546a704a..2a1efded 100644 --- a/core/fs/readdir.c +++ b/core/fs/readdir.c @@ -4,6 +4,7 @@ #include <sys/dirent.h> #include "fs.h" #include "core.h" +#include "multifs.h" /* * Open a directory @@ -13,6 +14,9 @@ __export DIR *opendir(const char *path) int rv; struct file *file; + if (switch_fs(&path)) + return NULL; + rv = searchdir(path, O_RDONLY|O_DIRECTORY); if (rv < 0) return NULL; @@ -24,6 +28,9 @@ __export DIR *opendir(const char *path) return NULL; } + restore_fs(); + restore_chdir_start(); + return (DIR *)file; } @@ -35,7 +42,7 @@ __export struct dirent *readdir(DIR *dir) static struct dirent buf; struct file *dd_dir = (struct file *)dir; int rv = -1; - + if (dd_dir) { if (dd_dir->fs->fs_ops->readdir) { rv = dd_dir->fs->fs_ops->readdir(dd_dir, &buf); diff --git a/core/include/multifs.h b/core/include/multifs.h new file mode 100644 index 00000000..861ca97e --- /dev/null +++ b/core/include/multifs.h @@ -0,0 +1,61 @@ +/* + * 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. +*/ + +#ifndef MULTIFS_H +#define MULTIFS_H + +/* + * MULTIFS SYNTAX: + * (hd[disk number],[partition number])/path/to/file + * + * E.G.: (hd0,1)/dir/file means /dir/file at partition 1 of the disk 0. + * Disk and Partition numbering starts from 0 and 1 respectivelly. + */ +#include "fs.h" + +/* + * root_fs means the file system where ldlinux.sys lives in. + * this_fs means the file system being currently used. + */ +extern struct fs_info *this_fs, *root_fs; + +/* + * Set this_fs back to root_fs, + * otherwise unexpected behavior may occurs. + */ +static inline void restore_fs(void) +{ + this_fs = root_fs; +} + +/* + * Basically restores the cwd of the underlying fs. + */ +static inline void restore_chdir_start(void) +{ + if (this_fs->fs_ops->chdir_start) { + if (this_fs->fs_ops->chdir_start() < 0) + printf("Failed to chdir to start directory\n"); + } +} + +typedef struct fs_info *(*get_fs_info_t)(const char **); +extern int switch_fs(const char **); + +#endif /* MULTIFS_H */ diff --git a/core/multifs.c b/core/multifs.c new file mode 100644 index 00000000..8951ef76 --- /dev/null +++ b/core/multifs.c @@ -0,0 +1,76 @@ +/* + * 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 <klibc/compiler.h> +#include <stdio.h> +#include <assert.h> +#include "multifs.h" + +static get_fs_info_t get_fs_info = NULL; + +/* + * Enable MultiFS support + * This function is called from ldlinux.c32 to enable MultiFS support. + * + * @addr: address of the get_fs_info function from ldlinux.c32. + */ +__export void enable_multifs(get_fs_info_t addr) +{ + if (addr) { + get_fs_info = addr; + dprintf("MultiFS: set get_fs_info to %p\n", get_fs_info); + } +} + +/* + * The request is considered MultiFS if the path starts + * with an open parentheses. + * + * @ret: Upon success, set this_fs to the fs where the underlying file + * resides and returns 0. Upon failure, returns -1; + */ +int switch_fs(const char **path) +{ + struct fs_info *fs; + + assert(path && *path); + if ((*path)[0] != '(') { + /* If so, don't need to restore chdir */ + if (this_fs == root_fs) + return 0; + + fs = root_fs; + goto ret; + } + + if (__unlikely(!get_fs_info)) { + printf("MultiFS support is not enabled!\n"); + return -1; + } + + fs = get_fs_info(path); + if (!fs) { + dprintf("MultiFS: It wasn't possible to get the proper fs!\n"); + return -1; + } +ret: + this_fs = fs; + restore_chdir_start(); + return 0; +} |