Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 15 Feb 2014 14:30:20 +0000 (UTC)
From:      Andrew Turner <andrew@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r261923 - projects/arm64/sys/boot/efi/libefi
Message-ID:  <201402151430.s1FEUKae045359@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: andrew
Date: Sat Feb 15 14:30:19 2014
New Revision: 261923
URL: http://svnweb.freebsd.org/changeset/base/261923

Log:
  Add a filesystem to read using the EFI Simple Filesystem Protocol.

Added:
  projects/arm64/sys/boot/efi/libefi/efisimplefs.c   (contents, props changed)
Modified:
  projects/arm64/sys/boot/efi/libefi/Makefile

Modified: projects/arm64/sys/boot/efi/libefi/Makefile
==============================================================================
--- projects/arm64/sys/boot/efi/libefi/Makefile	Sat Feb 15 13:27:45 2014	(r261922)
+++ projects/arm64/sys/boot/efi/libefi/Makefile	Sat Feb 15 14:30:19 2014	(r261923)
@@ -3,8 +3,8 @@
 LIB=	efi
 INTERNALLIB=
 
-SRCS=	delay.c efi_console.c efinet.c efipart.c errno.c handles.c \
-	libefi.c time.c
+SRCS=	delay.c efi_console.c efinet.c efipart.c efisimplefs.c errno.c \
+	handles.c libefi.c time.c
 
 CFLAGS+= -I${.CURDIR}/../include
 CFLAGS+= -I${.CURDIR}/../include/${MACHINE_CPUARCH:S/amd64/i386/}

