Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/813652/?format=api
{ "id": 813652, "url": "http://patchwork.ozlabs.org/api/patches/813652/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/patch/20170913220546.19560-12-robdclark@gmail.com/", "project": { "id": 18, "url": "http://patchwork.ozlabs.org/api/projects/18/?format=api", "name": "U-Boot", "link_name": "uboot", "list_id": "u-boot.lists.denx.de", "list_email": "u-boot@lists.denx.de", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20170913220546.19560-12-robdclark@gmail.com>", "list_archive_url": null, "date": "2017-09-13T22:05:34", "name": "[U-Boot,v3,11/21] efi_loader: add file/filesys support", "commit_ref": null, "pull_url": null, "state": "accepted", "archived": false, "hash": "4da9b49e818b63b67f9461904a73eba8593422fd", "submitter": { "id": 18760, "url": "http://patchwork.ozlabs.org/api/people/18760/?format=api", "name": "Rob Clark", "email": "robdclark@gmail.com" }, "delegate": { "id": 3400, "url": "http://patchwork.ozlabs.org/api/users/3400/?format=api", "username": "agraf", "first_name": "Alexander", "last_name": "Graf", "email": "agraf@suse.de" }, "mbox": "http://patchwork.ozlabs.org/project/uboot/patch/20170913220546.19560-12-robdclark@gmail.com/mbox/", "series": [ { "id": 2990, "url": "http://patchwork.ozlabs.org/api/series/2990/?format=api", "web_url": "http://patchwork.ozlabs.org/project/uboot/list/?series=2990", "date": "2017-09-13T22:05:23", "name": "efi_loader: enough UEFI for standard distro boot", "version": 3, "mbox": "http://patchwork.ozlabs.org/series/2990/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/813652/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/813652/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<u-boot-bounces@lists.denx.de>", "X-Original-To": "incoming@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming@bilbo.ozlabs.org", "Authentication-Results": [ "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=lists.denx.de\n\t(client-ip=81.169.180.215; helo=lists.denx.de;\n\tenvelope-from=u-boot-bounces@lists.denx.de;\n\treceiver=<UNKNOWN>)", "ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=gmail.com header.i=@gmail.com\n\theader.b=\"af4CeB2q\"; dkim-atps=neutral" ], "Received": [ "from lists.denx.de (dione.denx.de [81.169.180.215])\n\tby ozlabs.org (Postfix) with ESMTP id 3xswzM07rsz9s76\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Sep 2017 08:18:22 +1000 (AEST)", "by lists.denx.de (Postfix, from userid 105)\n\tid 9A0D4C22518; Wed, 13 Sep 2017 22:09:08 +0000 (UTC)", "from lists.denx.de (localhost [IPv6:::1])\n\tby lists.denx.de (Postfix) with ESMTP id BCC27C225AB;\n\tWed, 13 Sep 2017 22:07:53 +0000 (UTC)", "by lists.denx.de (Postfix, from userid 105)\n\tid 9A5C4C2258B; Wed, 13 Sep 2017 22:06:30 +0000 (UTC)", "from mail-qt0-f195.google.com (mail-qt0-f195.google.com\n\t[209.85.216.195])\n\tby lists.denx.de (Postfix) with ESMTPS id 85A55C21EC9\n\tfor <u-boot@lists.denx.de>; Wed, 13 Sep 2017 22:06:26 +0000 (UTC)", "by mail-qt0-f195.google.com with SMTP id b1so955815qtc.0\n\tfor <u-boot@lists.denx.de>; Wed, 13 Sep 2017 15:06:26 -0700 (PDT)", "from localhost ([2601:184:4780:aac0:25f8:dd96:a084:785a])\n\tby smtp.gmail.com with ESMTPSA id\n\tf4sm10394310qtg.35.2017.09.13.15.06.23\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tWed, 13 Sep 2017 15:06:23 -0700 (PDT)" ], "X-Spam-Checker-Version": "SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de", "X-Spam-Level": "", "X-Spam-Status": "No, score=-0.0 required=5.0 tests=FREEMAIL_FROM,\n\tRCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL,\n\tT_DKIM_INVALID\n\tautolearn=unavailable autolearn_force=no version=3.4.0", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;\n\th=from:to:cc:subject:date:message-id:in-reply-to:references;\n\tbh=kFlWhaB4WpUD8hIh5CpzG+89KVM8KE+dsJbeo4M0HNo=;\n\tb=af4CeB2qBYj28TobvT5ZCVKJWzQP4GoIPkn6+0gmZWm1zYJ8i43C8s7e2YN7rh3I43\n\taDkm18S94Ha346nET3f6qUG4NbHWPErTCn5J3g2WLYVXSObJ0nX8sPOi/iGYcEpkRu/p\n\tvpi79EfjpNfE8+jl/j/Ym1hwfpiVVdCPDSwodBdwcgXphdZM62CP6X1xlvmFepluR++W\n\tqVS6YzX/0IH/saKLrzAcEbFmj3hBZfQuHRMtODhM5A87KU7zwpLTG1Eo4H+AlxRk+85E\n\tIWRdWVAd+NnSAAEe0JmS+uaMzAjUb9P+vmmQRor2DN1SvP5DX7GPKwMpaoiDX5Y5lbFS\n\tZNHg==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=kFlWhaB4WpUD8hIh5CpzG+89KVM8KE+dsJbeo4M0HNo=;\n\tb=q7euiNRSJZWEO5bZpZadA22M2rIljtl/Vs2XmWhEBMbcMarNaKMWkavM15N3OUpPYY\n\tEquIJY3X5Mley5pYNEwGt+aI7XRGjFi3nT91HAkJoE+XiUPG0MnCQDux2b22Ul1P3gbQ\n\t1ap95J//xirzayvi4OFuc8X94iKJoFUOGnX3jxeGLnPpFKGyn6eqnXA+TPceGZ8+ucqt\n\t0q0UWPQq17byvlCHbuUtx162W9r7YYHgiEvmXlVooAB8gQEYf5nvJ7D8McTdb98d8QAd\n\t+gcyvXMmjj7uJ7YNe1odJToBIFrfk7TH3MyrekMHdAB6qLmgruWgkBszMGX9wBImu9k/\n\t36ug==", "X-Gm-Message-State": "AHPjjUjpRsgcIr442qxj9D57NSUMVmWgLUT39xauko3vJms0z/hpQd0L\n\t52RvCwjlQyKbxZM6wDE=", "X-Google-Smtp-Source": "AOwi7QA3OUjItbZW3c6d6hJNgXXxCOJ2Wj5MtInnVu9F2LOnbSdVzUMQ236s+S+8g7SAfek9TO6lWg==", "X-Received": "by 10.200.3.159 with SMTP id t31mr28166337qtg.338.1505340385023; \n\tWed, 13 Sep 2017 15:06:25 -0700 (PDT)", "From": "Rob Clark <robdclark@gmail.com>", "To": "U-Boot Mailing List <u-boot@lists.denx.de>", "Date": "Wed, 13 Sep 2017 18:05:34 -0400", "Message-Id": "<20170913220546.19560-12-robdclark@gmail.com>", "X-Mailer": "git-send-email 2.13.5", "In-Reply-To": "<20170913220546.19560-1-robdclark@gmail.com>", "References": "<20170913220546.19560-1-robdclark@gmail.com>", "Cc": "Heinrich Schuchardt <xypron.glpk@gmx.de>, Peter Jones <pjones@redhat.com>", "Subject": "[U-Boot] [PATCH v3 11/21] efi_loader: add file/filesys support", "X-BeenThere": "u-boot@lists.denx.de", "X-Mailman-Version": "2.1.18", "Precedence": "list", "List-Id": "U-Boot discussion <u-boot.lists.denx.de>", "List-Unsubscribe": "<https://lists.denx.de/options/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=unsubscribe>", "List-Archive": "<http://lists.denx.de/pipermail/u-boot/>", "List-Post": "<mailto:u-boot@lists.denx.de>", "List-Help": "<mailto:u-boot-request@lists.denx.de?subject=help>", "List-Subscribe": "<https://lists.denx.de/listinfo/u-boot>,\n\t<mailto:u-boot-request@lists.denx.de?subject=subscribe>", "MIME-Version": "1.0", "Content-Type": "text/plain; charset=\"utf-8\"", "Content-Transfer-Encoding": "base64", "Errors-To": "u-boot-bounces@lists.denx.de", "Sender": "\"U-Boot\" <u-boot-bounces@lists.denx.de>" }, "content": "fallback.efi (and probably other things) use UEFI's simple-file-system\nprotocol and file support to search for OS's to boot.\n\nSigned-off-by: Rob Clark <robdclark@gmail.com>\n---\n include/efi.h | 2 +\n include/efi_api.h | 65 +++++\n include/efi_loader.h | 13 +\n lib/efi_loader/Makefile | 1 +\n lib/efi_loader/efi_disk.c | 32 +++\n lib/efi_loader/efi_file.c | 560 ++++++++++++++++++++++++++++++++++++++\n lib/efi_loader/efi_image_loader.c | 3 +\n 7 files changed, 676 insertions(+)\n create mode 100644 lib/efi_loader/efi_file.c", "diff": "diff --git a/include/efi.h b/include/efi.h\nindex 87b0b43f20..ddd2b96417 100644\n--- a/include/efi.h\n+++ b/include/efi.h\n@@ -81,6 +81,8 @@ typedef struct {\n #define EFI_IP_ADDRESS_CONFLICT\t\t(EFI_ERROR_MASK | 34)\n #define EFI_HTTP_ERROR\t\t\t(EFI_ERROR_MASK | 35)\n \n+#define EFI_WARN_DELETE_FAILURE\t2\n+\n typedef unsigned long efi_status_t;\n typedef u64 efi_physical_addr_t;\n typedef u64 efi_virtual_addr_t;\ndiff --git a/include/efi_api.h b/include/efi_api.h\nindex 0c36122107..1aae96355f 100644\n--- a/include/efi_api.h\n+++ b/include/efi_api.h\n@@ -666,4 +666,69 @@ struct efi_pxe {\n \tstruct efi_pxe_mode *mode;\n };\n \n+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \\\n+\tEFI_GUID(0x964e5b22, 0x6459, 0x11d2, \\\n+\t\t 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)\n+#define EFI_FILE_PROTOCOL_REVISION 0x00010000\n+\n+struct efi_file_handle {\n+\tu64 rev;\n+\tefi_status_t (EFIAPI *open)(struct efi_file_handle *file,\n+\t\t\tstruct efi_file_handle **new_handle,\n+\t\t\ts16 *file_name, u64 open_mode, u64 attributes);\n+\tefi_status_t (EFIAPI *close)(struct efi_file_handle *file);\n+\tefi_status_t (EFIAPI *delete)(struct efi_file_handle *file);\n+\tefi_status_t (EFIAPI *read)(struct efi_file_handle *file,\n+\t\t\tu64 *buffer_size, void *buffer);\n+\tefi_status_t (EFIAPI *write)(struct efi_file_handle *file,\n+\t\t\tu64 *buffer_size, void *buffer);\n+\tefi_status_t (EFIAPI *getpos)(struct efi_file_handle *file,\n+\t\t\tu64 *pos);\n+\tefi_status_t (EFIAPI *setpos)(struct efi_file_handle *file,\n+\t\t\tu64 pos);\n+\tefi_status_t (EFIAPI *getinfo)(struct efi_file_handle *file,\n+\t\t\tefi_guid_t *info_type, u64 *buffer_size, void *buffer);\n+\tefi_status_t (EFIAPI *setinfo)(struct efi_file_handle *file,\n+\t\t\tefi_guid_t *info_type, u64 buffer_size, void *buffer);\n+\tefi_status_t (EFIAPI *flush)(struct efi_file_handle *file);\n+};\n+\n+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID \\\n+\tEFI_GUID(0x964e5b22, 0x6459, 0x11d2, \\\n+\t\t 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)\n+#define EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION 0x00010000\n+\n+struct efi_simple_file_system_protocol {\n+\tu64 rev;\n+\tefi_status_t (EFIAPI *open_volume)(struct efi_simple_file_system_protocol *this,\n+\t\t\tstruct efi_file_handle **root);\n+};\n+\n+#define EFI_FILE_INFO_GUID \\\n+\tEFI_GUID(0x9576e92, 0x6d3f, 0x11d2, \\\n+\t\t 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)\n+\n+#define EFI_FILE_MODE_READ\t0x0000000000000001\n+#define EFI_FILE_MODE_WRITE\t0x0000000000000002\n+#define EFI_FILE_MODE_CREATE\t0x8000000000000000\n+\n+#define EFI_FILE_READ_ONLY\t0x0000000000000001\n+#define EFI_FILE_HIDDEN\t\t0x0000000000000002\n+#define EFI_FILE_SYSTEM\t\t0x0000000000000004\n+#define EFI_FILE_RESERVED\t0x0000000000000008\n+#define EFI_FILE_DIRECTORY\t0x0000000000000010\n+#define EFI_FILE_ARCHIVE\t0x0000000000000020\n+#define EFI_FILE_VALID_ATTR\t0x0000000000000037\n+\n+struct efi_file_info {\n+\tu64 size;\n+\tu64 file_size;\n+\tu64 physical_size;\n+\tstruct efi_time create_time;\n+\tstruct efi_time last_access_time;\n+\tstruct efi_time modification_time;\n+\tu64 attribute;\n+\ts16 file_name[0];\n+};\n+\n #endif\ndiff --git a/include/efi_loader.h b/include/efi_loader.h\nindex ec8803f588..b0c1e8fb78 100644\n--- a/include/efi_loader.h\n+++ b/include/efi_loader.h\n@@ -65,6 +65,8 @@ extern const efi_guid_t efi_guid_console_control;\n extern const efi_guid_t efi_guid_device_path;\n extern const efi_guid_t efi_guid_loaded_image;\n extern const efi_guid_t efi_guid_device_path_to_text_protocol;\n+extern const efi_guid_t efi_simple_file_system_protocol_guid;\n+extern const efi_guid_t efi_file_info_guid;\n \n extern unsigned int __efi_runtime_start, __efi_runtime_stop;\n extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;\n@@ -140,6 +142,9 @@ int efi_net_register(void);\n /* Called by bootefi to make SMBIOS tables available */\n void efi_smbios_register(void);\n \n+struct efi_simple_file_system_protocol *\n+efi_fs_from_path(struct efi_device_path *fp);\n+\n /* Called by networking code to memorize the dhcp ack package */\n void efi_net_set_dhcp_ack(void *pkt, int len);\n \n@@ -168,6 +173,14 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type,\n /* Call this to signal an event */\n void efi_signal_event(struct efi_event *event);\n \n+/* open file system: */\n+struct efi_simple_file_system_protocol *efi_simple_file_system(\n+\t\tstruct blk_desc *desc, int part, struct efi_device_path *dp);\n+\n+/* open file from device-path: */\n+struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp);\n+\n+\n /* Generic EFI memory allocator, call this to get memory */\n void *efi_alloc(uint64_t len, int memory_type);\n /* More specific EFI memory allocator, called by EFI payloads */\ndiff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile\nindex f35e5ce8a8..cce92cfeb5 100644\n--- a/lib/efi_loader/Makefile\n+++ b/lib/efi_loader/Makefile\n@@ -16,6 +16,7 @@ always := $(efiprogs-y)\n obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o\n obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o\n obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o\n+obj-y += efi_file.o\n obj-$(CONFIG_LCD) += efi_gop.o\n obj-$(CONFIG_DM_VIDEO) += efi_gop.o\n obj-$(CONFIG_PARTITIONS) += efi_disk.o\ndiff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c\nindex 14f3e020c8..9805585eb1 100644\n--- a/lib/efi_loader/efi_disk.c\n+++ b/lib/efi_loader/efi_disk.c\n@@ -31,6 +31,8 @@ struct efi_disk_obj {\n \tstruct efi_device_path *dp;\n \t/* partition # */\n \tunsigned part;\n+\t/* handle to filesys proto (for partition objects) */\n+\tstruct efi_simple_file_system_protocol *volume;\n \t/* Offset into disk for simple partitions */\n \tlbaint_t offset;\n \t/* Internal block device */\n@@ -172,6 +174,28 @@ static const struct efi_block_io block_io_disk_template = {\n \t.flush_blocks = &efi_disk_flush_blocks,\n };\n \n+/*\n+ * Find filesystem from a device-path. The passed in path 'p' probably\n+ * contains one or more /File(name) nodes, so the comparison stops at\n+ * the first /File() node, and returns the pointer to that via 'rp'.\n+ * This is mostly intended to be a helper to map a device-path to an\n+ * efi_file_handle object.\n+ */\n+struct efi_simple_file_system_protocol *\n+efi_fs_from_path(struct efi_device_path *fp)\n+{\n+\tstruct efi_object *efiobj;\n+\tstruct efi_disk_obj *diskobj;\n+\n+\tefiobj = efi_dp_find_obj(fp, NULL);\n+\tif (!efiobj)\n+\t\treturn NULL;\n+\n+\tdiskobj = container_of(efiobj, struct efi_disk_obj, parent);\n+\n+\treturn diskobj->volume;\n+}\n+\n static void efi_disk_add_dev(const char *name,\n \t\t\t const char *if_typename,\n \t\t\t struct blk_desc *desc,\n@@ -194,6 +218,14 @@ static void efi_disk_add_dev(const char *name,\n \tdiskobj->parent.protocols[0].protocol_interface = &diskobj->ops;\n \tdiskobj->parent.protocols[1].guid = &efi_guid_device_path;\n \tdiskobj->parent.protocols[1].protocol_interface = diskobj->dp;\n+\tif (part >= 1) {\n+\t\tdiskobj->volume = efi_simple_file_system(desc, part,\n+\t\t\t\t\t\t\t diskobj->dp);\n+\t\tdiskobj->parent.protocols[2].guid =\n+\t\t\t&efi_simple_file_system_protocol_guid;\n+\t\tdiskobj->parent.protocols[2].protocol_interface =\n+\t\t\tdiskobj->volume;\n+\t}\n \tdiskobj->parent.handle = diskobj;\n \tdiskobj->ops = block_io_disk_template;\n \tdiskobj->ifname = if_typename;\ndiff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c\nnew file mode 100644\nindex 0000000000..5e1eee5a20\n--- /dev/null\n+++ b/lib/efi_loader/efi_file.c\n@@ -0,0 +1,560 @@\n+/*\n+ * EFI utils\n+ *\n+ * Copyright (c) 2017 Rob Clark\n+ *\n+ * SPDX-License-Identifier: GPL-2.0+\n+ */\n+\n+#include <common.h>\n+#include <charset.h>\n+#include <efi_loader.h>\n+#include <malloc.h>\n+#include <fs.h>\n+\n+struct file_system {\n+\tstruct efi_simple_file_system_protocol base;\n+\tstruct efi_device_path *dp;\n+\tstruct blk_desc *desc;\n+\tint part;\n+};\n+#define to_fs(x) container_of(x, struct file_system, base)\n+\n+struct file_handle {\n+\tstruct efi_file_handle base;\n+\tstruct file_system *fs;\n+\tloff_t offset; /* current file position/cursor */\n+\tint isdir;\n+\n+\t/* for reading a directory: */\n+\tstruct fs_dir_stream *dirs;\n+\tstruct fs_dirent *dent;\n+\n+\tchar path[0];\n+};\n+#define to_fh(x) container_of(x, struct file_handle, base)\n+\n+static const struct efi_file_handle efi_file_handle_protocol;\n+\n+static char *basename(struct file_handle *fh)\n+{\n+\tchar *s = strrchr(fh->path, '/');\n+\tif (s)\n+\t\treturn s + 1;\n+\treturn fh->path;\n+}\n+\n+static int set_blk_dev(struct file_handle *fh)\n+{\n+\treturn fs_set_blk_dev_with_part(fh->fs->desc, fh->fs->part);\n+}\n+\n+static int is_dir(struct file_handle *fh)\n+{\n+\tstruct fs_dir_stream *dirs;\n+\n+\tset_blk_dev(fh);\n+\tdirs = fs_opendir(fh->path);\n+\tif (!dirs)\n+\t\treturn 0;\n+\n+\tfs_closedir(dirs);\n+\n+\treturn 1;\n+}\n+\n+/*\n+ * Normalize a path which may include either back or fwd slashes,\n+ * double slashes, . or .. entries in the path, etc.\n+ */\n+static int sanitize_path(char *path)\n+{\n+\tchar *p\t;\n+\n+\t/* backslash to slash: */\n+\tp = path;\n+\twhile ((p = strchr(p, '\\\\')))\n+\t\t*p++ = '/';\n+\n+\t/* handle double-slashes: */\n+\tp = path;\n+\twhile ((p = strstr(p, \"//\"))) {\n+\t\tchar *src = p + 1;\n+\t\tmemmove(p, src, strlen(src) + 1);\n+\t}\n+\n+\t/* handle extra /.'s */\n+\tp = path;\n+\twhile ((p = strstr(p, \"/.\"))) {\n+\t\t/*\n+\t\t * You'd be tempted to do this *after* handling \"..\"s\n+\t\t * below to avoid having to check if \"/.\" is start of\n+\t\t * a \"/..\", but that won't have the correct results..\n+\t\t * for example, \"/foo/./../bar\" would get resolved to\n+\t\t * \"/foo/bar\" if you did these two passes in the other\n+\t\t * order\n+\t\t */\n+\t\tif (p[2] == '.') {\n+\t\t\tp += 2;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tchar *src = p + 2;\n+\t\tmemmove(p, src, strlen(src) + 1);\n+\t}\n+\n+\t/* handle extra /..'s: */\n+\tp = path;\n+\twhile ((p = strstr(p, \"/..\"))) {\n+\t\tchar *src = p + 3;\n+\n+\t\tp--;\n+\n+\t\t/* find beginning of previous path entry: */\n+\t\twhile (true) {\n+\t\t\tif (p < path)\n+\t\t\t\treturn -1;\n+\t\t\tif (*p == '/')\n+\t\t\t\tbreak;\n+\t\t\tp--;\n+\t\t}\n+\n+\t\tmemmove(p, src, strlen(src) + 1);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* NOTE: despite what you would expect, 'file_name' is actually a path.\n+ * With windoze style backlashes, ofc.\n+ */\n+static struct efi_file_handle *file_open(struct file_system *fs,\n+\t\tstruct file_handle *parent, s16 *file_name, u64 mode)\n+{\n+\tstruct file_handle *fh;\n+\tchar f0[MAX_UTF8_PER_UTF16] = {0};\n+\tint plen = 0;\n+\tint flen = 0;\n+\n+\tif (file_name) {\n+\t\tutf16_to_utf8((u8 *)f0, (u16 *)file_name, 1);\n+\t\tflen = utf16_strlen((u16 *)file_name);\n+\t}\n+\n+\t/* we could have a parent, but also an absolute path: */\n+\tif (f0[0] == '\\\\') {\n+\t\tplen = 0;\n+\t} else if (parent) {\n+\t\tplen = strlen(parent->path) + 1;\n+\t}\n+\n+\t/* +2 is for null and '/' */\n+\tfh = calloc(1, sizeof(*fh) + plen + (flen * MAX_UTF8_PER_UTF16) + 2);\n+\n+\tfh->base = efi_file_handle_protocol;\n+\tfh->fs = fs;\n+\n+\tif (parent) {\n+\t\tchar *p = fh->path;\n+\n+\t\tif (plen > 0) {\n+\t\t\tstrcpy(p, parent->path);\n+\t\t\tp += plen - 1;\n+\t\t\t*p++ = '/';\n+\t\t}\n+\n+\t\tutf16_to_utf8((u8 *)p, (u16 *)file_name, flen);\n+\n+\t\tif (sanitize_path(fh->path))\n+\t\t\tgoto error;\n+\n+\t\t/* check if file exists: */\n+\t\tif (set_blk_dev(fh))\n+\t\t\tgoto error;\n+\n+\t\tif (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path)))\n+\t\t\tgoto error;\n+\n+\t\t/* figure out if file is a directory: */\n+\t\tfh->isdir = is_dir(fh);\n+\t} else {\n+\t\tfh->isdir = 1;\n+\t\tstrcpy(fh->path, \"\");\n+\t}\n+\n+\treturn &fh->base;\n+\n+error:\n+\tfree(fh);\n+\treturn NULL;\n+}\n+\n+static efi_status_t EFIAPI efi_file_open(struct efi_file_handle *file,\n+\t\tstruct efi_file_handle **new_handle,\n+\t\ts16 *file_name, u64 open_mode, u64 attributes)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\n+\tEFI_ENTRY(\"%p, %p, \\\"%ls\\\", %llx, %llu\", file, new_handle, file_name,\n+\t\t open_mode, attributes);\n+\n+\t*new_handle = file_open(fh->fs, fh, file_name, open_mode);\n+\tif (!*new_handle)\n+\t\treturn EFI_EXIT(EFI_NOT_FOUND);\n+\n+\treturn EFI_EXIT(EFI_SUCCESS);\n+}\n+\n+static efi_status_t file_close(struct file_handle *fh)\n+{\n+\tfs_closedir(fh->dirs);\n+\tfree(fh);\n+\treturn EFI_SUCCESS;\n+}\n+\n+static efi_status_t EFIAPI efi_file_close(struct efi_file_handle *file)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tEFI_ENTRY(\"%p\", file);\n+\treturn EFI_EXIT(file_close(fh));\n+}\n+\n+static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tEFI_ENTRY(\"%p\", file);\n+\tfile_close(fh);\n+\treturn EFI_EXIT(EFI_WARN_DELETE_FAILURE);\n+}\n+\n+static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,\n+\t\tvoid *buffer)\n+{\n+\tloff_t actread;\n+\n+\tif (fs_read(fh->path, (ulong)buffer, fh->offset,\n+\t\t *buffer_size, &actread))\n+\t\treturn EFI_DEVICE_ERROR;\n+\n+\t*buffer_size = actread;\n+\tfh->offset += actread;\n+\n+\treturn EFI_SUCCESS;\n+}\n+\n+static efi_status_t dir_read(struct file_handle *fh, u64 *buffer_size,\n+\t\tvoid *buffer)\n+{\n+\tstruct efi_file_info *info = buffer;\n+\tstruct fs_dirent *dent;\n+\tunsigned required_size;\n+\n+\tif (!fh->dirs) {\n+\t\tassert(fh->offset == 0);\n+\t\tfh->dirs = fs_opendir(fh->path);\n+\t\tif (!fh->dirs)\n+\t\t\treturn EFI_DEVICE_ERROR;\n+\t}\n+\n+\t/*\n+\t * So this is a bit awkward. Since fs layer is stateful and we\n+\t * can't rewind an entry, in the EFI_BUFFER_TOO_SMALL case below\n+\t * we might have to return without consuming the dent.. so we\n+\t * have to stash it for next call.\n+\t */\n+\tif (fh->dent) {\n+\t\tdent = fh->dent;\n+\t\tfh->dent = NULL;\n+\t} else {\n+\t\tdent = fs_readdir(fh->dirs);\n+\t}\n+\n+\n+\tif (!dent) {\n+\t\t/* no more files in directory: */\n+\t\t/* workaround shim.efi bug/quirk.. as find_boot_csv()\n+\t\t * loops through directory contents, it initially calls\n+\t\t * read w/ zero length buffer to find out how much mem\n+\t\t * to allocate for the EFI_FILE_INFO, then allocates,\n+\t\t * and then calls a 2nd time. If we return size of\n+\t\t * zero the first time, it happily passes that to\n+\t\t * AllocateZeroPool(), and when that returns NULL it\n+\t\t * thinks it is EFI_OUT_OF_RESOURCES. So on first\n+\t\t * call return a non-zero size:\n+\t\t */\n+\t\tif (*buffer_size == 0)\n+\t\t\t*buffer_size = sizeof(*info);\n+\t\telse\n+\t\t\t*buffer_size = 0;\n+\t\treturn EFI_SUCCESS;\n+\t}\n+\n+\t/* check buffer size: */\n+\trequired_size = sizeof(*info) + 2 * (strlen(dent->name) + 1);\n+\tif (*buffer_size < required_size) {\n+\t\t*buffer_size = required_size;\n+\t\tfh->dent = dent;\n+\t\treturn EFI_BUFFER_TOO_SMALL;\n+\t}\n+\n+\t*buffer_size = required_size;\n+\tmemset(info, 0, required_size);\n+\n+\tinfo->size = required_size;\n+\tinfo->file_size = dent->size;\n+\tinfo->physical_size = dent->size;\n+\n+\tif (dent->type == FS_DT_DIR)\n+\t\tinfo->attribute |= EFI_FILE_DIRECTORY;\n+\n+\tascii2unicode((u16 *)info->file_name, dent->name);\n+\n+\tfh->offset++;\n+\n+\treturn EFI_SUCCESS;\n+}\n+\n+static efi_status_t EFIAPI efi_file_read(struct efi_file_handle *file,\n+\t\tu64 *buffer_size, void *buffer)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tefi_status_t ret = EFI_SUCCESS;\n+\n+\tEFI_ENTRY(\"%p, %p, %p\", file, buffer_size, buffer);\n+\n+\tif (set_blk_dev(fh)) {\n+\t\tret = EFI_DEVICE_ERROR;\n+\t\tgoto error;\n+\t}\n+\n+\tif (fh->isdir)\n+\t\tret = dir_read(fh, buffer_size, buffer);\n+\telse\n+\t\tret = file_read(fh, buffer_size, buffer);\n+\n+error:\n+\treturn EFI_EXIT(ret);\n+}\n+\n+static efi_status_t EFIAPI efi_file_write(struct efi_file_handle *file,\n+\t\tu64 *buffer_size, void *buffer)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tefi_status_t ret = EFI_SUCCESS;\n+\tloff_t actwrite;\n+\n+\tEFI_ENTRY(\"%p, %p, %p\", file, buffer_size, buffer);\n+\n+\tif (set_blk_dev(fh)) {\n+\t\tret = EFI_DEVICE_ERROR;\n+\t\tgoto error;\n+\t}\n+\n+\tif (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size,\n+\t\t &actwrite)) {\n+\t\tret = EFI_DEVICE_ERROR;\n+\t\tgoto error;\n+\t}\n+\n+\t*buffer_size = actwrite;\n+\tfh->offset += actwrite;\n+\n+error:\n+\treturn EFI_EXIT(ret);\n+}\n+\n+static efi_status_t EFIAPI efi_file_getpos(struct efi_file_handle *file,\n+\t\tu64 *pos)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tEFI_ENTRY(\"%p, %p\", file, pos);\n+\t*pos = fh->offset;\n+\treturn EFI_EXIT(EFI_SUCCESS);\n+}\n+\n+static efi_status_t EFIAPI efi_file_setpos(struct efi_file_handle *file,\n+\t\tu64 pos)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tefi_status_t ret = EFI_SUCCESS;\n+\n+\tEFI_ENTRY(\"%p, %llu\", file, pos);\n+\n+\tif (fh->isdir) {\n+\t\tif (pos != 0) {\n+\t\t\tret = EFI_UNSUPPORTED;\n+\t\t\tgoto error;\n+\t\t}\n+\t\tfs_closedir(fh->dirs);\n+\t\tfh->dirs = NULL;\n+\t}\n+\n+\tif (pos == ~0ULL) {\n+\t\tloff_t file_size;\n+\n+\t\tif (set_blk_dev(fh)) {\n+\t\t\tret = EFI_DEVICE_ERROR;\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tif (fs_size(fh->path, &file_size)) {\n+\t\t\tret = EFI_DEVICE_ERROR;\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tpos = file_size;\n+\t}\n+\n+\tfh->offset = pos;\n+\n+error:\n+\treturn EFI_EXIT(ret);\n+}\n+\n+static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file,\n+\t\tefi_guid_t *info_type, u64 *buffer_size, void *buffer)\n+{\n+\tstruct file_handle *fh = to_fh(file);\n+\tefi_status_t ret = EFI_SUCCESS;\n+\n+\tEFI_ENTRY(\"%p, %p, %p, %p\", file, info_type, buffer_size, buffer);\n+\n+\tif (!guidcmp(info_type, &efi_file_info_guid)) {\n+\t\tstruct efi_file_info *info = buffer;\n+\t\tchar *filename = basename(fh);\n+\t\tunsigned required_size;\n+\t\tloff_t file_size;\n+\n+\t\t/* check buffer size: */\n+\t\trequired_size = sizeof(*info) + 2 * (strlen(filename) + 1);\n+\t\tif (*buffer_size < required_size) {\n+\t\t\t*buffer_size = required_size;\n+\t\t\tret = EFI_BUFFER_TOO_SMALL;\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tif (set_blk_dev(fh)) {\n+\t\t\tret = EFI_DEVICE_ERROR;\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tif (fs_size(fh->path, &file_size)) {\n+\t\t\tret = EFI_DEVICE_ERROR;\n+\t\t\tgoto error;\n+\t\t}\n+\n+\t\tmemset(info, 0, required_size);\n+\n+\t\tinfo->size = required_size;\n+\t\tinfo->file_size = file_size;\n+\t\tinfo->physical_size = file_size;\n+\n+\t\tif (fh->isdir)\n+\t\t\tinfo->attribute |= EFI_FILE_DIRECTORY;\n+\n+\t\tascii2unicode((u16 *)info->file_name, filename);\n+\t} else {\n+\t\tret = EFI_UNSUPPORTED;\n+\t}\n+\n+error:\n+\treturn EFI_EXIT(ret);\n+}\n+\n+static efi_status_t EFIAPI efi_file_setinfo(struct efi_file_handle *file,\n+\t\tefi_guid_t *info_type, u64 buffer_size, void *buffer)\n+{\n+\tEFI_ENTRY(\"%p, %p, %llu, %p\", file, info_type, buffer_size, buffer);\n+\treturn EFI_EXIT(EFI_UNSUPPORTED);\n+}\n+\n+static efi_status_t EFIAPI efi_file_flush(struct efi_file_handle *file)\n+{\n+\tEFI_ENTRY(\"%p\", file);\n+\treturn EFI_EXIT(EFI_SUCCESS);\n+}\n+\n+static const struct efi_file_handle efi_file_handle_protocol = {\n+\t.rev = EFI_FILE_PROTOCOL_REVISION,\n+\t.open = efi_file_open,\n+\t.close = efi_file_close,\n+\t.delete = efi_file_delete,\n+\t.read = efi_file_read,\n+\t.write = efi_file_write,\n+\t.getpos = efi_file_getpos,\n+\t.setpos = efi_file_setpos,\n+\t.getinfo = efi_file_getinfo,\n+\t.setinfo = efi_file_setinfo,\n+\t.flush = efi_file_flush,\n+};\n+\n+struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp)\n+{\n+\tstruct efi_simple_file_system_protocol *v;\n+\tstruct efi_file_handle *f;\n+\tefi_status_t ret;\n+\n+\tv = efi_fs_from_path(fp);\n+\tif (!v)\n+\t\treturn NULL;\n+\n+\tEFI_CALL(ret = v->open_volume(v, &f));\n+\tif (ret != EFI_SUCCESS)\n+\t\treturn NULL;\n+\n+\t/* skip over device-path nodes before the file path: */\n+\twhile (fp && !EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH))\n+\t\tfp = efi_dp_next(fp);\n+\n+\twhile (fp) {\n+\t\tstruct efi_device_path_file_path *fdp =\n+\t\t\tcontainer_of(fp, struct efi_device_path_file_path, dp);\n+\t\tstruct efi_file_handle *f2;\n+\n+\t\tif (!EFI_DP_TYPE(fp, MEDIA_DEVICE, FILE_PATH)) {\n+\t\t\tprintf(\"bad file path!\\n\");\n+\t\t\tf->close(f);\n+\t\t\treturn NULL;\n+\t\t}\n+\n+\t\tEFI_CALL(ret = f->open(f, &f2, (s16 *)fdp->str,\n+\t\t\t\t EFI_FILE_MODE_READ, 0));\n+\t\tif (ret != EFI_SUCCESS)\n+\t\t\treturn NULL;\n+\n+\t\tfp = efi_dp_next(fp);\n+\n+\t\tEFI_CALL(f->close(f));\n+\t\tf = f2;\n+\t}\n+\n+\treturn f;\n+}\n+\n+static efi_status_t EFIAPI\n+efi_open_volume(struct efi_simple_file_system_protocol *this,\n+\t\tstruct efi_file_handle **root)\n+{\n+\tstruct file_system *fs = to_fs(this);\n+\n+\tEFI_ENTRY(\"%p, %p\", this, root);\n+\n+\t*root = file_open(fs, NULL, NULL, 0);\n+\n+\treturn EFI_EXIT(EFI_SUCCESS);\n+}\n+\n+struct efi_simple_file_system_protocol *\n+efi_simple_file_system(struct blk_desc *desc, int part,\n+\t\t struct efi_device_path *dp)\n+{\n+\tstruct file_system *fs;\n+\n+\tfs = calloc(1, sizeof(*fs));\n+\tfs->base.rev = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;\n+\tfs->base.open_volume = efi_open_volume;\n+\tfs->desc = desc;\n+\tfs->part = part;\n+\tfs->dp = dp;\n+\n+\treturn &fs->base;\n+}\ndiff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c\nindex f961407f50..469acae082 100644\n--- a/lib/efi_loader/efi_image_loader.c\n+++ b/lib/efi_loader/efi_image_loader.c\n@@ -17,6 +17,9 @@ DECLARE_GLOBAL_DATA_PTR;\n \n const efi_guid_t efi_guid_device_path = DEVICE_PATH_GUID;\n const efi_guid_t efi_guid_loaded_image = LOADED_IMAGE_GUID;\n+const efi_guid_t efi_simple_file_system_protocol_guid =\n+\t\tEFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;\n+const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;\n \n static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,\n \t\t\tunsigned long rel_size, void *efi_reloc)\n", "prefixes": [ "U-Boot", "v3", "11/21" ] }