All of lore.kernel.org
 help / color / mirror / Atom feed
From: Rob Clark <robdclark@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v0 16/20] efi_loader: add file/filesys support
Date: Fri,  4 Aug 2017 15:31:58 -0400	[thread overview]
Message-ID: <20170804193205.24669-17-robdclark@gmail.com> (raw)
In-Reply-To: <20170804193205.24669-1-robdclark@gmail.com>

fallback.efi (and probably other things) use UEFI's simple-file-system
protocol and file support to search for OS's to boot.

Signed-off-by: Rob Clark <robdclark@gmail.com>
---
 fs/fs.c                           |  21 ++
 include/efi.h                     |   2 +
 include/efi_api.h                 |  65 ++++++
 include/efi_loader.h              |  13 ++
 include/fs.h                      |   2 +
 lib/efi_loader/Makefile           |   1 +
 lib/efi_loader/efi_disk.c         |  51 +++++
 lib/efi_loader/efi_file.c         | 468 ++++++++++++++++++++++++++++++++++++++
 lib/efi_loader/efi_image_loader.c |   3 +
 9 files changed, 626 insertions(+)
 create mode 100644 lib/efi_loader/efi_file.c

diff --git a/fs/fs.c b/fs/fs.c
index 42a028a6ce..a269619b51 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -247,6 +247,27 @@ int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype)
 	return -1;
 }
 
