summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordfr <dfr@FreeBSD.org>2001-09-07 08:51:48 +0000
committerdfr <dfr@FreeBSD.org>2001-09-07 08:51:48 +0000
commit622326c63f3f1ddcb403114fe79b534bb7460cee (patch)
tree850ec5e8bcc8596551e2cbb390f58043230a016c /sys
parent6f1a1519fddb32bfc76e36cbf05c2cc0c415adca (diff)
downloadFreeBSD-src-622326c63f3f1ddcb403114fe79b534bb7460cee.zip
FreeBSD-src-622326c63f3f1ddcb403114fe79b534bb7460cee.tar.gz
Add a libstand filesystem for accessing EFI native filesystems.
Diffstat (limited to 'sys')
-rw-r--r--sys/boot/efi/libefi/Makefile2
-rw-r--r--sys/boot/efi/libefi/efiboot.h9
-rw-r--r--sys/boot/efi/libefi/efifs.c341
3 files changed, 349 insertions, 3 deletions
diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile
index dac66ed..7e53714 100644
--- a/sys/boot/efi/libefi/Makefile
+++ b/sys/boot/efi/libefi/Makefile
@@ -7,7 +7,7 @@ INTERNALLIB= true
INTERNALSTATICLIB= true
SRCS= libefi.c efi_console.c time.c copy.c devicename.c module.c exit.c
-SRCS+= delay.c
+SRCS+= delay.c efifs.c
CFLAGS+= -fpic
CFLAGS+= -I${.CURDIR}/../include
diff --git a/sys/boot/efi/libefi/efiboot.h b/sys/boot/efi/libefi/efiboot.h
index b1d7df0..518c9c0 100644
--- a/sys/boot/efi/libefi/efiboot.h
+++ b/sys/boot/efi/libefi/efiboot.h
@@ -35,11 +35,12 @@
* EFI fully-qualified device descriptor
*/
struct efi_devdesc {
- struct devsw *d_dev;
- int d_type;
+ struct devsw *d_dev;
+ int d_type;
#define DEVT_NONE 0
#define DEVT_DISK 1
#define DEVT_NET 2
+ EFI_HANDLE d_handle;
union {
struct {
int unit;
@@ -61,9 +62,13 @@ extern int efi_setcurrdev(struct env_var *ev, int flags, void *value);
typedef unsigned long physaddr_t;
/* exported devices XXX rename? */
+extern struct devsw efifs_dev;
extern struct devsw efi_disk;
extern struct netif_driver efi_net;
+/* Wrapper over EFI filesystems. */
+extern struct fs_ops efi_fsops;
+
/* this is in startup code */
extern void delay(int);
extern void reboot(void);
diff --git a/sys/boot/efi/libefi/efifs.c b/sys/boot/efi/libefi/efifs.c
new file mode 100644
index 0000000..6bd2452
--- /dev/null
+++ b/sys/boot/efi/libefi/efifs.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 2001 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <stddef.h>
+#include <stand.h>
+#include <stdarg.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include "efiboot.h"
+
+static int
+efifs_open(const char *upath, struct open_file *f)
+{
+ struct efi_devdesc *dev = f->f_devdata;
+ static EFI_GUID sfsid = SIMPLE_FILE_SYSTEM_PROTOCOL;
+ EFI_FILE_IO_INTERFACE *sfs;
+ EFI_FILE *root;
+ EFI_FILE *file;
+ EFI_STATUS status;
+ CHAR16 *cp;
+ CHAR16 *path;
+
+ if (!dev->d_handle)
+ return ENOENT;
+
+ status = BS->HandleProtocol(dev->d_handle, &sfsid, (VOID **)&sfs);
+ if (EFI_ERROR(status))
+ return ENOENT;
+
+ /*
+ * Fine the root directory.
+ */
+ status = sfs->OpenVolume(sfs, &root);
+
+ /*
+ * Convert path to CHAR16, skipping leading separators.
+ */
+ while (*upath == '/')
+ upath++;
+ if (!*upath) {
+ /* Opening the root directory, */
+ f->f_fsdata = root;
+ return 0;
+ }
+ cp = path = malloc((strlen(upath) + 1) * sizeof(CHAR16));
+ if (path == NULL)
+ return ENOMEM;
+ while (*upath) {
+ if (*upath == '/')
+ *cp = '\\';
+ else
+ *cp = *upath;
+ upath++;
+ cp++;
+ }
+ *cp++ = 0;
+
+ /*
+ * Try to open it.
+ */
+ status = root->Open(root, &file, path, EFI_FILE_MODE_READ, 0);
+ free(path);
+ if (EFI_ERROR(status)) {
+ root->Close(root);
+ return ENOENT;
+ }
+
+ root->Close(root);
+ f->f_fsdata = file;
+ return 0;
+}
+
+static int
+efifs_close(struct open_file *f)
+{
+ EFI_FILE *file = f->f_fsdata;
+
+ file->Close(file);
+ return 0;
+}
+
+static int
+efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ EFI_FILE *file = f->f_fsdata;
+ EFI_STATUS status;
+ UINTN sz = size;
+
+ status = file->Read(file, &sz, buf);
+ if (EFI_ERROR(status))
+ return EIO;
+
+ *resid = size - sz;
+ return 0;
+}
+
+static off_t
+efifs_seek(struct open_file *f, off_t offset, int where)
+{
+ EFI_FILE *file = f->f_fsdata;
+ EFI_STATUS status;
+ UINT64 base;
+ UINTN sz;
+ static EFI_GUID infoid = EFI_FILE_INFO_ID;
+ EFI_FILE_INFO info;
+
+ switch (where) {
+ case SEEK_SET:
+ base = 0;
+ break;
+
+ case SEEK_CUR:
+ status = file->GetPosition(file, &base);
+ if (EFI_ERROR(status))
+ return -1;
+ break;
+
+ case SEEK_END:
+ sz = sizeof(info);
+ status = file->GetInfo(file, &infoid, &sz, &info);
+ if (EFI_ERROR(status))
+ return -1;
+ base = info.FileSize;
+ break;
+ }
+
+ status = file->SetPosition(file, base + offset);
+ if (EFI_ERROR(status))
+ return -1;
+ file->GetPosition(file, &base);
+
+ return base;
+}
+
+static int
+efifs_stat(struct open_file *f, struct stat *sb)
+{
+ EFI_FILE *file = f->f_fsdata;
+ EFI_STATUS status;
+ char *buf;
+ UINTN sz;
+ static EFI_GUID infoid = EFI_FILE_INFO_ID;
+ EFI_FILE_INFO *info;
+
+ bzero(sb, sizeof(*sb));
+
+ buf = malloc(1024);
+ sz = 1024;
+
+ status = file->GetInfo(file, &infoid, &sz, buf);
+ if (EFI_ERROR(status)) {
+ free(buf);
+ return -1;
+ }
+
+ info = (EFI_FILE_INFO *) buf;
+
+ if (info->Attribute & EFI_FILE_READ_ONLY)
+ sb->st_mode = S_IRUSR;
+ else
+ sb->st_mode = S_IRUSR | S_IWUSR;
+ if (info->Attribute & EFI_FILE_DIRECTORY)
+ sb->st_mode |= S_IFDIR;
+ sb->st_size = info->FileSize;
+
+ free(buf);
+ return 0;
+}
+
+static int
+efifs_readdir(struct open_file *f, struct dirent *d)
+{
+ EFI_FILE *file = f->f_fsdata;
+ EFI_STATUS status;
+ char *buf;
+ UINTN sz;
+ EFI_FILE_INFO *info;
+ int i;
+
+ buf = malloc(1024);
+ sz = 1024;
+
+ status = file->Read(file, &sz, buf);
+ if (EFI_ERROR(status) || sz < offsetof(EFI_FILE_INFO, FileName))
+ return ENOENT;
+
+ info = (EFI_FILE_INFO *) buf;
+
+ d->d_fileno = 0;
+ d->d_reclen = sizeof(*d);
+ if (info->Attribute & EFI_FILE_DIRECTORY)
+ d->d_type = DT_DIR;
+ else
+ d->d_type = DT_REG;
+ d->d_namlen = ((info->Size - offsetof(EFI_FILE_INFO, FileName))
+ / sizeof(CHAR16));
+ for (i = 0; i < d->d_namlen; i++)
+ d->d_name[i] = info->FileName[i];
+ d->d_name[i] = 0;
+
+ free(buf);
+ return 0;
+}
+
+struct fs_ops efi_fsops = {
+ "fs",
+ efifs_open,
+ efifs_close,
+ efifs_read,
+ null_write,
+ efifs_seek,
+ efifs_stat,
+ efifs_readdir
+};
+
+static EFI_HANDLE *fs_handles;
+UINTN fs_handle_count;;
+
+static int
+efifs_dev_init(void)
+{
+ EFI_STATUS status;
+ UINTN sz;
+ static EFI_GUID sfsid = SIMPLE_FILE_SYSTEM_PROTOCOL;
+
+ sz = 0;
+ status = BS->LocateHandle(ByProtocol, &sfsid, 0, &sz, 0);
+ if (status != EFI_BUFFER_TOO_SMALL)
+ return ENOENT;
+ fs_handles = (EFI_HANDLE *) malloc(sz);
+ status = BS->LocateHandle(ByProtocol, &sfsid, 0,
+ &sz, fs_handles);
+ if (EFI_ERROR(status)) {
+ free(fs_handles);
+ return ENOENT;
+ }
+ fs_handle_count = sz / sizeof(EFI_HANDLE);
+
+ return 0;
+}
+
+/*
+ * Print information about disks
+ */
+static void
+efifs_dev_print(int verbose)
+{
+ int i;
+ char line[80];
+
+ for (i = 0; i < fs_handle_count; i++) {
+ sprintf(line, " fs%d: EFI filesystem", i);
+ pager_output(line);
+ /* XXX more detail? */
+ pager_output("\n");
+ }
+}
+
+/*
+ * Attempt to open the disk described by (dev) for use by (f).
+ *
+ * Note that the philosophy here is "give them exactly what
+ * they ask for". This is necessary because being too "smart"
+ * about what the user might want leads to complications.
+ * (eg. given no slice or partition value, with a disk that is
+ * sliced - are they after the first BSD slice, or the DOS
+ * slice before it?)
+ */
+static int
+efifs_dev_open(struct open_file *f, ...)
+{
+ va_list args;
+ struct efi_devdesc *dev;
+ int unit;
+
+ va_start(args, f);
+ dev = va_arg(args, struct efi_devdesc*);
+ va_end(args);
+
+ unit = dev->d_kind.efidisk.unit;
+ if (unit < 0 || unit >= fs_handle_count) {
+ printf("attempt to open nonexistent EFI filesystem\n");
+ return(ENXIO);
+ }
+
+ dev->d_handle = fs_handles[unit];
+
+ return 0;
+}
+
+static int
+efifs_dev_close(struct open_file *f)
+{
+
+ return 0;
+}
+
+static int
+efifs_dev_strategy(void *devdata, int rw, daddr_t dblk, size_t size, char *buf, size_t *rsize)
+{
+ return 0;
+}
+
+struct devsw efifs_dev = {
+ "fs",
+ DEVT_DISK,
+ efifs_dev_init,
+ efifs_dev_strategy,
+ efifs_dev_open,
+ efifs_dev_close,
+ noioctl,
+ efifs_dev_print
+};
OpenPOWER on IntegriCloud