aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaphael S. Carvalho <raphael.scarv@gmail.com>2013-10-18 02:06:41 -0300
committerPaulo Alcantara <pcacjr@zytor.com>2016-01-31 18:35:19 -0200
commit1713bbec496a98a847a03cc94b8c06a95d559caa (patch)
tree5422b8dea81f34f0f90bc017dbcbf410b155ba57
parentb5ff74ae43ec48da32f220ec677f586ac9221856 (diff)
downloadsyslinux-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.c2
-rw-r--r--core/fs/diskio.c28
-rw-r--r--core/fs/diskio_bios.c40
-rw-r--r--core/fs/fs.c22
-rw-r--r--core/fs/readdir.c9
-rw-r--r--core/include/multifs.h61
-rw-r--r--core/multifs.c76
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;
+}