[PATCH v2 0/3] efi: Minor improvements for the EFI app

This series collects a few fixes and improvements useful when booting U-Boot as an EFI app.
Changes in v2: - Drop duplicate acpi_xsdt patch - Put the board_early_init_r code into board/
Simon Glass (3): efi: Collect the ACPI tables in the app efi: Correct display of table GUIDs efi: Avoid using dm_scan_other()
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++ cmd/efi_common.c | 4 +- configs/efi-x86_app64_defconfig | 1 + lib/efi/efi_app.c | 199 +++---------------------------- 5 files changed, 227 insertions(+), 187 deletions(-) create mode 100644 board/efi/efi-x86_app/Makefile create mode 100644 board/efi/efi-x86_app/efi_app.c

Locate these so that they can be displayed using the 'acpi' command.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
lib/efi/efi_app.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 2209410f35b5..c5eb816655ea 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -12,18 +12,21 @@ #include <cpu_func.h> #include <debug_uart.h> #include <dm.h> +#include <efi.h> +#include <efi_api.h> #include <errno.h> #include <init.h> #include <malloc.h> +#include <sysreset.h> +#include <uuid.h> #include <asm/global_data.h> #include <linux/err.h> #include <linux/types.h> -#include <efi.h> -#include <efi_api.h> -#include <sysreset.h> +#include <asm/global_data.h> #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/root.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -320,6 +323,19 @@ int dm_scan_other(bool pre_reloc_only) return 0; }
+static void scan_tables(struct efi_system_table *sys_table) +{ + efi_guid_t acpi = EFI_ACPI_TABLE_GUID; + uint i; + + for (i = 0; i < sys_table->nr_tables; i++) { + struct efi_configuration_table *tab = &sys_table->tables[i]; + + if (!memcmp(&tab->guid, &acpi, sizeof(efi_guid_t))) + gd_set_acpi_start(map_to_sysmem(tab->table)); + } +} + /** * efi_main() - Start an EFI image * @@ -354,6 +370,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, return ret; }
+ scan_tables(priv->sys_table); + /* * We could store the EFI memory map here, but it changes all the time, * so this is only useful for debugging.

On 11/12/23 21:55, Simon Glass wrote:
Locate these so that they can be displayed using the 'acpi' command.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v1)
lib/efi/efi_app.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-)
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index 2209410f35b5..c5eb816655ea 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -12,18 +12,21 @@ #include <cpu_func.h> #include <debug_uart.h> #include <dm.h> +#include <efi.h> +#include <efi_api.h> #include <errno.h> #include <init.h> #include <malloc.h> +#include <sysreset.h> +#include <uuid.h> #include <asm/global_data.h> #include <linux/err.h> #include <linux/types.h> -#include <efi.h> -#include <efi_api.h> -#include <sysreset.h> +#include <asm/global_data.h> #include <dm/device-internal.h> #include <dm/lists.h> #include <dm/root.h> +#include <mapmem.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -320,6 +323,19 @@ int dm_scan_other(bool pre_reloc_only) return 0; }
+static void scan_tables(struct efi_system_table *sys_table) +{
- efi_guid_t acpi = EFI_ACPI_TABLE_GUID;
- uint i;
- for (i = 0; i < sys_table->nr_tables; i++) {
struct efi_configuration_table *tab = &sys_table->tables[i];
In cmd/bootefi we have a static function get_config_table() I guess we should export and move it to lib/.
if (!memcmp(&tab->guid, &acpi, sizeof(efi_guid_t)))
gd_set_acpi_start(map_to_sysmem(tab->table));
return; could be added here to shorten the search.
Reviewed-by: Heinrich Schuchardt xypron.glpk@gmx.de
- }
+}
- /**
- efi_main() - Start an EFI image
@@ -354,6 +370,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, return ret; }
- scan_tables(priv->sys_table);
- /*
- We could store the EFI memory map here, but it changes all the time,
- so this is only useful for debugging.

The printf() %pU option decodes GUIDs so it is not necessary to do this first. Drop the incorrect code.
Signed-off-by: Simon Glass sjg@chromium.org ---
(no changes since v1)
cmd/efi_common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/cmd/efi_common.c b/cmd/efi_common.c index f4056096cd3f..1aa2351fcdfd 100644 --- a/cmd/efi_common.c +++ b/cmd/efi_common.c @@ -17,10 +17,8 @@ void efi_show_tables(struct efi_system_table *systab)
for (i = 0; i < systab->nr_tables; i++) { struct efi_configuration_table *tab = &systab->tables[i]; - char guid_str[37];
- uuid_bin_to_str(tab->guid.b, guid_str, 1); - printf("%p %pUl %s\n", tab->table, guid_str, + printf("%p %pUl %s\n", tab->table, tab->guid.b, uuid_guid_get_str(tab->guid.b) ?: "(unknown)"); } }

On 11/12/23 21:55, Simon Glass wrote:
The printf() %pU option decodes GUIDs so it is not necessary to do this first. Drop the incorrect code.
Signed-off-by: Simon Glass sjg@chromium.org
Reviewed-by: Heinrich Schuchardt xyprn.glpk@gmx.de
(no changes since v1)
cmd/efi_common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/cmd/efi_common.c b/cmd/efi_common.c index f4056096cd3f..1aa2351fcdfd 100644 --- a/cmd/efi_common.c +++ b/cmd/efi_common.c @@ -17,10 +17,8 @@ void efi_show_tables(struct efi_system_table *systab)
for (i = 0; i < systab->nr_tables; i++) { struct efi_configuration_table *tab = &systab->tables[i];
char guid_str[37];
uuid_bin_to_str(tab->guid.b, guid_str, 1);
printf("%p %pUl %s\n", tab->table, guid_str,
} }printf("%p %pUl %s\n", tab->table, tab->guid.b, uuid_guid_get_str(tab->guid.b) ?: "(unknown)");

On Sun, 12 Nov 2023 at 22:55, Simon Glass sjg@chromium.org wrote:
The printf() %pU option decodes GUIDs so it is not necessary to do this first. Drop the incorrect code.
Signed-off-by: Simon Glass sjg@chromium.org
(no changes since v1)
cmd/efi_common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/cmd/efi_common.c b/cmd/efi_common.c index f4056096cd3f..1aa2351fcdfd 100644 --- a/cmd/efi_common.c +++ b/cmd/efi_common.c @@ -17,10 +17,8 @@ void efi_show_tables(struct efi_system_table *systab)
for (i = 0; i < systab->nr_tables; i++) { struct efi_configuration_table *tab = &systab->tables[i];
char guid_str[37];
uuid_bin_to_str(tab->guid.b, guid_str, 1);
printf("%p %pUl %s\n", tab->table, guid_str,
printf("%p %pUl %s\n", tab->table, tab->guid.b, uuid_guid_get_str(tab->guid.b) ?: "(unknown)"); }
}
2.42.0.869.gea05f2083d-goog
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org ---
Changes in v2: - Drop duplicate acpi_xsdt patch - Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++ configs/efi-x86_app64_defconfig | 1 + lib/efi/efi_app.c | 187 ----------------------------- 4 files changed, 211 insertions(+), 187 deletions(-) create mode 100644 board/efi/efi-x86_app/Makefile create mode 100644 board/efi/efi-x86_app/efi_app.c
diff --git a/board/efi/efi-x86_app/Makefile b/board/efi/efi-x86_app/Makefile new file mode 100644 index 000000000000..682f8754b44d --- /dev/null +++ b/board/efi/efi-x86_app/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2023 Google LLC + +obj-y += efi_app.o diff --git a/board/efi/efi-x86_app/efi_app.c b/board/efi/efi-x86_app/efi_app.c new file mode 100644 index 000000000000..c5e4192fe06c --- /dev/null +++ b/board/efi/efi-x86_app/efi_app.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI-app board implementation + * + * Copyright 2023 Google LLC + * Written by Simon Glass sjg@chromium.org + */ + +#include <dm.h> +#include <efi.h> +#include <efi_api.h> +#include <errno.h> +#include <malloc.h> +#include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/root.h> +#include <linux/types.h> + +DECLARE_GLOBAL_DATA_PTR; + +/** + * efi_bind_block() - bind a new block device to an EFI device + * + * Binds a new top-level EFI_MEDIA device as well as a child block device so + * that the block device can be accessed in U-Boot. + * + * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1', + * for example, just like any other interface type. + * + * @handle: handle of the controller on which this driver is installed + * @blkio: block io protocol proxied by this driver + * @device_path: EFI device path structure for this + * @len: Length of @device_path in bytes + * @devp: Returns the bound device + * Return: 0 if OK, -ve on error + */ +int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, + struct efi_device_path *device_path, int len, + struct udevice **devp) +{ + struct efi_media_plat plat; + struct udevice *dev; + char name[18]; + int ret; + + plat.handle = handle; + plat.blkio = blkio; + plat.device_path = malloc(device_path->length); + if (!plat.device_path) + return log_msg_ret("path", -ENOMEM); + memcpy(plat.device_path, device_path, device_path->length); + ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media", + &plat, ofnode_null(), &dev); + if (ret) + return log_msg_ret("bind", ret); + + snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev)); + device_set_name(dev, name); + *devp = dev; + + return 0; +} + +/** + * devpath_is_partition() - Figure out if a device path is a partition + * + * Checks if a device path refers to a partition on some media device. This + * works by checking for a valid partition number in a hard-driver media device + * as the final component of the device path. + * + * @path: device path + * Return: true if a partition, false if not + * (e.g. it might be media which contains partitions) + */ +static bool devpath_is_partition(const struct efi_device_path *path) +{ + const struct efi_device_path *p; + bool was_part = false; + + for (p = path; p->type != DEVICE_PATH_TYPE_END; + p = (void *)p + p->length) { + was_part = false; + if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE && + p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) { + struct efi_device_path_hard_drive_path *hd = + (void *)path; + + if (hd->partition_number) + was_part = true; + } + } + + return was_part; +} + +/** + * setup_block() - Find all block devices and setup EFI devices for them + * + * Partitions are ignored, since U-Boot has partition handling. Errors with + * particular devices produce a warning but execution continues to try to + * find others. + * + * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP + * if a required protocol is not supported + */ +static int setup_block(void) +{ + efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID; + efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; + efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + struct efi_boot_services *boot = efi_get_boot(); + struct efi_device_path_utilities_protocol *util; + struct efi_device_path_to_text_protocol *text; + struct efi_device_path *path; + struct efi_block_io *blkio; + efi_uintn_t num_handles; + efi_handle_t *handle; + int ret, i; + + if (!boot) + return log_msg_ret("sys", -ENOSYS); + + /* Find all devices which support the block I/O protocol */ + ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL, + &num_handles, &handle); + if (ret) + return log_msg_ret("loc", -ENOTSUPP); + log_debug("Found %d handles:\n", (int)num_handles); + + /* We need to look up the path size and convert it to text */ + ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util); + if (ret) + return log_msg_ret("util", -ENOTSUPP); + ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text); + if (ret) + return log_msg_ret("text", -ENOTSUPP); + + for (i = 0; i < num_handles; i++) { + struct udevice *dev; + const u16 *name; + bool is_part; + int len; + + ret = boot->handle_protocol(handle[i], &efi_devpath_guid, + (void **)&path); + if (ret) { + log_warning("- devpath %d failed (ret=%d)\n", i, ret); + continue; + } + + ret = boot->handle_protocol(handle[i], &efi_blkio_guid, + (void **)&blkio); + if (ret) { + log_warning("- blkio %d failed (ret=%d)\n", i, ret); + continue; + } + + name = text->convert_device_path_to_text(path, true, false); + is_part = devpath_is_partition(path); + + if (!is_part) { + len = util->get_device_path_size(path); + ret = efi_bind_block(handle[i], blkio, path, len, &dev); + if (ret) { + log_warning("- blkio bind %d failed (ret=%d)\n", + i, ret); + continue; + } + } else { + dev = NULL; + } + + /* + * Show the device name if we created one. Otherwise indicate + * that it is a partition. + */ + printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>", + name); + } + boot->free_pool(handle); + + return 0; +} + +/** + * board_early_init_r() - Scan for UEFI devices that should be available + * + * This sets up block devices within U-Boot for those found in UEFI. With this, + * U-Boot can access those devices + * + * Returns: 0 on success, -ve on error + */ +int board_early_init_r(void) +{ + if (gd->flags & GD_FLG_RELOC) { + int ret; + + ret = setup_block(); + if (ret) + return ret; + } + + return 0; +} diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig index d6b6c3d82995..e6a62b30dd09 100644 --- a/configs/efi-x86_app64_defconfig +++ b/configs/efi-x86_app64_defconfig @@ -17,6 +17,7 @@ CONFIG_USE_BOOTCOMMAND=y CONFIG_BOOTCOMMAND="ext2load scsi 0:3 01000000 /boot/vmlinuz; zboot 01000000" CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_BOARD_EARLY_INIT_R=y CONFIG_HUSH_PARSER=y CONFIG_SYS_PBSIZE=532 CONFIG_CMD_BOOTZ=y diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index c5eb816655ea..e79fa5dad176 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -68,49 +68,6 @@ int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, return 0; }
-/** - * efi_bind_block() - bind a new block device to an EFI device - * - * Binds a new top-level EFI_MEDIA device as well as a child block device so - * that the block device can be accessed in U-Boot. - * - * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1', - * for example, just like any other interface type. - * - * @handle: handle of the controller on which this driver is installed - * @blkio: block io protocol proxied by this driver - * @device_path: EFI device path structure for this - * @len: Length of @device_path in bytes - * @devp: Returns the bound device - * Return: 0 if OK, -ve on error - */ -int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio, - struct efi_device_path *device_path, int len, - struct udevice **devp) -{ - struct efi_media_plat plat; - struct udevice *dev; - char name[18]; - int ret; - - plat.handle = handle; - plat.blkio = blkio; - plat.device_path = malloc(device_path->length); - if (!plat.device_path) - return log_msg_ret("path", -ENOMEM); - memcpy(plat.device_path, device_path, device_path->length); - ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media", - &plat, ofnode_null(), &dev); - if (ret) - return log_msg_ret("bind", ret); - - snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev)); - device_set_name(dev, name); - *devp = dev; - - return 0; -} - static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot; @@ -179,150 +136,6 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
-/** - * devpath_is_partition() - Figure out if a device path is a partition - * - * Checks if a device path refers to a partition on some media device. This - * works by checking for a valid partition number in a hard-driver media device - * as the final component of the device path. - * - * @path: device path - * Return: true if a partition, false if not - * (e.g. it might be media which contains partitions) - */ -static bool devpath_is_partition(const struct efi_device_path *path) -{ - const struct efi_device_path *p; - bool was_part = false; - - for (p = path; p->type != DEVICE_PATH_TYPE_END; - p = (void *)p + p->length) { - was_part = false; - if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE && - p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) { - struct efi_device_path_hard_drive_path *hd = - (void *)path; - - if (hd->partition_number) - was_part = true; - } - } - - return was_part; -} - -/** - * setup_block() - Find all block devices and setup EFI devices for them - * - * Partitions are ignored, since U-Boot has partition handling. Errors with - * particular devices produce a warning but execution continues to try to - * find others. - * - * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP - * if a required protocol is not supported - */ -static int setup_block(void) -{ - efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID; - efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID; - efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; - efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; - struct efi_boot_services *boot = efi_get_boot(); - struct efi_device_path_utilities_protocol *util; - struct efi_device_path_to_text_protocol *text; - struct efi_device_path *path; - struct efi_block_io *blkio; - efi_uintn_t num_handles; - efi_handle_t *handle; - int ret, i; - - if (!boot) - return log_msg_ret("sys", -ENOSYS); - - /* Find all devices which support the block I/O protocol */ - ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL, - &num_handles, &handle); - if (ret) - return log_msg_ret("loc", -ENOTSUPP); - log_debug("Found %d handles:\n", (int)num_handles); - - /* We need to look up the path size and convert it to text */ - ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util); - if (ret) - return log_msg_ret("util", -ENOTSUPP); - ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text); - if (ret) - return log_msg_ret("text", -ENOTSUPP); - - for (i = 0; i < num_handles; i++) { - struct udevice *dev; - const u16 *name; - bool is_part; - int len; - - ret = boot->handle_protocol(handle[i], &efi_devpath_guid, - (void **)&path); - if (ret) { - log_warning("- devpath %d failed (ret=%d)\n", i, ret); - continue; - } - - ret = boot->handle_protocol(handle[i], &efi_blkio_guid, - (void **)&blkio); - if (ret) { - log_warning("- blkio %d failed (ret=%d)\n", i, ret); - continue; - } - - name = text->convert_device_path_to_text(path, true, false); - is_part = devpath_is_partition(path); - - if (!is_part) { - len = util->get_device_path_size(path); - ret = efi_bind_block(handle[i], blkio, path, len, &dev); - if (ret) { - log_warning("- blkio bind %d failed (ret=%d)\n", - i, ret); - continue; - } - } else { - dev = NULL; - } - - /* - * Show the device name if we created one. Otherwise indicate - * that it is a partition. - */ - printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>", - name); - } - boot->free_pool(handle); - - return 0; -} - -/** - * dm_scan_other() - Scan for UEFI devices that should be available to U-Boot - * - * This sets up block devices within U-Boot for those found in UEFI. With this, - * U-Boot can access those devices - * - * @pre_reloc_only: true to only bind pre-relocation devices (ignored) - * Returns: 0 on success, -ve on error - */ -int dm_scan_other(bool pre_reloc_only) -{ - if (gd->flags & GD_FLG_RELOC) { - int ret; - - ret = setup_block(); - if (ret) - return ret; - } - - return 0; -} - static void scan_tables(struct efi_system_table *sys_table) { efi_guid_t acpi = EFI_ACPI_TABLE_GUID;

On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
Best regards
Heinrich
configs/efi-x86_app64_defconfig | 1 + lib/efi/efi_app.c | 187 ----------------------------- 4 files changed, 211 insertions(+), 187 deletions(-) create mode 100644 board/efi/efi-x86_app/Makefile create mode 100644 board/efi/efi-x86_app/efi_app.c
diff --git a/board/efi/efi-x86_app/Makefile b/board/efi/efi-x86_app/Makefile new file mode 100644 index 000000000000..682f8754b44d --- /dev/null +++ b/board/efi/efi-x86_app/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2023 Google LLC
+obj-y += efi_app.o diff --git a/board/efi/efi-x86_app/efi_app.c b/board/efi/efi-x86_app/efi_app.c new file mode 100644 index 000000000000..c5e4192fe06c --- /dev/null +++ b/board/efi/efi-x86_app/efi_app.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- EFI-app board implementation
- Copyright 2023 Google LLC
- Written by Simon Glass sjg@chromium.org
- */
+#include <dm.h> +#include <efi.h> +#include <efi_api.h> +#include <errno.h> +#include <malloc.h> +#include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/root.h> +#include <linux/types.h>
+DECLARE_GLOBAL_DATA_PTR;
+/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @device_path: EFI device path structure for this
- @len: Length of @device_path in bytes
- @devp: Returns the bound device
- Return: 0 if OK, -ve on error
- */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio,
struct efi_device_path *device_path, int len,
struct udevice **devp)
+{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
- plat.handle = handle;
- plat.blkio = blkio;
- plat.device_path = malloc(device_path->length);
- if (!plat.device_path)
return log_msg_ret("path", -ENOMEM);
- memcpy(plat.device_path, device_path, device_path->length);
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
- if (ret)
return log_msg_ret("bind", ret);
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- *devp = dev;
- return 0;
+}
+/**
- devpath_is_partition() - Figure out if a device path is a partition
- Checks if a device path refers to a partition on some media device. This
- works by checking for a valid partition number in a hard-driver media device
- as the final component of the device path.
- @path: device path
- Return: true if a partition, false if not
(e.g. it might be media which contains partitions)
- */
+static bool devpath_is_partition(const struct efi_device_path *path) +{
- const struct efi_device_path *p;
- bool was_part = false;
- for (p = path; p->type != DEVICE_PATH_TYPE_END;
p = (void *)p + p->length) {
was_part = false;
if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
struct efi_device_path_hard_drive_path *hd =
(void *)path;
if (hd->partition_number)
was_part = true;
}
- }
- return was_part;
+}
+/**
- setup_block() - Find all block devices and setup EFI devices for them
- Partitions are ignored, since U-Boot has partition handling. Errors with
- particular devices produce a warning but execution continues to try to
- find others.
- Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
- if a required protocol is not supported
- */
+static int setup_block(void) +{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
- efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_device_path_utilities_protocol *util;
- struct efi_device_path_to_text_protocol *text;
- struct efi_device_path *path;
- struct efi_block_io *blkio;
- efi_uintn_t num_handles;
- efi_handle_t *handle;
- int ret, i;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- /* Find all devices which support the block I/O protocol */
- ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL,
&num_handles, &handle);
- if (ret)
return log_msg_ret("loc", -ENOTSUPP);
- log_debug("Found %d handles:\n", (int)num_handles);
- /* We need to look up the path size and convert it to text */
- ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util);
- if (ret)
return log_msg_ret("util", -ENOTSUPP);
- ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text);
- if (ret)
return log_msg_ret("text", -ENOTSUPP);
- for (i = 0; i < num_handles; i++) {
struct udevice *dev;
const u16 *name;
bool is_part;
int len;
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&path);
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
(void **)&blkio);
if (ret) {
log_warning("- blkio %d failed (ret=%d)\n", i, ret);
continue;
}
name = text->convert_device_path_to_text(path, true, false);
is_part = devpath_is_partition(path);
if (!is_part) {
len = util->get_device_path_size(path);
ret = efi_bind_block(handle[i], blkio, path, len, &dev);
if (ret) {
log_warning("- blkio bind %d failed (ret=%d)\n",
i, ret);
continue;
}
} else {
dev = NULL;
}
/*
* Show the device name if we created one. Otherwise indicate
* that it is a partition.
*/
printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>",
name);
- }
- boot->free_pool(handle);
- return 0;
+}
+/**
- board_early_init_r() - Scan for UEFI devices that should be available
- This sets up block devices within U-Boot for those found in UEFI. With this,
- U-Boot can access those devices
- Returns: 0 on success, -ve on error
- */
+int board_early_init_r(void) +{
- if (gd->flags & GD_FLG_RELOC) {
int ret;
ret = setup_block();
if (ret)
return ret;
- }
- return 0;
+} diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig index d6b6c3d82995..e6a62b30dd09 100644 --- a/configs/efi-x86_app64_defconfig +++ b/configs/efi-x86_app64_defconfig @@ -17,6 +17,7 @@ CONFIG_USE_BOOTCOMMAND=y CONFIG_BOOTCOMMAND="ext2load scsi 0:3 01000000 /boot/vmlinuz; zboot 01000000" CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_DISPLAY_BOARDINFO_LATE=y +CONFIG_BOARD_EARLY_INIT_R=y CONFIG_HUSH_PARSER=y CONFIG_SYS_PBSIZE=532 CONFIG_CMD_BOOTZ=y diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c index c5eb816655ea..e79fa5dad176 100644 --- a/lib/efi/efi_app.c +++ b/lib/efi/efi_app.c @@ -68,49 +68,6 @@ int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, return 0; }
-/**
- efi_bind_block() - bind a new block device to an EFI device
- Binds a new top-level EFI_MEDIA device as well as a child block device so
- that the block device can be accessed in U-Boot.
- The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
- for example, just like any other interface type.
- @handle: handle of the controller on which this driver is installed
- @blkio: block io protocol proxied by this driver
- @device_path: EFI device path structure for this
- @len: Length of @device_path in bytes
- @devp: Returns the bound device
- Return: 0 if OK, -ve on error
- */
-int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio,
struct efi_device_path *device_path, int len,
struct udevice **devp)
-{
- struct efi_media_plat plat;
- struct udevice *dev;
- char name[18];
- int ret;
- plat.handle = handle;
- plat.blkio = blkio;
- plat.device_path = malloc(device_path->length);
- if (!plat.device_path)
return log_msg_ret("path", -ENOMEM);
- memcpy(plat.device_path, device_path, device_path->length);
- ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
&plat, ofnode_null(), &dev);
- if (ret)
return log_msg_ret("bind", ret);
- snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
- device_set_name(dev, name);
- *devp = dev;
- return 0;
-}
- static efi_status_t setup_memory(struct efi_priv *priv) { struct efi_boot_services *boot = priv->boot;
@@ -179,150 +136,6 @@ static void free_memory(struct efi_priv *priv) global_data_ptr = NULL; }
-/**
- devpath_is_partition() - Figure out if a device path is a partition
- Checks if a device path refers to a partition on some media device. This
- works by checking for a valid partition number in a hard-driver media device
- as the final component of the device path.
- @path: device path
- Return: true if a partition, false if not
(e.g. it might be media which contains partitions)
- */
-static bool devpath_is_partition(const struct efi_device_path *path) -{
- const struct efi_device_path *p;
- bool was_part = false;
- for (p = path; p->type != DEVICE_PATH_TYPE_END;
p = (void *)p + p->length) {
was_part = false;
if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
struct efi_device_path_hard_drive_path *hd =
(void *)path;
if (hd->partition_number)
was_part = true;
}
- }
- return was_part;
-}
-/**
- setup_block() - Find all block devices and setup EFI devices for them
- Partitions are ignored, since U-Boot has partition handling. Errors with
- particular devices produce a warning but execution continues to try to
- find others.
- Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
- if a required protocol is not supported
- */
-static int setup_block(void) -{
- efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
- efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
- efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
- efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
- struct efi_boot_services *boot = efi_get_boot();
- struct efi_device_path_utilities_protocol *util;
- struct efi_device_path_to_text_protocol *text;
- struct efi_device_path *path;
- struct efi_block_io *blkio;
- efi_uintn_t num_handles;
- efi_handle_t *handle;
- int ret, i;
- if (!boot)
return log_msg_ret("sys", -ENOSYS);
- /* Find all devices which support the block I/O protocol */
- ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL,
&num_handles, &handle);
- if (ret)
return log_msg_ret("loc", -ENOTSUPP);
- log_debug("Found %d handles:\n", (int)num_handles);
- /* We need to look up the path size and convert it to text */
- ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util);
- if (ret)
return log_msg_ret("util", -ENOTSUPP);
- ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text);
- if (ret)
return log_msg_ret("text", -ENOTSUPP);
- for (i = 0; i < num_handles; i++) {
struct udevice *dev;
const u16 *name;
bool is_part;
int len;
ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
(void **)&path);
if (ret) {
log_warning("- devpath %d failed (ret=%d)\n", i, ret);
continue;
}
ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
(void **)&blkio);
if (ret) {
log_warning("- blkio %d failed (ret=%d)\n", i, ret);
continue;
}
name = text->convert_device_path_to_text(path, true, false);
is_part = devpath_is_partition(path);
if (!is_part) {
len = util->get_device_path_size(path);
ret = efi_bind_block(handle[i], blkio, path, len, &dev);
if (ret) {
log_warning("- blkio bind %d failed (ret=%d)\n",
i, ret);
continue;
}
} else {
dev = NULL;
}
/*
* Show the device name if we created one. Otherwise indicate
* that it is a partition.
*/
printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>",
name);
- }
- boot->free_pool(handle);
- return 0;
-}
-/**
- dm_scan_other() - Scan for UEFI devices that should be available to U-Boot
- This sets up block devices within U-Boot for those found in UEFI. With this,
- U-Boot can access those devices
- @pre_reloc_only: true to only bind pre-relocation devices (ignored)
- Returns: 0 on success, -ve on error
- */
-int dm_scan_other(bool pre_reloc_only) -{
- if (gd->flags & GD_FLG_RELOC) {
int ret;
ret = setup_block();
if (ret)
return ret;
- }
- return 0;
-}
- static void scan_tables(struct efi_system_table *sys_table) { efi_guid_t acpi = EFI_ACPI_TABLE_GUID;

On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".

Hi,
On Tue, 21 Nov 2023 at 06:21, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".
This patch was marked as old /archived in patchwork so has been forgotten. I have marked it new and non-archived in the hope that it can be applied to -master soon.
I believe that having the EFI app support bootstd could be a useful addition.
Regards, Simon

On 12/16/23 21:46, Simon Glass wrote:
Hi,
On Tue, 21 Nov 2023 at 06:21, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".
I cannot see that this patch is moving any code our of lib/.
But why should we move generic code into board?
This patch was marked as old /archived in patchwork so has been forgotten. I have marked it new and non-archived in the hope that it can be applied to -master soon.
There is nothing x86 specific about the code. Generic code should be in lib/. Please, provide a new version of the patch.
I believe that having the EFI app support bootstd could be a useful addition.
That was not disputed.
Best regards
Heinrich

On Sat, Dec 16, 2023 at 09:57:41PM +0100, Heinrich Schuchardt wrote:
On 12/16/23 21:46, Simon Glass wrote:
Hi,
On Tue, 21 Nov 2023 at 06:21, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".
I cannot see that this patch is moving any code our of lib/.
But why should we move generic code into board?
This patch was marked as old /archived in patchwork so has been forgotten. I have marked it new and non-archived in the hope that it can be applied to -master soon.
There is nothing x86 specific about the code. Generic code should be in lib/. Please, provide a new version of the patch.
It's not generic EFI code, it's generic "U-Boot as EFI application" code and so the whole "board" needs a bit of a clean and re-work as we all agree that there shouldn't be anything architecture specific about it, only building the binary for the correct architecture. However, we just aren't well structured to support that right now. Where on the list of priorities does that have to fall rather than just allowing for functionality to be tested / used? There's not yet IIRC efi-arm64_app but what we have today (and would have had with Simon's patch) should have just built and worked.

