aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@linux.intel.com>2011-06-27 12:18:33 +0100
committerMatt Fleming <matt.fleming@linux.intel.com>2011-07-28 12:21:29 +0100
commit93ecef34e72cf6008cadbee0c499bdcfbec60e8d (patch)
treeb91c214e0e7330a913d4289a422e87ed4a9d8e69
parente86f71fe1a230b4e43c6ee43f9697fb8daa46eef (diff)
downloadefilinux-93ecef34e72cf6008cadbee0c499bdcfbec60e8d.tar.gz
efilinux: File support
Files are managed via 'struct file', which allows us to hide the details necessary for accessing the file via the firmware, e.g. all the handles. Signed-off-by: Matt Fleming <matt.fleming@linux.intel.com>
-rw-r--r--Makefile7
-rw-r--r--entry.c6
-rw-r--r--fs/fs.c208
-rw-r--r--fs/fs.h109
-rw-r--r--protocol.h71
5 files changed, 398 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index ae787f6..47985dc 100644
--- a/Makefile
+++ b/Makefile
@@ -53,18 +53,19 @@ LDSCRIPT=$(LIBDIR)/gnuefi/elf_$(ARCH)_efi.lds
CFLAGS=-I. -I/usr/include/efi -I/usr/include/efi/$(ARCH) \
-DEFI_FUNCTION_WRAPPER -fPIC -fshort-wchar -ffreestanding \
- -Wall
+ -Wall -Ifs/
LDFLAGS=-T $(LDSCRIPT) -Bsymbolic -shared -nostdlib -L$(LIBDIR) $(CRT0)
IMAGE=efilinux.efi
OBJS = entry.o malloc.o
+FS = fs/fs.o
all: $(IMAGE)
efilinux.efi: efilinux.so
-efilinux.so: $(OBJS)
+efilinux.so: $(OBJS) $(FS)
$(LD) $(LDFLAGS) -o $@ $^ -lgnuefi -lefi $(shell $(CC) -print-libgcc-file-name)
clean:
- rm -f $(IMAGE) efilinux.so $(OBJS)
+ rm -f $(IMAGE) efilinux.so $(OBJS) $(FS)
diff --git a/entry.c b/entry.c
index cdb7221..4f9cacf 100644
--- a/entry.c
+++ b/entry.c
@@ -32,7 +32,9 @@
*/
#include <efi.h>
+#include <efilib.h>
#include "efilinux.h"
+#include "fs.h"
#define ERROR_STRING_LENGTH 32
@@ -171,6 +173,10 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *_table)
if (err != EFI_SUCCESS)
goto failed;
+ err = fs_init();
+ if (err != EFI_SUCCESS)
+ goto failed;
+
return EFI_SUCCESS;
failed:
diff --git a/fs/fs.c b/fs/fs.c
new file mode 100644
index 0000000..b799c00
--- /dev/null
+++ b/fs/fs.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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 <efi.h>
+#include <efilib.h>
+#include "efilinux.h"
+#include "fs.h"
+#include "stdlib.h"
+#include "protocol.h"
+
+struct fs_device {
+ EFI_HANDLE handle;
+ EFI_FILE_HANDLE fh;
+ struct fs_ops *ops;
+};
+
+static struct fs_device *fs_devices;
+static UINTN nr_fs_devices;
+
+/**
+ * file_open - Open a file on a volume
+ * @name: pathname of the file to open
+ * @file: used to return a pointer to the allocated file on success
+ */
+EFI_STATUS
+file_open(CHAR16 *name, struct file **file)
+{
+ EFI_FILE_HANDLE fh;
+ struct file *f;
+ CHAR16 *filename;
+ EFI_STATUS err;
+ int dev_len;
+ int i;
+
+ f = malloc(sizeof(*f));
+ if (!f)
+ return EFI_OUT_OF_RESOURCES;
+
+ for (i = 0; i < nr_fs_devices; i++) {
+ EFI_DEVICE_PATH *path;
+ CHAR16 *dev;
+
+ path = DevicePathFromHandle(fs_devices[i].handle);
+ dev = DevicePathToStr(path);
+
+ if (!StrnCmp(dev, name, StrLen(dev))) {
+ f->handle = fs_devices[i].fh;
+ dev_len = StrLen(dev);
+ free_pool(dev);
+ break;
+ }
+
+ free_pool(dev);
+ }
+
+ if (i == nr_fs_devices) {
+ err = EFI_NOT_FOUND;
+ goto fail;
+ }
+
+ /* Strip the device name */
+ filename = name + dev_len;
+
+ /* skip any path separators */
+ while (*filename == ':' || *filename == '\\')
+ filename++;
+
+ err = uefi_call_wrapper(f->handle->Open, 5, f->handle, &fh,
+ filename, EFI_FILE_MODE_READ, (UINT64)0);
+ if (err != EFI_SUCCESS)
+ goto fail;
+
+ f->fh = fh;
+ *file = f;
+
+ return err;
+fail:
+ Print(L"Unable to open file \"%s\"", name);
+ free(f);
+ return err;
+}
+
+/**
+ * file_close - Close a file handle
+ * @f: the file to close
+ */
+EFI_STATUS
+file_close(struct file *f)
+{
+ UINTN err;
+
+ err = uefi_call_wrapper(f->handle->Close, 1, f->fh);
+
+ if (err == EFI_SUCCESS)
+ free(f);
+
+ return err;
+}
+
+/**
+ * list_boot_devices - Print a list of all disks with filesystems
+ */
+void list_boot_devices(void)
+{
+ int i;
+
+ Print(L"Devices:\n\n");
+
+ for (i = 0; i < nr_fs_devices; i++) {
+ EFI_DEVICE_PATH *path;
+ EFI_HANDLE dev_handle;
+ CHAR16 *dev;
+
+ dev_handle = fs_devices[i].handle;
+
+ path = DevicePathFromHandle(dev_handle);
+ dev = DevicePathToStr(path);
+
+ Print(L"\t%d. \"%s\"\n", i, dev);
+ free_pool(dev);
+ }
+
+ Print(L"\n");
+}
+
+/*
+ * Initialise filesystem protocol.
+ */
+EFI_STATUS
+fs_init(void)
+{
+ EFI_STATUS err;
+ UINTN size = 0;
+ int i;
+
+ size = 0;
+ err = locate_handle(ByProtocol, &FileSystemProtocol,
+ NULL, &size, NULL);
+
+ if (err != EFI_SUCCESS && size == 0) {
+ Print(L"No devices support filesystems\n");
+ goto out;
+ }
+
+ nr_fs_devices = size / sizeof(EFI_HANDLE);
+ fs_devices = malloc(sizeof(*fs_devices) * nr_fs_devices);
+ if (!fs_devices)
+ goto out;
+
+ err = locate_handle(ByProtocol, &FileSystemProtocol,
+ NULL, &size, (void **)fs_devices);
+
+ for (i = 0; i < nr_fs_devices; i++) {
+ EFI_FILE_IO_INTERFACE *io;
+ EFI_FILE_HANDLE fh;
+ EFI_HANDLE dev_handle;
+
+ dev_handle = fs_devices[i].handle;
+ err = handle_protocol(dev_handle, &FileSystemProtocol,
+ (void **)&io);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ err = volume_open(io, &fh);
+ if (err != EFI_SUCCESS)
+ goto out;
+
+ fs_devices[i].fh = fh;
+ }
+
+out:
+ return err;
+}
+
+void fs_exit(void)
+{
+ free(fs_devices);
+}
diff --git a/fs/fs.h b/fs/fs.h
new file mode 100644
index 0000000..3f66809
--- /dev/null
+++ b/fs/fs.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2011, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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.
+ *
+ */
+
+#ifndef __FS_H__
+#define __FS_H__
+
+#define MAX_FILENAME 256
+
+struct file {
+ EFI_FILE_HANDLE handle;
+ EFI_FILE_HANDLE fh;
+};
+
+/**
+ * volume_open - Open the root directory on a volume
+ * @vol: the volume to open
+ * @fh: place to return the open file handle for the root directory
+ */
+static inline EFI_STATUS
+volume_open(EFI_FILE_IO_INTERFACE *vol, EFI_FILE_HANDLE *fh)
+{
+ return uefi_call_wrapper(vol->OpenVolume, 2, vol, fh);
+}
+
+/**
+ * file_read - Read from an open file
+ * @f: the file to read
+ * @size: size in bytes to read from @f
+ * @buf: place to store the data read
+ */
+static inline EFI_STATUS
+file_read(struct file *f, UINTN *size, void *buf)
+{
+ return uefi_call_wrapper(f->handle->Read, 3, f->fh, size, buf);
+}
+
+/**
+ * file_set_position - Set the current offset of a file
+ * @f: the file on which we're changing current file position
+ * @pos: the file offset to set the current position to
+ */
+static inline EFI_STATUS
+file_set_position(struct file *f, UINT64 pos)
+{
+ return uefi_call_wrapper(f->fh->SetPosition, 2, f->fh, pos);
+}
+
+/**
+ * file_size - Get the size (in bytes) of @file
+ * @f: the file to query
+ * @size: where to store the size of the file
+ */
+static inline EFI_STATUS
+file_size(struct file *f, UINT64 *size)
+{
+ EFI_FILE_INFO *info;
+
+ info = LibFileInfo(f->fh);
+
+ if (!info)
+ return EFI_UNSUPPORTED;
+
+ *size = info->FileSize;
+
+ free_pool(info);
+
+ return EFI_SUCCESS;
+}
+
+extern EFI_STATUS file_open(CHAR16 *name, struct file **file);
+extern EFI_STATUS file_close(struct file *f);
+
+extern void list_boot_devices(void);
+
+extern EFI_STATUS fs_init(void);
+extern void fs_exit(void);
+
+#endif /* __FS_H__ */
diff --git a/protocol.h b/protocol.h
new file mode 100644
index 0000000..6881d70
--- /dev/null
+++ b/protocol.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2011, Intel Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products
+ * derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT OWNER 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.
+ */
+
+#ifndef __PROTOCOL_H__
+#define __PROTOCOL_H__
+
+/**
+ * handle_protocol - Query @handle to see if it supports @protocol
+ * @handle: the handle being queried
+ * @protocol: the GUID of the protocol
+ * @interface: used to return the protocol interface
+ *
+ * Query @handle to see if @protocol is supported. If it is supported,
+ * @interface contains the protocol interface.
+ */
+static inline EFI_STATUS
+handle_protocol(EFI_HANDLE handle, EFI_GUID *protocol, void **interface)
+{
+ return uefi_call_wrapper(boot->HandleProtocol, 3,
+ handle, protocol, interface);
+}
+
+/**
+ * locate_handle - Search for handles that support @protocol
+ * @type: the search type, which handles are returned
+ * @protocol: the protocol to search by (only valid if @type is ByProtocol)
+ * @key: the search key
+ * @size: on input the size in bytes of @buffer, on output the size of
+ * the returned array or the required size to store the array
+ * in @buffer if it was not large enough
+ * @buffer: buffere where the array of handles is returned
+ */
+static inline EFI_STATUS
+locate_handle(EFI_LOCATE_SEARCH_TYPE type, EFI_GUID *protocol, void *key,
+ UINTN *size, EFI_HANDLE *buffer)
+{
+ return uefi_call_wrapper(boot->LocateHandle, 5, type, protocol,
+ key, size, buffer);
+}
+
+#endif /* __PROTOCOL_H__ */