Added: projects/arm64/sys/boot/efi/libefi/efisimplefs.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/arm64/sys/boot/efi/libefi/efisimplefs.c	Sat Feb 15 14:30:19 2014	(r261923)
@@ -0,0 +1,386 @@
+/*-
+ * Copyright (c) 2014 Andrew Turner
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <stdarg.h>
+
+#include <stand.h>
+
+#include <bootstrap.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <efiprot.h>
+
+static EFI_GUID sfs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL;
+static EFI_GUID file_info_guid = EFI_FILE_INFO_ID;
+
+static int efifs_open(const char *path, struct open_file *f);
+static int efifs_write(struct open_file *f, void *buf, size_t size,
+    size_t *resid);
+static int efifs_close(struct open_file *f);
+static int efifs_read(struct open_file *f, void *buf, size_t size,
+    size_t *resid);
+static off_t efifs_seek(struct open_file *f, off_t offset, int where);
+static int efifs_stat(struct open_file *f, struct stat *sb);
+static int efifs_readdir(struct open_file *f, struct dirent *d);
+
+struct fs_ops efifs_fsops = {
+	"efifs",
+	efifs_open,
+	efifs_close,
+	efifs_read,
+	efifs_write,
+	efifs_seek,
+	efifs_stat,
+	efifs_readdir
+};
+
+static CHAR16 *
+path_to_filename(const char *path)
+{
+	CHAR16 *filename;
+	size_t len;
+	int i;
+
+	len = strlen(path) + 1;
+	filename = malloc(len * 2);
+	if (filename == NULL)
+		return (NULL);
+
+	for (i = 0; i < len; i++) {
+		if (path[i] == '/')
+			filename[i] = L'\\';
+		else
+			filename[i] = path[i];
+	}
+
+	return filename;
+}
+
+static int
+efifs_open(const char *path, struct open_file *f)
+{
+	EFI_FILE *dev, *file;
+	EFI_STATUS status;
+	struct devdesc *devdesc;
+	CHAR16 *filename;
+
+	devdesc = (struct devdesc *)(f->f_devdata);
+	if (devdesc->d_opendata == NULL)
+		return (EINVAL);
+
+	if (f->f_dev != &efisfs_dev)
+		return (EINVAL);
+
+	dev = devdesc->d_opendata;
+
+	filename = path_to_filename(path);
+	if (filename == NULL)
+		return (ENOMEM);
+
+	status = dev->Open(dev, &file, filename, EFI_FILE_MODE_READ, 0);
+	free(filename);
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	f->f_fsdata = file;
+
+	return (0);
+}
+
+static int
+efifs_close(struct open_file *f)
+{
+	EFI_STATUS status;
+	EFI_FILE *file;
+
+	file = f->f_fsdata;
+	if (file == NULL)
+		return (EINVAL);
+
+	status = file->Close(file);
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	return (0);
+}
+
+static int
+efifs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+	EFI_STATUS status;
+	EFI_FILE *file;
+	size_t read_size;
+
+	file = f->f_fsdata;
+	if (file == NULL)
+		return (EINVAL);
+
+	read_size = size;
+	status = file->Read(file, &read_size, buf);
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	if (resid != NULL)
+		*resid = (size - read_size);
+
+	return (0);
+}
+
+static int
+efifs_write(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+	printf("efifs_write\n");
+
+	return (EINVAL);
+}
+
+static off_t
+efifs_seek(struct open_file *f, off_t offset, int where)
+{
+	printf("efifs_seek\n");
+
+	return (EINVAL);
+}
+
+static int
+efifs_stat(struct open_file *f, struct stat *sb)
+{
+	EFI_FILE_INFO *info;
+	EFI_STATUS status;
+	EFI_FILE *file;
+	UINTN infosz;
+
+	file = f->f_fsdata;
+	if (file == NULL)
+		return (EINVAL);
+
+	infosz = sizeof(EFI_FILE_INFO);
+	info = malloc(infosz);
+	if (info == NULL)
+		return (ENOMEM);
+
+	status = file->GetInfo(file, &file_info_guid, &infosz, info);
+	/* Resize the buffer and try again if required */
+	if (status == EFI_BUFFER_TOO_SMALL) {
+		EFI_FILE_INFO *tmp;
+
+		tmp = realloc(info, infosz);
+		if (info == NULL) {
+			free(info);
+			return (ENOMEM);
+		}
+		info = tmp;
+		status = file->GetInfo(file, &file_info_guid, &infosz, info);
+	}
+
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	bzero(sb, sizeof(*sb));
+
+	sb->st_size = info->FileSize;
+	sb->st_mode = S_IRUSR;
+	if (info->FileName[0] == 0)
+		sb->st_mode = S_IFDIR;
+	else
+		sb->st_mode |=
+		    (info->Attribute & EFI_FILE_DIRECTORY) ? S_IFDIR : S_IFREG;
+
+	return (0);
+}
+
+static int
+efifs_readdir(struct open_file *f, struct dirent *d)
+{
+	EFI_FILE_INFO *cur_file;
+	EFI_STATUS status;
+	EFI_FILE *file;
+	UINTN filesz;
+	int i;
+
+	file = f->f_fsdata;
+	if (file == NULL)
+		return (EINVAL);
+
+	filesz = sizeof(*cur_file) + sizeof(d->d_name) * 2;
+	cur_file = malloc(filesz);
+	if (cur_file == NULL)
+		return (ENOMEM);
+
+	bzero(cur_file, filesz);
+
+	status = file->Read(file, &filesz, cur_file);
+	if (EFI_ERROR(status)) {
+		free(cur_file);
+		return (efi_status_to_errno(status));
+	}
+
+	if (filesz == 0) {
+		free(cur_file);
+		return (ENOENT);
+	}
+
+	bzero(d, sizeof(*d));
+
+	for (i = 0; i < sizeof(d->d_name); i++) {
+		d->d_name[i] = cur_file->FileName[i];
+		if (cur_file->FileName[i] == L'\0')
+			break;
+	}
+
+	free(cur_file);
+
+	return (0);
+}
+
+
+static int efisfs_init(void);
+static int efisfs_strategy(void *, int, daddr_t, size_t, char *, size_t *);
+static int efisfs_open(struct open_file *, ...);
+static int efisfs_close(struct open_file *);
+static void efisfs_print(int);
+
+struct devsw efisfs_dev = {
+	.dv_name = "simplefs",
+	.dv_type = DEVT_FS,
+	.dv_init = efisfs_init,
+	.dv_strategy = efisfs_strategy,
+	.dv_open = efisfs_open,
+	.dv_close = efisfs_close,
+	.dv_ioctl = noioctl,
+	.dv_print = efisfs_print,
+	.dv_cleanup = NULL
+};
+
+static int
+efisfs_init(void)
+{
+	EFI_FILE_IO_INTERFACE *fsio;
+	EFI_HANDLE *hin, *hout;
+	EFI_STATUS status;
+	UINTN sz;
+	u_int n, nin, nout;
+	int err;
+
+	sz = 0;
+	hin = NULL;
+	status = BS->LocateHandle(ByProtocol, &sfs_guid, 0, &sz, 0);
+	if (status == EFI_BUFFER_TOO_SMALL) {
+		hin = (EFI_HANDLE *)malloc(sz * 2);
+		status = BS->LocateHandle(ByProtocol, &sfs_guid, 0, &sz,
+		    hin);
+		if (EFI_ERROR(status))
+			free(hin);
+	}
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	/* Filter handles to only include FreeBSD partitions. */
+	nin = sz / sizeof(EFI_HANDLE);
+	hout = hin + nin;
+	nout = 0;
+
+	for (n = 0; n < nin; n++) {
+		status = BS->HandleProtocol(hin[n], &sfs_guid, &fsio);
+		if (EFI_ERROR(status))
+			continue;
+		if(fsio->Revision != EFI_FILE_IO_INTERFACE_REVISION)
+			continue;
+		hout[nout] = hin[n];
+		nout++;
+	}
+
+	err = efi_register_handles(&efisfs_dev, hout, nout);
+	free(hin);
+	return (err);
+}
+
+static int
+efisfs_strategy(void *devdata, int rw, daddr_t blk, size_t size, char *buf,
+    size_t *rsize)
+{
+	printf("efisfs_strategy\n");
+
+	return (ENXIO);
+}
+
+static int
+efisfs_open(struct open_file *f, ...)
+{
+	va_list args;
+	struct devdesc *dev;
+	EFI_FILE_IO_INTERFACE *fsio;
+	EFI_FILE *fileio;
+	EFI_HANDLE h;
+	EFI_STATUS status;
+
+	va_start(args, f);
+	dev = va_arg(args, struct devdesc*);
+	va_end(args);
+
+	h = efi_find_handle(&efisfs_dev, dev->d_unit);
+	if (h == NULL)
+		return (EINVAL);
+
+	status = BS->HandleProtocol(h, &sfs_guid, &fsio);
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	if(fsio->Revision != EFI_FILE_IO_INTERFACE_REVISION)
+		return (EAGAIN);
+
+	status = fsio->OpenVolume(fsio, &fileio);
+	if (EFI_ERROR(status))
+		return (efi_status_to_errno(status));
+
+	dev->d_opendata = fileio;
+	return (0);
+}
+
+static int
+efisfs_close(struct open_file *f)
+{
+	struct devdesc *dev;
+
+	dev = (struct devdesc *)(f->f_devdata);
+	if (dev->d_opendata == NULL)
+		return (EINVAL);
+
+	dev->d_opendata = NULL;
+	return (0);
+}
+
+static void
+efisfs_print(int verbose)
+{
+	printf("efisfs_print\n");
+}
+



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201402151430.s1FEUKae045359>