Am 16. Dezember 2023 23:14:20 MEZ schrieb Tom Rini trini@konsulko.com:
On Sat, Dec 16, 2023 at 09:57:41PM +0100, Heinrich Schuchardt wrote:
On 12/16/23 21:46, Simon Glass wrote:
Hi,
On Tue, 21 Nov 2023 at 06:21, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".
I cannot see that this patch is moving any code our of lib/.
But why should we move generic code into board?
This patch was marked as old /archived in patchwork so has been forgotten. I have marked it new and non-archived in the hope that it can be applied to -master soon.
There is nothing x86 specific about the code. Generic code should be in lib/. Please, provide a new version of the patch.
It's not generic EFI code, it's generic "U-Boot as EFI application" code and so the whole "board" needs a bit of a clean and re-work as we all agree that there shouldn't be anything architecture specific about it, only building the binary for the correct architecture. However, we just aren't well structured to support that right now. Where on the list of priorities does that have to fall rather than just allowing for functionality to be tested / used? There's not yet IIRC efi-arm64_app but what we have today (and would have had with Simon's patch) should have just built and worked.
We have /lib/efi/ for that code.
Regards
Heinrich

Hi Heinrich,
On Sat, 16 Dec 2023 at 14:02, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 12/16/23 21:46, Simon Glass wrote:
Hi,
On Tue, 21 Nov 2023 at 06:21, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".
I cannot see that this patch is moving any code our of lib/.
But why should we move generic code into board?
It isn't really generic
This patch was marked as old /archived in patchwork so has been forgotten. I have marked it new and non-archived in the hope that it can be applied to -master soon.
There is nothing x86 specific about the code. Generic code should be in lib/. Please, provide a new version of the patch.
I believe that having the EFI app support bootstd could be a useful addition.
That was not disputed.
Best regards
Heinrich