+/* set current blk device w/ blk_desc + partition # */
+int fs_set_blk_dev2(struct blk_desc *desc, int part)
+{
+	struct fstype_info *info;
+	int ret, i;
+
+	ret = part_get_info(desc, part, &fs_partition);
+	if (ret)
+		return ret;
+	fs_dev_desc = desc;
+
+	for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) {
+		if (!info->probe(fs_dev_desc, &fs_partition)) {
+			fs_type = info->fstype;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
 static void fs_close(void)
 {
 	struct fstype_info *info = fs_get_info(fs_type);
diff --git a/include/efi.h b/include/efi.h
index 87b0b43f20..ddd2b96417 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -81,6 +81,8 @@ typedef struct {
 #define EFI_IP_ADDRESS_CONFLICT		(EFI_ERROR_MASK | 34)
 #define EFI_HTTP_ERROR			(EFI_ERROR_MASK | 35)
 
+#define EFI_WARN_DELETE_FAILURE	2
+
 typedef unsigned long efi_status_t;
 typedef u64 efi_physical_addr_t;
 typedef u64 efi_virtual_addr_t;
diff --git a/include/efi_api.h b/include/efi_api.h
index dd79cace32..1a542846b3 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -657,4 +657,69 @@ struct efi_pxe {
 	struct efi_pxe_mode *mode;
 };
 
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
+	EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
+		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_FILE_PROTOCOL_REVISION 0x00010000
+
+struct efi_file_handle {
+	u64 rev;
+	efi_status_t (EFIAPI *open)(struct efi_file_handle *file,
+			struct efi_file_handle **new_handle,
+			s16 *file_name, u64 open_mode, u64 attributes);
+	efi_status_t (EFIAPI *close)(struct efi_file_handle *file);
+	efi_status_t (EFIAPI *delete)(struct efi_file_handle *file);
+	efi_status_t (EFIAPI *read)(struct efi_file_handle *file,
+			u64 *buffer_size, void *buffer);
+	efi_status_t (EFIAPI *write)(struct efi_file_handle *file,
+			u64 *buffer_size, void *buffer);
+	efi_status_t (EFIAPI *getpos)(struct efi_file_handle *file,
+			u64 *pos);
+	efi_status_t (EFIAPI *setpos)(struct efi_file_handle *file,
+			u64 pos);
+	efi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file,
+			efi_guid_t *info_type, u64 *buffer_size, void *buffer);
+	efi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file,
+			efi_guid_t *info_type, u64 buffer_size, void *buffer);
+	efi_status_t (EFIAPI *flush)(struct efi_file_handle *file);
+};
+
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \
+	EFI_GUID(0x964e5b22, 0x6459, 0x11d2, \
+		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000
+
+struct efi_simple_file_system_protocol {
+	u64 rev;
+	efi_status_t (EFIAPI *open_volume)(struct efi_simple_file_system_protocol *this,
+			struct efi_file_handle **root);
+};
+
+#define EFI_FILE_INFO_GUID \
+	EFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \
+		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+#define EFI_FILE_MODE_READ	0x0000000000000001
+#define EFI_FILE_MODE_WRITE	0x0000000000000002
+#define EFI_FILE_MODE_CREATE	0x8000000000000000
+
+#define EFI_FILE_READ_ONLY	0x0000000000000001
+#define EFI_FILE_HIDDEN		0x0000000000000002
+#define EFI_FILE_SYSTEM		0x0000000000000004
+#define EFI_FILE_RESERVED	0x0000000000000008
+#define EFI_FILE_DIRECTORY	0x0000000000000010
+#define EFI_FILE_ARCHIVE	0x0000000000000020
+#define EFI_FILE_VALID_ATTR	0x0000000000000037
+
+struct efi_file_info {
+	u64 size;
+	u64 file_size;
+	u64 physical_size;
+	struct efi_time create_time;
+	struct efi_time last_access_time;
+	struct efi_time modification_time;
+	u64 attribute;
+	s16 file_name[0];
+};
+
 #endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 479fb6b63d..4210d5f19a 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -65,6 +65,8 @@ extern const efi_guid_t efi_guid_console_control;
 extern const efi_guid_t efi_guid_device_path;
 extern const efi_guid_t efi_guid_loaded_image;
 extern const efi_guid_t efi_guid_device_path_to_text_protocol;
+extern const efi_guid_t efi_simple_file_system_protocol_guid;
+extern const efi_guid_t efi_file_info_guid;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
@@ -147,6 +149,9 @@ int efi_net_register(void);
 /* Called by bootefi to make SMBIOS tables available */
 void efi_smbios_register(void);
 
+struct efi_simple_file_system_protocol *
+efi_fs_from_path(struct efi_device_path *fp);
+
 /* Called by networking code to memorize the dhcp ack package */
 void efi_net_set_dhcp_ack(void *pkt, int len);
 
@@ -175,6 +180,14 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,
 /* Call this to signal an event */
 void efi_signal_event(struct efi_event *event);
 
+/* open file system: */
+struct efi_simple_file_system_protocol * efi_simple_file_system(
+		struct blk_desc *desc, int part, struct efi_device_path *dp);
+
+/* open file from device-path: */
+struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);
+
+
 /* Generic EFI memory allocator, call this to get memory */
 void *efi_alloc(uint64_t len, int memory_type);
 /* More specific EFI memory allocator, called by EFI payloads */
diff --git a/include/fs.h b/include/fs.h
index 71051d7c66..7e920916e3 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -26,6 +26,8 @@
  */
 int fs_set_blk_dev(const char *ifname, const char *dev_part_str, int fstype);
 
+int fs_set_blk_dev2(struct blk_desc *desc, int part);
+
 /*
  * Print the list of files on the partition previously set by fs_set_blk_dev(),
  * in directory "dirname".
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index f35e5ce8a8..cce92cfeb5 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -16,6 +16,7 @@ always := $(efiprogs-y)
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
 obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
 obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
+obj-y += efi_file.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index eea65a402a..f7565ad937 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -31,6 +31,8 @@ struct efi_disk_obj {
 	struct efi_device_path *dp;
 	/* partition # */
 	unsigned part;
+	/* handle to filesys proto (for partition objects) */
+	struct efi_simple_file_system_protocol *volume;
 	/* Offset into disk for simple partitions */
 	lbaint_t offset;
 	/* Internal block device */
@@ -172,6 +174,49 @@ static const struct efi_block_io block_io_disk_template = {
 	.flush_blocks = &efi_disk_flush_blocks,
 };
 
+static efi_status_t EFIAPI efi_disk_open_fs(void *handle,
+					    const efi_guid_t *protocol,
+					    void **protocol_interface)
+{
+	struct efi_disk_obj *diskobj = handle;
+
+	if (!diskobj->volume) {
+		diskobj->volume =
+			efi_simple_file_system(diskobj->desc,
+					       diskobj->part,
+					       diskobj->dp);
+	}
+
+	*protocol_interface = diskobj->volume;
+
+	return EFI_SUCCESS;
+}
+
+/*
+ * Find filesystem from a device-path.  The passed in path 'p' probably
+ * contains one or more /File(name) nodes, so the comparison stops at
+ * the first /File() node, and returns the pointer to that via 'rp'.
+ * This is mostly intended to be a helper to map a device-path to an
+ * efi_file_handle object.
+ */
+struct efi_simple_file_system_protocol *
+efi_fs_from_path(struct efi_device_path *fp)
+{
+	struct efi_simple_file_system_protocol *volume;
+	struct efi_object *efiobj;
+	struct efi_disk_obj *diskobj;
+
+	efiobj = efi_dp_find_obj(fp);
+	if (!efiobj)
+		return NULL;
+
+	diskobj = container_of(efiobj, struct efi_disk_obj, parent);
+
+	efi_disk_open_fs(diskobj, NULL, (void **)&volume);
+
+	return volume;
+}
+
 static void efi_disk_add_dev(const char *name,
 			     const char *if_typename,
 			     struct blk_desc *desc,
@@ -194,6 +239,12 @@ static void efi_disk_add_dev(const char *name,
 	diskobj->parent.protocols[0].protocol_interface = &diskobj->ops;
 	diskobj->parent.protocols[1].guid = &efi_guid_device_path;
 	diskobj->parent.protocols[1].protocol_interface = diskobj->dp;
+	if (part >= 1) {
+		diskobj->parent.protocols[2].guid =
+			&efi_simple_file_system_protocol_guid;
+		diskobj->parent.protocols[2].open =
+			efi_disk_open_fs;
+	}
 	diskobj->parent.handle = diskobj;
 	diskobj->ops = block_io_disk_template;
 	diskobj->ifname = if_typename;
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
new file mode 100644
index 0000000000..7bdd16c649
--- /dev/null
+++ b/lib/efi_loader/efi_file.c
@@ -0,0 +1,468 @@
+/*
+ *  EFI utils
+ *
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <efi_loader.h>
+#include <malloc.h>
+#include <fs.h>
+
+struct file_system {
+	struct efi_simple_file_system_protocol base;
+	struct efi_device_path *dp;
+	struct blk_desc *desc;
+	int part;
+};
+#define to_fs(x) container_of(x, struct file_system, base)
+
+struct file_handle {
+	struct efi_file_handle base;
+	struct file_system *fs;
+	loff_t offset;       /* current file position/cursor */
+	int isdir;
+	char path[0];
+};
+#define to_fh(x) container_of(x, struct file_handle, base)
+
+static const struct efi_file_handle efi_file_handle_protocol;
+
+static char *basename(struct file_handle *fh)
+{
+	char *s = strrchr(fh->path, '/');
+	if (s)
+		return s + 1;
+	return fh->path;
+}
+
+static int set_blk_dev(struct file_handle *fh)
+{
+	return fs_set_blk_dev2(fh->fs->desc, fh->fs->part);
+}
+
+static int is_dir(struct file_handle *fh, const char *filename)
+{
+	char buf[256];
+	struct fs_dirent d;
+	const char *path;
+	int ret;
+
+	if (!filename) {
+		path = fh->path;
+	} else {
+		ret = snprintf(buf, sizeof(buf), "%s/%s",
+				fh->path, filename);
+		if (ret >= sizeof(buf))
+			return 0;
+		path = buf;
+	}
+
+	set_blk_dev(fh);
+	ret = fs_readdir(path, 0, &d);
+	if (ret == -ENOTDIR) {
+		return 0;
+	} else if (ret == -ENXIO) {
+		debug("WARNING: cannot read directories!\n");
+		/*
+		 * We don't know, assume regular file, but if
+		 * the EFI app tries to read a directory, it
+		 * won't work properly.  This will be a problem
+		 * for fallback.efi as it searches /EFI/ for
+		 * OS installations.  Too bad.
+		 */
+		return 0;
+	} else {
+		return 1;
+	}
+}
+
+/* NOTE: despite what you would expect, 'file_name' is actually a path.
+ * With windoze style backlashes, ofc.
+ */
+static struct efi_file_handle *file_open(struct file_system *fs,
+		struct file_handle *parent, s16 *file_name)
+{
+	struct file_handle *fh;
+	char f0[MAX_UTF8_PER_UTF16] = {0};
+	int plen = 0;
+	int flen = 0;
+
+	if (file_name)
+		utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1);
+
+	/* we could have a parent, but also an absolute path: */
+	if (f0[0] == '\\') {
+		plen = 0;
+		flen = utf16_strlen((u16 *)file_name);
+	} else if (parent) {
+		plen = strlen(parent->path) + 1;
+		flen = utf16_strlen((u16 *)file_name);
+	}
+
+	/* +2 is for null and '/' */
+	fh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);
+
+	fh->base = efi_file_handle_protocol;
+	fh->fs = fs;
+
+	if (parent) {
+		char *p = fh->path;
+
+		if (plen > 0) {
+			strcpy(p, parent->path);
+			p += plen - 1;
+			*p++ = '/';
+		}
+
+		utf16_to_utf8((u8 *)p, (u16 *)file_name, flen);
+
+		/* sanitize path: */
+		while ((p = strchr(p, '\\')))
+			*p++ = '/';
+
+		/* check if file exists: */
+		if (set_blk_dev(fh))
+			goto error;
+		if (!fs_exists(fh->path))
+			goto error;
+
+		/* figure out if file is a directory: */
+		fh->isdir = is_dir(fh, NULL);
+	} else {
+		fh->isdir = 1;
+		strcpy(fh->path, "");
+	}
+
+	return &fh->base;
+
+error:
+	free(fh);
+	return NULL;
+}
+
+static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,
+		struct efi_file_handle **new_handle,
+		s16 *file_name, u64 open_mode, u64 attributes)
+{
+	struct file_handle *fh = to_fh(file);
+
+	EFI_ENTRY("%p, %p, %p, %llu, %llu", file, new_handle, file_name,
+		open_mode, attributes);
+
+	*new_handle = file_open(fh->fs, fh, file_name);
+	if (!*new_handle)
+		return EFI_EXIT(EFI_NOT_FOUND);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)
+{
+	struct file_handle *fh = to_fh(file);
+	EFI_ENTRY("%p", file);
+	free(fh);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
+{
+	efi_file_close(file);
+	return EFI_WARN_DELETE_FAILURE;
+}
+
+static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
+		void *buffer)
+{
+	loff_t actread;
+
+	if (fs_read(fh->path, (ulong)buffer, fh->offset,
+			*buffer_size, &actread))
+		return EFI_DEVICE_ERROR;
+
+	*buffer_size = actread;
+	fh->offset += actread;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,
+		void *buffer)
+{
+	struct efi_file_info *info = buffer;
+	struct fs_dirent dent;
+	unsigned required_size;
+	int ret;
+
+	ret = fs_readdir(fh->path, fh->offset, &dent);
+
+	if (ret == -ENOENT) {
+		/* no more files in directory: */
+		/* workaround shim.efi bug/quirk.. as find_boot_csv()
+		 * loops through directory contents, it initially calls
+		 * read w/ zero length buffer to find out how much mem
+		 * to allocate for the EFI_FILE_INFO, then allocates,
+		 * and then calls a 2nd time.  If we return size of
+		 * zero the first time, it happily passes that to
+		 * AllocateZeroPool(), and when that returns NULL it
+		 * thinks it is EFI_OUT_OF_RESOURCES.  So on first
+		 * call return a non-zero size:
+		 */
+		if (*buffer_size == 0)
+			*buffer_size = sizeof(*info);
+		else
+			*buffer_size = 0;
+		return EFI_SUCCESS;
+	} else if (ret) {
+		return EFI_DEVICE_ERROR;
+	}
+
+	/* check buffer size: */
+	required_size = sizeof(*info) + 2 * (strlen(dent.name) + 1);
+	if (*buffer_size < required_size) {
+		*buffer_size = required_size;
+		return EFI_BUFFER_TOO_SMALL;
+	}
+
+	*buffer_size = required_size;
+	memset(info, 0, required_size);
+
+	info->size = required_size;
+	info->file_size = dent.size;
+	info->physical_size = dent.size;
+
+	if (is_dir(fh, dent.name))
+		info->attribute |= EFI_FILE_DIRECTORY;
+
+	ascii2unicode((u16 *)info->file_name, dent.name);
+
+	fh->offset++;
+
+	return EFI_SUCCESS;
+}
+
+static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,
+		u64 *buffer_size, void *buffer)
+{
+	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
+
+	if (set_blk_dev(fh)) {
+		ret = EFI_DEVICE_ERROR;
+		goto error;
+	}
+
+	if (fh->isdir) {
+		ret = dir_read(fh, buffer_size, buffer);
+	} else {
+		ret = file_read(fh, buffer_size, buffer);
+	}
+
+error:
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,
+		u64 *buffer_size, void *buffer)
+{
+	EFI_ENTRY("%p, %p, %p", file, buffer_size, buffer);
+	return EFI_EXIT(EFI_WRITE_PROTECTED);
+}
+
+static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file,
+		u64 *pos)
+{
+	struct file_handle *fh = to_fh(file);
+	EFI_ENTRY("%p, %p", file, pos);
+	*pos = fh->offset;
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,
+		u64 pos)
+{
+	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %llu", file, pos);
+
+	if (fh->isdir && (pos != 0)) {
+		ret = EFI_UNSUPPORTED;
+		goto error;
+	}
+
+	if (pos == ~0ULL) {
+		loff_t file_size;
+
+		if (set_blk_dev(fh)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		if (fs_size(fh->path, &file_size)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		pos = file_size;
+	}
+
+	fh->offset = pos;
+
+error:
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,
+		efi_guid_t *info_type, u64 *buffer_size, void *buffer)
+{
+	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer);
+
+	if (!guidcmp(info_type, &efi_file_info_guid)) {
+		struct efi_file_info *info = buffer;
+		char *filename = basename(fh);
+		unsigned required_size;
+		loff_t file_size;
+
+		/* check buffer size: */
+		required_size = sizeof(*info) + 2 * (strlen(filename) + 1);
+		if (*buffer_size < required_size) {
+			*buffer_size = required_size;
+			ret = EFI_BUFFER_TOO_SMALL;
+			goto error;
+		}
+
+		if (set_blk_dev(fh)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		if (fs_size(fh->path, &file_size)) {
+			ret = EFI_DEVICE_ERROR;
+			goto error;
+		}
+
+		memset(info, 0, required_size);
+
+		info->size = required_size;
+		info->file_size = file_size;
+		info->physical_size = file_size;
+
+		if (fh->isdir)
+			info->attribute |= EFI_FILE_DIRECTORY;
+
+		ascii2unicode((u16 *)info->file_name, filename);
+	} else {
+		ret = EFI_UNSUPPORTED;
+	}
+
+error:
+	return EFI_EXIT(ret);
+}
+
+static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,
+		efi_guid_t *info_type, u64 buffer_size, void *buffer)
+{
+	EFI_ENTRY("%p, %p, %llu, %p", file, info_type, buffer_size, buffer);
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)
+{
+	EFI_ENTRY("%p", file);
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+static const struct efi_file_handle efi_file_handle_protocol = {
+	.rev = EFI_FILE_PROTOCOL_REVISION,
+	.open = efi_file_open,
+	.close = efi_file_close,
+	.delete = efi_file_delete,
+	.read = efi_file_read,
+	.write = efi_file_write,
+	.getpos = efi_file_getpos,
+	.setpos = efi_file_setpos,
+	.getinfo = efi_file_getinfo,
+	.setinfo = efi_file_setinfo,
+	.flush = efi_file_flush,
+};
+
+struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)
+{
+	struct efi_simple_file_system_protocol *v;
+	struct efi_file_handle *f;
+	efi_status_t ret;
+
+	v = efi_fs_from_path(fp);
+	if (!v)
+		return NULL;
+
+	EFI_CALL(ret = v->open_volume(v, &f));
+	if (ret != EFI_SUCCESS)
+		return NULL;
+
+	/* skip over device-path nodes before the file path: */
+	while (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
+		fp = efi_dp_next(fp);
+	}
+
+	while (fp) {
+		struct efi_device_path_file_path *fdp =
+			container_of(fp, struct efi_device_path_file_path, dp);
+		struct efi_file_handle *f2;
+
+		if (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {
+			printf("bad file path!\n");
+			f->close(f);
+			return NULL;
+		}
+
+		EFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str, EFI_FILE_MODE_READ, 0));
+		if (ret != EFI_SUCCESS)
+			return NULL;
+
+		fp = efi_dp_next(fp);
+
+		EFI_CALL(f->close(f));
+		f = f2;
+	}
+
+	return f;
+}
+
+static efi_status_t EFIAPI
+efi_open_volume(struct efi_simple_file_system_protocol *this,
+		struct efi_file_handle **root)
+{
+	struct file_system *fs = to_fs(this);
+
+	EFI_ENTRY("%p, %p", this, root);
+
+	*root = file_open(fs, NULL, NULL);
+
+	return EFI_EXIT(EFI_SUCCESS);
+}
+
+struct efi_simple_file_system_protocol *
+efi_simple_file_system(struct blk_desc *desc, int part,
+		       struct efi_device_path *dp)
+{
+	struct file_system *fs;
+
+	fs = calloc(1, sizeof(*fs));
+	fs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
+	fs->base.open_volume = efi_open_volume;
+	fs->desc = desc;
+	fs->part = part;
+	fs->dp = dp;
+
+	return &fs->base;
+}
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index f961407f50..469acae082 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -17,6 +17,9 @@ DECLARE_GLOBAL_DATA_PTR;
 
 const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;
 const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;
+const efi_guid_t efi_simple_file_system_protocol_guid =
+		EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
+const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
 
 static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
 			unsigned long rel_size, void *efi_reloc)
-- 
2.13.0

  parent reply	other threads:[~2017-08-04 19:31 UTC|newest]

Thread overview: 116+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-04 19:31 [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 01/20] fs: add fs_readdir() Rob Clark
2017-08-07 18:19   ` Brüns, Stefan
2017-08-07 19:11     ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 02/20] fs/fat: implement readdir Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 03/20] short-wchar Rob Clark
2017-08-04 20:28   ` Heinrich Schuchardt
2017-08-04 20:36     ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 04/20] part: extract MBR signature from partitions Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 05/20] efi: add some more device path structures Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 06/20] common: add some utf16 handling helpers Rob Clark
2017-08-06  5:17   ` Simon Glass
2017-08-08 22:50   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
2017-08-08 23:21     ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 07/20] vsprintf.c: add wide string (%ls) support Rob Clark
2017-08-08 22:03   ` [U-Boot] [U-Boot, v0, " Heinrich Schuchardt
2017-08-08 22:44     ` Rob Clark
2017-08-08 23:08       ` Heinrich Schuchardt
2017-08-08 23:20         ` Alexander Graf
2017-08-08 23:39         ` Rob Clark
2017-08-08 23:55           ` Alexander Graf
2017-08-09  0:14             ` Rob Clark
2017-08-09  1:14               ` Rob Clark
2017-08-09 11:27               ` Tom Rini
2017-08-10  2:16                 ` rick at andestech.com
2017-08-09  8:50           ` Peter Robinson
2017-08-08 22:52     ` Rob Clark
2017-08-09 13:38     ` Rob Clark
2017-08-09 13:48       ` Alexander Graf
2017-08-09 14:35         ` Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 08/20] efi_loader: add back optional efi_handler::open() Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 09/20] efi_loader: add device-path utils Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 10/20] efi_loader: drop redundant efi_device_path_protocol Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 11/20] efi_loader: add guidstr helper Rob Clark
2017-08-05 19:33   ` Heinrich Schuchardt
2017-08-05 19:56     ` Rob Clark
2017-08-05 20:18       ` Heinrich Schuchardt
2017-08-04 19:31 ` [U-Boot] [PATCH v0 12/20] efi_loader: flesh out device-path to text Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 13/20] efi_loader: use proper device-paths for partitions Rob Clark
2017-08-04 20:41   ` Mark Kettenis
2017-08-04 20:57     ` Rob Clark
2017-08-05 14:01       ` Mark Kettenis
2017-08-05 14:19         ` Rob Clark
2017-08-05 14:28         ` Mark Kettenis
2017-08-05 14:35           ` Rob Clark
2017-08-05 15:08             ` Mark Kettenis
2017-08-05 15:22               ` Rob Clark
2017-08-05 16:02                 ` Heinrich Schuchardt
2017-08-05 16:13                   ` Rob Clark
2017-08-05 15:10             ` Heinrich Schuchardt
2017-08-05 15:24               ` Rob Clark
2017-08-05 15:36                 ` Rob Clark
2017-08-06 13:16                   ` Mark Kettenis
2017-08-06 14:17                     ` Rob Clark
2017-08-06 14:26                       ` Rob Clark
2017-08-06 14:28                     ` Mark Kettenis
2017-08-06 14:45                       ` Rob Clark
2017-08-06 15:34                         ` Rob Clark
2017-08-06 16:00                           ` Heinrich Schuchardt
2017-08-06 16:14                           ` Jonathan Gray
2017-08-06 17:28                           ` Mark Kettenis
2017-08-06 17:49                             ` Rob Clark
2017-08-06 18:13                               ` Peter Robinson
2017-08-06 18:21                               ` Mark Kettenis
2017-08-06 18:37                                 ` Mark Kettenis
2017-08-06 18:47                                   ` Rob Clark
2017-08-06 18:53                                     ` Rob Clark
2017-08-06 18:41                                 ` Rob Clark
2017-08-07 15:47                           ` Jonathan Gray
2017-08-07 16:16                             ` Rob Clark
2017-08-08  1:36                               ` Jonathan Gray
2017-08-05 14:28         ` Rob Clark
2017-08-06 12:53           ` Mark Kettenis
2017-08-07 17:32     ` Peter Jones
2017-08-04 19:31 ` [U-Boot] [PATCH v0 14/20] efi_loader: use proper device-paths for net Rob Clark
2017-08-04 19:31 ` [U-Boot] [PATCH v0 15/20] efi_loader: refactor boot device and loaded_image handling Rob Clark
2017-08-04 19:31 ` Rob Clark [this message]
2017-08-04 19:31 ` [U-Boot] [PATCH v0 17/20] efi_loader: support load_image() from a file-path Rob Clark
2017-08-04 19:32 ` [U-Boot] [PATCH v0 18/20] efi_loader: make pool allocations cacheline aligned Rob Clark
2017-08-04 19:32 ` [U-Boot] [PATCH v0 19/20] efi_loader: efi variable support Rob Clark
2017-08-06  5:17   ` Simon Glass
2017-08-04 19:32 ` [U-Boot] [PATCH v0 20/20] efi_loader: add bootmgr Rob Clark
2017-08-04 20:06   ` Heinrich Schuchardt
2017-08-04 20:28     ` Rob Clark
2017-08-04 20:29       ` Rob Clark
2017-08-04 22:46       ` Peter Jones
2017-08-05 15:58 ` [U-Boot] [PATCH v0 21/20] efi_loader: hack for archs that cannot do unaligned accesses Rob Clark
2017-08-05 16:12   ` Heinrich Schuchardt
2017-08-05 16:16     ` Rob Clark
2017-08-05 16:19       ` Rob Clark
2017-08-05 16:26         ` Heinrich Schuchardt
2017-08-05 16:46           ` Rob Clark
2017-08-05 16:52       ` Heinrich Schuchardt
2017-08-05 17:06         ` Rob Clark
2017-08-05 18:43           ` Rob Clark
2017-08-05 20:05             ` Heinrich Schuchardt
2017-08-05 20:31               ` Rob Clark
2017-08-07 20:19                 ` Alexander Graf
2017-08-07 21:14                   ` Mark Kettenis
2017-08-07 22:18                     ` Rob Clark
2017-08-08  6:52                       ` Alexander Graf
2017-08-08  8:11                         ` Ard Biesheuvel
2017-08-08 11:32                           ` Leif Lindholm
2017-08-08 12:01                             ` Rob Clark
2017-08-08 12:39                               ` Leif Lindholm
2017-08-08  9:27                         ` Rob Clark
2017-08-08 12:26                       ` Mark Kettenis
2017-08-08 12:54                         ` Rob Clark
2017-08-08 13:33                           ` Mark Kettenis
2017-08-08 14:03                             ` Rob Clark
2017-08-08 14:10                               ` Rob Clark
2017-08-08 18:20                               ` Rob Clark
2017-08-07 16:56           ` Rob Clark
2017-08-07 17:15         ` Peter Jones
2017-08-10  1:32 ` [U-Boot] [PATCH v0 00/20] enough UEFI for standard distro boot Tom Rini
2017-08-10 10:41   ` Rob Clark

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170804193205.24669-17-robdclark@gmail.com \
    --to=robdclark@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.