Hi Heinrich,
On Mon, Dec 18, 2023 at 3:02 PM Simon Glass sjg@chromium.org wrote:
Hi Heinrich,
On Sat, 16 Dec 2023 at 14:02, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 12/16/23 21:46, Simon Glass wrote:
Hi,
On Tue, 21 Nov 2023 at 06:21, Tom Rini trini@konsulko.com wrote:
On Tue, Nov 21, 2023 at 01:18:09PM +0100, Heinrich Schuchardt wrote:
On 11/12/23 21:55, Simon Glass wrote:
This function is defined by bootstd so using it precludes using that feature. Use the board_early_init_r() feature instead.
This requires moving quite a lot of code into the board directory, butt this is the normal place for code called by board_early_init_r()
Signed-off-by: Simon Glass sjg@chromium.org
Changes in v2:
Drop duplicate acpi_xsdt patch
Put the board_early_init_r code into board/
board/efi/efi-x86_app/Makefile | 5 + board/efi/efi-x86_app/efi_app.c | 205 ++++++++++++++++++++++++++++++++
Our target should be to enable building the EFI app on all architectures.
Only x86 specific code should be added to board/efi/efi-x86_app/efi_app.c.
A later enhancement to make U-Boot as an EFI app more generic would be good, but outside the scope of this patch which is moving generic code out from "lib" and in to "board".
I cannot see that this patch is moving any code our of lib/.
But why should we move generic code into board?
It isn't really generic
This patch was marked as old /archived in patchwork so has been forgotten. I have marked it new and non-archived in the hope that it can be applied to -master soon.
There is nothing x86 specific about the code. Generic code should be in lib/. Please, provide a new version of the patch.
I believe that having the EFI app support bootstd could be a useful addition.
That was not disputed.
OK, I see now that your objection was putting it into board/ so I sent a new patch for that.
It is very strange to have board_early_init_r() calling code in lib though. We should think of a better way.
Regards, SImon
participants (4)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Simon Glass
-
Tom Rini