From 2ea957952362fe9238cbf3996c001f8bf3f04701 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 28 May 2025 10:03:14 -0600 Subject: efi: Rename the lib/efi directory This directory was created when U-Boot gained the ability to run as an EFI app in 2015. Since then the EFI-loader feature has been added. The code in lib/efi is not actually used by the loader, so the name is confusing. Rename the directory to efi_client to indicate that it includes files just for U-Boot being a client of EFI, i.e. the EFI app and stub. Signed-off-by: Simon Glass --- MAINTAINERS | 2 +- Makefile | 2 +- doc/develop/uefi/u-boot_on_efi.rst | 8 +- lib/Makefile | 2 +- lib/efi/Kconfig | 79 -------- lib/efi/Makefile | 17 -- lib/efi/efi.c | 208 -------------------- lib/efi/efi_app.c | 235 ----------------------- lib/efi/efi_app_init.c | 205 -------------------- lib/efi/efi_info.c | 46 ----- lib/efi/efi_stub.c | 376 ------------------------------------- lib/efi_client/Kconfig | 79 ++++++++ lib/efi_client/Makefile | 17 ++ lib/efi_client/efi.c | 208 ++++++++++++++++++++ lib/efi_client/efi_app.c | 235 +++++++++++++++++++++++ lib/efi_client/efi_app_init.c | 205 ++++++++++++++++++++ lib/efi_client/efi_info.c | 46 +++++ lib/efi_client/efi_stub.c | 376 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/Kconfig | 2 +- 19 files changed, 1174 insertions(+), 1174 deletions(-) delete mode 100644 lib/efi/Kconfig delete mode 100644 lib/efi/Makefile delete mode 100644 lib/efi/efi.c delete mode 100644 lib/efi/efi_app.c delete mode 100644 lib/efi/efi_app_init.c delete mode 100644 lib/efi/efi_info.c delete mode 100644 lib/efi/efi_stub.c create mode 100644 lib/efi_client/Kconfig create mode 100644 lib/efi_client/Makefile create mode 100644 lib/efi_client/efi.c create mode 100644 lib/efi_client/efi_app.c create mode 100644 lib/efi_client/efi_app_init.c create mode 100644 lib/efi_client/efi_info.c create mode 100644 lib/efi_client/efi_stub.c diff --git a/MAINTAINERS b/MAINTAINERS index d490b43c57f..3e555596a1c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1104,7 +1104,7 @@ F: configs/efi-x86_app* F: doc/develop/uefi/u-boot_on_efi.rst F: drivers/block/efi-media-uclass.c F: drivers/block/sb_efi_media.c -F: lib/efi/efi_app.c +F: lib/efi_client/ F: scripts/build-efi.sh F: test/dm/efi_media.c diff --git a/Makefile b/Makefile index 6a0251373c4..9c22b510333 100644 --- a/Makefile +++ b/Makefile @@ -1891,7 +1891,7 @@ u-boot-payload.lds: $(LDSCRIPT_EFI) FORCE quiet_cmd_u-boot_payload ?= LD $@ cmd_u-boot_payload ?= $(LD) $(LDFLAGS_EFI_PAYLOAD) -o $@ \ -T u-boot-payload.lds arch/x86/cpu/call32.o \ - lib/efi/efi.o lib/efi/efi_stub.o u-boot.bin.o \ + lib/efi_client/efi.o lib/efi_client/efi_stub.o u-boot.bin.o \ $(addprefix arch/$(ARCH)/lib/,$(EFISTUB)) u-boot-payload: u-boot.bin.o u-boot-payload.lds FORCE diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 245b4af1fa3..42e84c13049 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -113,7 +113,7 @@ implemented completely differently. EFI Application ~~~~~~~~~~~~~~~ For the application the whole of U-Boot is built as a shared library. The -efi_main() function is in lib/efi/efi_app.c. It sets up some basic EFI +efi_main() function is in lib/efi_client/efi_app.c. It sets up some basic EFI functions with efi_init(), sets up U-Boot global_data, allocates memory for U-Boot's malloc(), etc. and enters the normal init sequence (board_init_f() and board_init_r()). @@ -149,7 +149,7 @@ image (including device tree) into a small EFI stub application responsible for booting it. The stub application is built as a normal EFI application except that it has a lot of data attached to it. -The stub application is implemented in lib/efi/efi_stub.c. The efi_main() +The stub application is implemented in lib/efi_client/efi_stub.c. The efi_main() function is called by EFI. It is responsible for copying U-Boot from its original location into memory, disabling EFI boot services and starting U-Boot. U-Boot then starts as normal, relocates, starts all drivers, etc. @@ -192,7 +192,7 @@ careful to build the correct one so that your UEFI firmware can start it. Most UEFI images are 64-bit at present. The payload stub can be build as either 32- or 64-bits. Only a small amount -of code is built this way (see the extra- line in lib/efi/Makefile). +of code is built this way (see the extra- line in lib/efi_client/Makefile). Everything else is built as a normal U-Boot, so is always 32-bit on x86 at present. @@ -353,7 +353,7 @@ This work could be extended in a number of ways: Where is the code? ------------------ -lib/efi +lib/efi_client payload stub, application, support code. Mostly arch-neutral arch/x86/cpu/efi diff --git a/lib/Makefile b/lib/Makefile index 18ae0cd87bf..1dd738a7cd1 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ ifndef CONFIG_XPL_BUILD -obj-$(CONFIG_EFI) += efi/ +obj-$(CONFIG_EFI) += efi_client/ obj-$(CONFIG_EFI_LOADER) += efi_driver/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/ diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig deleted file mode 100644 index 81ed3e66b34..00000000000 --- a/lib/efi/Kconfig +++ /dev/null @@ -1,79 +0,0 @@ -menu "U-Boot as UEFI application" - depends on X86 - -config EFI - bool "Support running U-Boot from EFI" - depends on X86 - imply X86_TSC_READ_BASE - help - U-Boot can be started from EFI on certain platforms. This allows - EFI to perform most of the system init and then jump to U-Boot for - final system boot. Another option is to run U-Boot as an EFI - application, with U-Boot using EFI's drivers instead of its own. - -choice - prompt "Select EFI mode to use" - depends on X86 && EFI - -config EFI_APP - bool "Support running as an EFI application" - select CHARSET - help - Build U-Boot as an application which can be started from EFI. This - is useful for examining a platform in the early stages of porting - U-Boot to it. It allows only very basic functionality, such as a - command prompt and memory and I/O functions. Use 'reset' to return - to EFI. - -config EFI_STUB - bool "Support running as an EFI payload" - -endchoice - -choice - prompt "EFI app 32/64-bit selection" - depends on EFI_APP - help - EFI does not support mixing 32-bit and 64-bit modes. This is a - significant problem because it means that you must build a stub with - the correct type for EFI to load it correctly. If you are using - 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do - this may produce no error message - it just won't start! - -config EFI_APP_32BIT - bool "Produce an app for running with 32-bit EFI" - -config EFI_APP_64BIT - bool "Produce an app for running with 64-bit EFI" - -endchoice - -choice - prompt "EFI stub 32/64-bit selection" - depends on EFI_STUB - help - EFI does not support mixing 32-bit and 64-bit modes. This is a - significant problem because it means that you must build a stub with - the correct type for EFI to load it correctly. If you are using - 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do - this may produce no error message - it just won't start! - -config EFI_STUB_32BIT - bool "Produce a stub for running with 32-bit EFI" - -config EFI_STUB_64BIT - bool "Produce a stub for running with 64-bit EFI" - -endchoice - -config EFI_RAM_SIZE - hex "Amount of EFI RAM for U-Boot" - depends on EFI_APP - default 0x10000000 - help - Set the amount of EFI RAM which is claimed by U-Boot for its own - use. U-Boot allocates this from EFI on start-up (along with a few - other smaller amounts) and it can never be increased after that. - It is used as the RAM size in with U-Boot. - -endmenu diff --git a/lib/efi/Makefile b/lib/efi/Makefile deleted file mode 100644 index 232fa684360..00000000000 --- a/lib/efi/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# (C) Copyright 2015 Google, Inc - -obj-$(CONFIG_EFI_APP) += efi_app.o efi.o efi_app_init.o -obj-$(CONFIG_EFI_STUB) += efi_info.o - -CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \ - $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) -CFLAGS_efi_stub.o := -fpic -fshort-wchar \ - $(if $(CONFIG_EFI_STUB_64BIT),-m64) -CFLAGS_REMOVE_efi.o := -mregparm=3 \ - $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) -CFLAGS_efi.o := -fpic -fshort-wchar \ - $(if $(CONFIG_EFI_STUB_64BIT),-m64) - -extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o diff --git a/lib/efi/efi.c b/lib/efi/efi.c deleted file mode 100644 index bcb34d67465..00000000000 --- a/lib/efi/efi.c +++ /dev/null @@ -1,208 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Functions shared by the app and stub - * - * Copyright (c) 2015 Google, Inc - * - * EFI information obtained here: - * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES - * - * Common EFI functions - */ - -#include -#include -#include -#include -#include -#include -#include - -static struct efi_priv *global_priv; - -struct efi_priv *efi_get_priv(void) -{ - return global_priv; -} - -void efi_set_priv(struct efi_priv *priv) -{ - global_priv = priv; -} - -struct efi_system_table *efi_get_sys_table(void) -{ - return global_priv->sys_table; -} - -struct efi_boot_services *efi_get_boot(void) -{ - return global_priv->boot; -} - -unsigned long efi_get_ram_base(void) -{ - return global_priv->ram_base; -} - -/* - * Global declaration of gd. - * - * As we write to it before relocation we have to make sure it is not put into - * a .bss section which may overlap a .rela section. Initialization forces it - * into a .data section which cannot overlap any .rela section. - */ -struct global_data *global_data_ptr = (struct global_data *)~0; - -/* - * Unfortunately we cannot access any code outside what is built especially - * for the stub. lib/string.c is already being built for the U-Boot payload - * so it uses the wrong compiler flags. Add our own memset() here. - */ -static void efi_memset(void *ptr, int ch, int size) -{ - char *dest = ptr; - - while (size-- > 0) - *dest++ = ch; -} - -/* - * Since the EFI stub cannot access most of the U-Boot code, add our own - * simple console output functions here. The EFI app will not use these since - * it can use the normal console. - */ -void efi_putc(struct efi_priv *priv, const char ch) -{ - struct efi_simple_text_output_protocol *con = priv->sys_table->con_out; - uint16_t ucode[2]; - - ucode[0] = ch; - ucode[1] = '\0'; - con->output_string(con, ucode); -} - -void efi_puts(struct efi_priv *priv, const char *str) -{ - while (*str) - efi_putc(priv, *str++); -} - -int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, - struct efi_system_table *sys_table) -{ - efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; - struct efi_boot_services *boot = sys_table->boottime; - struct efi_loaded_image *loaded_image; - int ret; - - efi_memset(priv, '\0', sizeof(*priv)); - priv->sys_table = sys_table; - priv->boot = sys_table->boottime; - priv->parent_image = image; - priv->run = sys_table->runtime; - - efi_puts(priv, "U-Boot EFI "); - efi_puts(priv, banner); - efi_putc(priv, ' '); - - ret = boot->open_protocol(priv->parent_image, &loaded_image_guid, - (void **)&loaded_image, priv->parent_image, - NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); - if (ret) { - efi_puts(priv, "Failed to get loaded image protocol\n"); - return ret; - } - priv->image_data_type = loaded_image->image_data_type; - - return 0; -} - -void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp) -{ - struct efi_boot_services *boot = priv->boot; - void *buf = NULL; - - *retp = boot->allocate_pool(priv->image_data_type, size, &buf); - - return buf; -} - -void efi_free(struct efi_priv *priv, void *ptr) -{ - struct efi_boot_services *boot = priv->boot; - - boot->free_pool(ptr); -} - -int efi_store_memory_map(struct efi_priv *priv) -{ - struct efi_boot_services *boot = priv->sys_table->boottime; - efi_uintn_t size, desc_size; - efi_status_t ret; - - /* Get the memory map so we can switch off EFI */ - size = 0; - ret = boot->get_memory_map(&size, NULL, &priv->memmap_key, - &priv->memmap_desc_size, - &priv->memmap_version); - if (ret != EFI_BUFFER_TOO_SMALL) { - /* - * Note this function avoids using printf() since it is not - * available in the stub - */ - printhex2(EFI_BITS_PER_LONG); - putc(' '); - printhex2(ret); - puts(" No memory map\n"); - return ret; - } - /* - * Since doing a malloc() may change the memory map and also we want to - * be able to read the memory map in efi_call_exit_boot_services() - * below, after more changes have happened - */ - priv->memmap_alloc = size + 1024; - priv->memmap_size = priv->memmap_alloc; - priv->memmap_desc = efi_malloc(priv, size, &ret); - if (!priv->memmap_desc) { - printhex2(ret); - puts(" No memory for memory descriptor\n"); - return ret; - } - - ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc, - &priv->memmap_key, &desc_size, - &priv->memmap_version); - if (ret) { - printhex2(ret); - puts(" Can't get memory map\n"); - return ret; - } - - return 0; -} - -int efi_call_exit_boot_services(void) -{ - struct efi_priv *priv = efi_get_priv(); - const struct efi_boot_services *boot = priv->boot; - efi_uintn_t size; - u32 version; - efi_status_t ret; - - size = priv->memmap_alloc; - ret = boot->get_memory_map(&size, priv->memmap_desc, - &priv->memmap_key, - &priv->memmap_desc_size, &version); - if (ret) { - printhex2(ret); - puts(" Can't get memory map\n"); - return ret; - } - ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key); - if (ret) - return ret; - - return 0; -} diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c deleted file mode 100644 index 9b94a93ee4f..00000000000 --- a/lib/efi/efi_app.c +++ /dev/null @@ -1,235 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2015 Google, Inc - * - * EFI information obtained here: - * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES - * - * This file implements U-Boot running as an EFI application. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -DECLARE_GLOBAL_DATA_PTR; - -int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) -{ - return -ENOSYS; -} - -int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, - int *desc_sizep, uint *versionp) -{ - struct efi_priv *priv = efi_get_priv(); - struct efi_boot_services *boot = priv->sys_table->boottime; - efi_uintn_t size, desc_size, key; - struct efi_mem_desc *desc; - efi_status_t ret; - u32 version; - - /* Get the memory map so we can switch off EFI */ - size = 0; - ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); - if (ret != EFI_BUFFER_TOO_SMALL) - return log_msg_ret("get", -ENOMEM); - - desc = malloc(size); - if (!desc) - return log_msg_ret("mem", -ENOMEM); - - ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); - if (ret) - return log_msg_ret("get", -EINVAL); - - *descp = desc; - *sizep = size; - *desc_sizep = desc_size; - *versionp = version; - *keyp = key; - - return 0; -} - -static efi_status_t setup_memory(struct efi_priv *priv) -{ - struct efi_boot_services *boot = priv->boot; - efi_physical_addr_t addr; - efi_status_t ret; - int pages; - - /* - * Use global_data_ptr instead of gd since it is an assignment. There - * are very few assignments to global_data in U-Boot and this makes - * it easier to find them. - */ - global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret); - if (!global_data_ptr) - return ret; - memset(gd, '\0', sizeof(*gd)); - - gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_VAL(SYS_MALLOC_F_LEN), - &ret); - if (!gd->malloc_base) - return ret; - pages = CONFIG_EFI_RAM_SIZE >> 12; - - /* - * Don't allocate any memory above 4GB. U-Boot is a 32-bit application - * so we want it to load below 4GB. - */ - addr = 1ULL << 32; - ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - priv->image_data_type, pages, &addr); - if (ret) { - log_info("(using pool %lx) ", ret); - priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, - &ret); - if (!priv->ram_base) - return ret; - priv->use_pool_for_malloc = true; - } else { - log_info("(using allocated RAM address %lx) ", (ulong)addr); - priv->ram_base = addr; - } - gd->ram_size = pages << 12; - - return 0; -} - -/** - * free_memory() - Free memory used by the U-Boot app - * - * This frees memory allocated in setup_memory(), in preparation for returning - * to UEFI. It also zeroes the global_data pointer. - * - * @priv: Private EFI data - */ -static void free_memory(struct efi_priv *priv) -{ - struct efi_boot_services *boot = priv->boot; - - if (priv->use_pool_for_malloc) - efi_free(priv, (void *)priv->ram_base); - else - boot->free_pages(priv->ram_base, gd->ram_size >> 12); - - efi_free(priv, (void *)gd->malloc_base); - efi_free(priv, gd); - global_data_ptr = NULL; -} - -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 - * - * This function is called by our EFI start-up code. It handles running - * U-Boot. If it returns, EFI will continue. Another way to get back to EFI - * is via reset_cpu(). - */ -efi_status_t EFIAPI efi_main(efi_handle_t image, - struct efi_system_table *sys_table) -{ - struct efi_priv local_priv, *priv = &local_priv; - efi_status_t ret; - - /* Set up access to EFI data structures */ - ret = efi_init(priv, "App", image, sys_table); - if (ret) { - printf("Failed to set up U-Boot: err=%lx\n", ret); - return ret; - } - efi_set_priv(priv); - - /* - * Set up the EFI debug UART so that printf() works. This is - * implemented in the EFI serial driver, serial_efi.c. The application - * can use printf() freely. - */ - debug_uart_init(); - - ret = setup_memory(priv); - if (ret) { - printf("Failed to set up memory: ret=%lx\n", ret); - 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. - * - * ret = efi_store_memory_map(priv); - * if (ret) - * return ret; - */ - - printf("starting\n"); - - board_init_f(GD_FLG_SKIP_RELOC); - board_init_r(NULL, 0); - free_memory(priv); - - return EFI_SUCCESS; -} - -static void efi_exit(void) -{ - struct efi_priv *priv = efi_get_priv(); - - free_memory(priv); - printf("U-Boot EFI exiting\n"); - priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); -} - -static int efi_sysreset_request(struct udevice *dev, enum sysreset_t type) -{ - efi_exit(); - - return -EINPROGRESS; -} - -static const struct udevice_id efi_sysreset_ids[] = { - { .compatible = "efi,reset" }, - { } -}; - -static struct sysreset_ops efi_sysreset_ops = { - .request = efi_sysreset_request, -}; - -U_BOOT_DRIVER(efi_sysreset) = { - .name = "efi-sysreset", - .id = UCLASS_SYSRESET, - .of_match = efi_sysreset_ids, - .ops = &efi_sysreset_ops, -}; diff --git a/lib/efi/efi_app_init.c b/lib/efi/efi_app_init.c deleted file mode 100644 index c5e4192fe06..00000000000 --- a/lib/efi/efi_app_init.c +++ /dev/null @@ -1,205 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * EFI-app board implementation - * - * Copyright 2023 Google LLC - * Written by Simon Glass - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 : "", - 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/lib/efi/efi_info.c b/lib/efi/efi_info.c deleted file mode 100644 index 5b564c5651d..00000000000 --- a/lib/efi/efi_info.c +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2015 Google, Inc - * - * Access to the EFI information table - */ - -#include -#include -#include -#include - -int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) -{ - struct efi_entry_hdr *entry; - struct efi_info_hdr *info; - int ret; - - if (!gd->arch.table) - return -ENODATA; - - info = map_sysmem(gd->arch.table, 0); - if (info->version != EFI_TABLE_VERSION) { - ret = -EPROTONOSUPPORT; - goto err; - } - - entry = (struct efi_entry_hdr *)((ulong)info + info->hdr_size); - while (entry->type != EFIET_END) { - if (entry->type == type) { - if (entry->addr) - *datap = map_sysmem(entry->addr, entry->size); - else - *datap = entry + 1; - *sizep = entry->size; - return 0; - } - entry = (struct efi_entry_hdr *)((ulong)entry + entry->link); - } - - ret = -ENOENT; -err: - unmap_sysmem(info); - - return ret; -} diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c deleted file mode 100644 index a083c7f1e9b..00000000000 --- a/lib/efi/efi_stub.c +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2015 Google, Inc - * - * EFI information obtained here: - * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES - * - * Loads a payload (U-Boot) within the EFI environment. This is built as an - * EFI application. It can be built either in 32-bit or 64-bit mode. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_X86 -/* - * Problem areas: - * - putc() uses the ns16550 address directly and assumed I/O access. Many - * platforms will use memory access - * get_codeseg32() is only meaningful on x86 - */ -#error "This file needs to be ported for use on architectures" -#endif - -static bool use_uart; - -struct __packed desctab_info { - uint16_t limit; - uint64_t addr; - uint16_t pad; -}; - -/* - * EFI uses Unicode and we don't. The easiest way to get a sensible output - * function is to use the U-Boot debug UART. We use EFI's console output - * function where available, and assume the built-in UART after that. We rely - * on EFI to set up the UART for us and just bring in the functions here. - * This last bit is a bit icky, but it's only for debugging anyway. We could - * build in ns16550.c with some effort, but this is a payload loader after - * all. - * - * Note: We avoid using printf() so we don't need to bring in lib/vsprintf.c. - * That would require some refactoring since we already build this for U-Boot. - * Building an EFI shared library version would have to be a separate stem. - * That might push us to using the SPL framework to build this stub. However - * that would involve a round of EFI-specific changes in SPL. Worth - * considering if we start needing more U-Boot functionality. Note that we - * could then move get_codeseg32() to arch/x86/cpu/cpu.c. - */ -void _debug_uart_init(void) -{ -} - -void putc(const char ch) -{ - struct efi_priv *priv = efi_get_priv(); - - if (ch == '\n') - putc('\r'); - - if (use_uart) { - struct ns16550 *com_port = (struct ns16550 *)0x3f8; - - while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0) - ; - outb(ch, (ulong)&com_port->thr); - } else { - efi_putc(priv, ch); - } -} - -void puts(const char *str) -{ - while (*str) - putc(*str++); -} - -static inline void _debug_uart_putc(int ch) -{ - putc(ch); -} - -DEBUG_UART_FUNCS - -void *memcpy(void *dest, const void *src, size_t size) -{ - unsigned char *dptr = dest; - const unsigned char *ptr = src; - const unsigned char *end = src + size; - - while (ptr < end) - *dptr++ = *ptr++; - - return dest; -} - -void *memset(void *inptr, int ch, size_t size) -{ - char *ptr = inptr; - char *end = ptr + size; - - while (ptr < end) - *ptr++ = ch; - - return ptr; -} - -static void jump_to_uboot(ulong cs32, ulong addr, ulong info) -{ -#ifdef CONFIG_EFI_STUB_32BIT - /* - * U-Boot requires these parameters in registers, not on the stack. - * See _x86boot_start() for this code. - */ - typedef void (*func_t)(int bist, int unused, ulong info) - __attribute__((regparm(3))); - - ((func_t)addr)(0, 0, info); -#else - cpu_call32(cs32, CONFIG_TEXT_BASE, info); -#endif -} - -#ifdef CONFIG_EFI_STUB_64BIT -static void get_gdt(struct desctab_info *info) -{ - asm volatile ("sgdt %0" : : "m"(*info) : "memory"); -} -#endif - -static inline unsigned long read_cr3(void) -{ - unsigned long val; - - asm volatile("mov %%cr3,%0" : "=r" (val) : : "memory"); - return val; -} - -/** - * get_codeseg32() - Find the code segment to use for 32-bit code - * - * U-Boot only works in 32-bit mode at present, so when booting from 64-bit - * EFI we must first change to 32-bit mode. To do this we need to find the - * correct code segment to use (an entry in the Global Descriptor Table). - * - * Return: code segment GDT offset, or 0 for 32-bit EFI, -ENOENT if not found - */ -static int get_codeseg32(void) -{ - int cs32 = 0; - -#ifdef CONFIG_EFI_STUB_64BIT - struct desctab_info gdt; - uint64_t *ptr; - int i; - - get_gdt(&gdt); - for (ptr = (uint64_t *)(unsigned long)gdt.addr, i = 0; i < gdt.limit; - i += 8, ptr++) { - uint64_t desc = *ptr; - uint64_t base, limit; - - /* - * Check that the target U-Boot jump address is within the - * selector and that the selector is of the right type. - */ - base = ((desc >> GDT_BASE_LOW_SHIFT) & GDT_BASE_LOW_MASK) | - ((desc >> GDT_BASE_HIGH_SHIFT) & GDT_BASE_HIGH_MASK) - << 16; - limit = ((desc >> GDT_LIMIT_LOW_SHIFT) & GDT_LIMIT_LOW_MASK) | - ((desc >> GDT_LIMIT_HIGH_SHIFT) & GDT_LIMIT_HIGH_MASK) - << 16; - base <<= 12; /* 4KB granularity */ - limit <<= 12; - if ((desc & GDT_PRESENT) && (desc & GDT_NOTSYS) && - !(desc & GDT_LONG) && (desc & GDT_4KB) && - (desc & GDT_32BIT) && (desc & GDT_CODE) && - CONFIG_TEXT_BASE > base && - CONFIG_TEXT_BASE + CONFIG_SYS_MONITOR_LEN < limit - ) { - cs32 = i; - break; - } - } - -#ifdef DEBUG - puts("\ngdt: "); - printhex8(gdt.limit); - puts(", addr: "); - printhex8(gdt.addr >> 32); - printhex8(gdt.addr); - for (i = 0; i < gdt.limit; i += 8) { - uint32_t *ptr = (uint32_t *)((unsigned long)gdt.addr + i); - - puts("\n"); - printhex2(i); - puts(": "); - printhex8(ptr[1]); - puts(" "); - printhex8(ptr[0]); - } - puts("\n "); - puts("32-bit code segment: "); - printhex2(cs32); - puts("\n "); - - puts("page_table: "); - printhex8(read_cr3()); - puts("\n "); -#endif - if (!cs32) { - puts("Can't find 32-bit code segment\n"); - return -ENOENT; - } -#endif - - return cs32; -} - -/** - * setup_info_table() - sets up a table containing information from EFI - * - * We must call exit_boot_services() before jumping out of the stub into U-Boot - * proper, so that U-Boot has full control of peripherals, memory, etc. - * - * Once we do this, we cannot call any boot-services functions so we must find - * out everything we need to before doing that. - * - * Set up a struct efi_info_hdr table which can hold various records (e.g. - * struct efi_entry_memmap) with information obtained from EFI. - * - * @priv: Pointer to our private information which contains the list - * @size: Size of the table to allocate - * Return: 0 if OK, non-zero on error - */ -static int setup_info_table(struct efi_priv *priv, int size) -{ - struct efi_info_hdr *info; - efi_status_t ret; - - /* Get some memory for our info table */ - priv->info_size = size; - info = efi_malloc(priv, priv->info_size, &ret); - if (ret) { - printhex2(ret); - puts(" No memory for info table: "); - return ret; - } - - memset(info, '\0', sizeof(*info)); - info->version = EFI_TABLE_VERSION; - info->hdr_size = sizeof(*info); - priv->info = info; - priv->next_hdr = (char *)info + info->hdr_size; - - return 0; -} - -/** - * add_entry_addr() - Add a new entry to the efi_info list - * - * This adds an entry, consisting of a tag and two lots of data. This avoids the - * caller having to coalesce the data first - * - * @priv: Pointer to our private information which contains the list - * @type: Type of the entry to add - * @ptr1: Pointer to first data block to add - * @size1: Size of first data block in bytes (can be 0) - * @ptr2: Pointer to second data block to add - * @size2: Size of second data block in bytes (can be 0) - */ -static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, - void *ptr1, int size1, void *ptr2, int size2) -{ - struct efi_entry_hdr *hdr = priv->next_hdr; - - hdr->type = type; - hdr->size = size1 + size2; - hdr->addr = 0; - hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16); - priv->next_hdr += hdr->link; - memcpy(hdr + 1, ptr1, size1); - memcpy((void *)(hdr + 1) + size1, ptr2, size2); - priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info; -} - -/** - * efi_main() - Start an EFI image - * - * This function is called by our EFI start-up code. It handles running - * U-Boot. If it returns, EFI will continue. - */ -efi_status_t EFIAPI efi_main(efi_handle_t image, - struct efi_system_table *sys_table) -{ - struct efi_priv local_priv, *priv = &local_priv; - struct efi_boot_services *boot = sys_table->boottime; - struct efi_entry_memmap map; - struct efi_gop *gop; - struct efi_entry_gopmode mode; - struct efi_entry_systable table; - efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; - efi_status_t ret; - int cs32; - - ret = efi_init(priv, "Payload", image, sys_table); - if (ret) { - printhex2(ret); - puts(" efi_init() failed\n"); - return ret; - } - efi_set_priv(priv); - - cs32 = get_codeseg32(); - if (cs32 < 0) - return EFI_UNSUPPORTED; - - ret = efi_store_memory_map(priv); - if (ret) - return ret; - - ret = setup_info_table(priv, priv->memmap_size + 128); - if (ret) - return ret; - - ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); - if (ret) { - puts(" GOP unavailable\n"); - } else { - mode.fb_base = gop->mode->fb_base; - mode.fb_size = gop->mode->fb_size; - mode.info_size = gop->mode->info_size; - add_entry_addr(priv, EFIET_GOP_MODE, &mode, sizeof(mode), - gop->mode->info, - sizeof(struct efi_gop_mode_info)); - } - - table.sys_table = (ulong)sys_table; - add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0); - - ret = efi_call_exit_boot_services(); - if (ret) - return ret; - - /* The EFI UART won't work now, switch to a debug one */ - use_uart = true; - - map.version = priv->memmap_version; - map.desc_size = priv->memmap_desc_size; - add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), - priv->memmap_desc, priv->memmap_size); - add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); - - memcpy((void *)CONFIG_TEXT_BASE, _binary_u_boot_bin_start, - (ulong)_binary_u_boot_bin_end - - (ulong)_binary_u_boot_bin_start); - -#ifdef DEBUG - puts("EFI table at "); - printhex8((ulong)priv->info); - puts(" size "); - printhex8(priv->info->total_size); -#endif - putc('\n'); - jump_to_uboot(cs32, CONFIG_TEXT_BASE, (ulong)priv->info); - - return EFI_LOAD_ERROR; -} diff --git a/lib/efi_client/Kconfig b/lib/efi_client/Kconfig new file mode 100644 index 00000000000..81ed3e66b34 --- /dev/null +++ b/lib/efi_client/Kconfig @@ -0,0 +1,79 @@ +menu "U-Boot as UEFI application" + depends on X86 + +config EFI + bool "Support running U-Boot from EFI" + depends on X86 + imply X86_TSC_READ_BASE + help + U-Boot can be started from EFI on certain platforms. This allows + EFI to perform most of the system init and then jump to U-Boot for + final system boot. Another option is to run U-Boot as an EFI + application, with U-Boot using EFI's drivers instead of its own. + +choice + prompt "Select EFI mode to use" + depends on X86 && EFI + +config EFI_APP + bool "Support running as an EFI application" + select CHARSET + help + Build U-Boot as an application which can be started from EFI. This + is useful for examining a platform in the early stages of porting + U-Boot to it. It allows only very basic functionality, such as a + command prompt and memory and I/O functions. Use 'reset' to return + to EFI. + +config EFI_STUB + bool "Support running as an EFI payload" + +endchoice + +choice + prompt "EFI app 32/64-bit selection" + depends on EFI_APP + help + EFI does not support mixing 32-bit and 64-bit modes. This is a + significant problem because it means that you must build a stub with + the correct type for EFI to load it correctly. If you are using + 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do + this may produce no error message - it just won't start! + +config EFI_APP_32BIT + bool "Produce an app for running with 32-bit EFI" + +config EFI_APP_64BIT + bool "Produce an app for running with 64-bit EFI" + +endchoice + +choice + prompt "EFI stub 32/64-bit selection" + depends on EFI_STUB + help + EFI does not support mixing 32-bit and 64-bit modes. This is a + significant problem because it means that you must build a stub with + the correct type for EFI to load it correctly. If you are using + 32-bit EFI, select 32-bit here, else select 64-bit. Failure to do + this may produce no error message - it just won't start! + +config EFI_STUB_32BIT + bool "Produce a stub for running with 32-bit EFI" + +config EFI_STUB_64BIT + bool "Produce a stub for running with 64-bit EFI" + +endchoice + +config EFI_RAM_SIZE + hex "Amount of EFI RAM for U-Boot" + depends on EFI_APP + default 0x10000000 + help + Set the amount of EFI RAM which is claimed by U-Boot for its own + use. U-Boot allocates this from EFI on start-up (along with a few + other smaller amounts) and it can never be increased after that. + It is used as the RAM size in with U-Boot. + +endmenu diff --git a/lib/efi_client/Makefile b/lib/efi_client/Makefile new file mode 100644 index 00000000000..232fa684360 --- /dev/null +++ b/lib/efi_client/Makefile @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# (C) Copyright 2015 Google, Inc + +obj-$(CONFIG_EFI_APP) += efi_app.o efi.o efi_app_init.o +obj-$(CONFIG_EFI_STUB) += efi_info.o + +CFLAGS_REMOVE_efi_stub.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +CFLAGS_efi_stub.o := -fpic -fshort-wchar \ + $(if $(CONFIG_EFI_STUB_64BIT),-m64) +CFLAGS_REMOVE_efi.o := -mregparm=3 \ + $(if $(CONFIG_EFI_STUB_64BIT),-march=i386 -m32) +CFLAGS_efi.o := -fpic -fshort-wchar \ + $(if $(CONFIG_EFI_STUB_64BIT),-m64) + +extra-$(CONFIG_EFI_STUB) += efi_stub.o efi.o diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c new file mode 100644 index 00000000000..bcb34d67465 --- /dev/null +++ b/lib/efi_client/efi.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Functions shared by the app and stub + * + * Copyright (c) 2015 Google, Inc + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * Common EFI functions + */ + +#include +#include +#include +#include +#include +#include +#include + +static struct efi_priv *global_priv; + +struct efi_priv *efi_get_priv(void) +{ + return global_priv; +} + +void efi_set_priv(struct efi_priv *priv) +{ + global_priv = priv; +} + +struct efi_system_table *efi_get_sys_table(void) +{ + return global_priv->sys_table; +} + +struct efi_boot_services *efi_get_boot(void) +{ + return global_priv->boot; +} + +unsigned long efi_get_ram_base(void) +{ + return global_priv->ram_base; +} + +/* + * Global declaration of gd. + * + * As we write to it before relocation we have to make sure it is not put into + * a .bss section which may overlap a .rela section. Initialization forces it + * into a .data section which cannot overlap any .rela section. + */ +struct global_data *global_data_ptr = (struct global_data *)~0; + +/* + * Unfortunately we cannot access any code outside what is built especially + * for the stub. lib/string.c is already being built for the U-Boot payload + * so it uses the wrong compiler flags. Add our own memset() here. + */ +static void efi_memset(void *ptr, int ch, int size) +{ + char *dest = ptr; + + while (size-- > 0) + *dest++ = ch; +} + +/* + * Since the EFI stub cannot access most of the U-Boot code, add our own + * simple console output functions here. The EFI app will not use these since + * it can use the normal console. + */ +void efi_putc(struct efi_priv *priv, const char ch) +{ + struct efi_simple_text_output_protocol *con = priv->sys_table->con_out; + uint16_t ucode[2]; + + ucode[0] = ch; + ucode[1] = '\0'; + con->output_string(con, ucode); +} + +void efi_puts(struct efi_priv *priv, const char *str) +{ + while (*str) + efi_putc(priv, *str++); +} + +int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, + struct efi_system_table *sys_table) +{ + efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_loaded_image *loaded_image; + int ret; + + efi_memset(priv, '\0', sizeof(*priv)); + priv->sys_table = sys_table; + priv->boot = sys_table->boottime; + priv->parent_image = image; + priv->run = sys_table->runtime; + + efi_puts(priv, "U-Boot EFI "); + efi_puts(priv, banner); + efi_putc(priv, ' '); + + ret = boot->open_protocol(priv->parent_image, &loaded_image_guid, + (void **)&loaded_image, priv->parent_image, + NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret) { + efi_puts(priv, "Failed to get loaded image protocol\n"); + return ret; + } + priv->image_data_type = loaded_image->image_data_type; + + return 0; +} + +void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp) +{ + struct efi_boot_services *boot = priv->boot; + void *buf = NULL; + + *retp = boot->allocate_pool(priv->image_data_type, size, &buf); + + return buf; +} + +void efi_free(struct efi_priv *priv, void *ptr) +{ + struct efi_boot_services *boot = priv->boot; + + boot->free_pool(ptr); +} + +int efi_store_memory_map(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size; + efi_status_t ret; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &priv->memmap_key, + &priv->memmap_desc_size, + &priv->memmap_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + /* + * Note this function avoids using printf() since it is not + * available in the stub + */ + printhex2(EFI_BITS_PER_LONG); + putc(' '); + printhex2(ret); + puts(" No memory map\n"); + return ret; + } + /* + * Since doing a malloc() may change the memory map and also we want to + * be able to read the memory map in efi_call_exit_boot_services() + * below, after more changes have happened + */ + priv->memmap_alloc = size + 1024; + priv->memmap_size = priv->memmap_alloc; + priv->memmap_desc = efi_malloc(priv, size, &ret); + if (!priv->memmap_desc) { + printhex2(ret); + puts(" No memory for memory descriptor\n"); + return ret; + } + + ret = boot->get_memory_map(&priv->memmap_size, priv->memmap_desc, + &priv->memmap_key, &desc_size, + &priv->memmap_version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + + return 0; +} + +int efi_call_exit_boot_services(void) +{ + struct efi_priv *priv = efi_get_priv(); + const struct efi_boot_services *boot = priv->boot; + efi_uintn_t size; + u32 version; + efi_status_t ret; + + size = priv->memmap_alloc; + ret = boot->get_memory_map(&size, priv->memmap_desc, + &priv->memmap_key, + &priv->memmap_desc_size, &version); + if (ret) { + printhex2(ret); + puts(" Can't get memory map\n"); + return ret; + } + ret = boot->exit_boot_services(priv->parent_image, priv->memmap_key); + if (ret) + return ret; + + return 0; +} diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c new file mode 100644 index 00000000000..9b94a93ee4f --- /dev/null +++ b/lib/efi_client/efi_app.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2015 Google, Inc + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * This file implements U-Boot running as an EFI application. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +{ + return -ENOSYS; +} + +int efi_get_mmap(struct efi_mem_desc **descp, int *sizep, uint *keyp, + int *desc_sizep, uint *versionp) +{ + struct efi_priv *priv = efi_get_priv(); + struct efi_boot_services *boot = priv->sys_table->boottime; + efi_uintn_t size, desc_size, key; + struct efi_mem_desc *desc; + efi_status_t ret; + u32 version; + + /* Get the memory map so we can switch off EFI */ + size = 0; + ret = boot->get_memory_map(&size, NULL, &key, &desc_size, &version); + if (ret != EFI_BUFFER_TOO_SMALL) + return log_msg_ret("get", -ENOMEM); + + desc = malloc(size); + if (!desc) + return log_msg_ret("mem", -ENOMEM); + + ret = boot->get_memory_map(&size, desc, &key, &desc_size, &version); + if (ret) + return log_msg_ret("get", -EINVAL); + + *descp = desc; + *sizep = size; + *desc_sizep = desc_size; + *versionp = version; + *keyp = key; + + return 0; +} + +static efi_status_t setup_memory(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->boot; + efi_physical_addr_t addr; + efi_status_t ret; + int pages; + + /* + * Use global_data_ptr instead of gd since it is an assignment. There + * are very few assignments to global_data in U-Boot and this makes + * it easier to find them. + */ + global_data_ptr = efi_malloc(priv, sizeof(struct global_data), &ret); + if (!global_data_ptr) + return ret; + memset(gd, '\0', sizeof(*gd)); + + gd->malloc_base = (ulong)efi_malloc(priv, CONFIG_VAL(SYS_MALLOC_F_LEN), + &ret); + if (!gd->malloc_base) + return ret; + pages = CONFIG_EFI_RAM_SIZE >> 12; + + /* + * Don't allocate any memory above 4GB. U-Boot is a 32-bit application + * so we want it to load below 4GB. + */ + addr = 1ULL << 32; + ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, + priv->image_data_type, pages, &addr); + if (ret) { + log_info("(using pool %lx) ", ret); + priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE, + &ret); + if (!priv->ram_base) + return ret; + priv->use_pool_for_malloc = true; + } else { + log_info("(using allocated RAM address %lx) ", (ulong)addr); + priv->ram_base = addr; + } + gd->ram_size = pages << 12; + + return 0; +} + +/** + * free_memory() - Free memory used by the U-Boot app + * + * This frees memory allocated in setup_memory(), in preparation for returning + * to UEFI. It also zeroes the global_data pointer. + * + * @priv: Private EFI data + */ +static void free_memory(struct efi_priv *priv) +{ + struct efi_boot_services *boot = priv->boot; + + if (priv->use_pool_for_malloc) + efi_free(priv, (void *)priv->ram_base); + else + boot->free_pages(priv->ram_base, gd->ram_size >> 12); + + efi_free(priv, (void *)gd->malloc_base); + efi_free(priv, gd); + global_data_ptr = NULL; +} + +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 + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. Another way to get back to EFI + * is via reset_cpu(). + */ +efi_status_t EFIAPI efi_main(efi_handle_t image, + struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + efi_status_t ret; + + /* Set up access to EFI data structures */ + ret = efi_init(priv, "App", image, sys_table); + if (ret) { + printf("Failed to set up U-Boot: err=%lx\n", ret); + return ret; + } + efi_set_priv(priv); + + /* + * Set up the EFI debug UART so that printf() works. This is + * implemented in the EFI serial driver, serial_efi.c. The application + * can use printf() freely. + */ + debug_uart_init(); + + ret = setup_memory(priv); + if (ret) { + printf("Failed to set up memory: ret=%lx\n", ret); + 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. + * + * ret = efi_store_memory_map(priv); + * if (ret) + * return ret; + */ + + printf("starting\n"); + + board_init_f(GD_FLG_SKIP_RELOC); + board_init_r(NULL, 0); + free_memory(priv); + + return EFI_SUCCESS; +} + +static void efi_exit(void) +{ + struct efi_priv *priv = efi_get_priv(); + + free_memory(priv); + printf("U-Boot EFI exiting\n"); + priv->boot->exit(priv->parent_image, EFI_SUCCESS, 0, NULL); +} + +static int efi_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + efi_exit(); + + return -EINPROGRESS; +} + +static const struct udevice_id efi_sysreset_ids[] = { + { .compatible = "efi,reset" }, + { } +}; + +static struct sysreset_ops efi_sysreset_ops = { + .request = efi_sysreset_request, +}; + +U_BOOT_DRIVER(efi_sysreset) = { + .name = "efi-sysreset", + .id = UCLASS_SYSRESET, + .of_match = efi_sysreset_ids, + .ops = &efi_sysreset_ops, +}; diff --git a/lib/efi_client/efi_app_init.c b/lib/efi_client/efi_app_init.c new file mode 100644 index 00000000000..c5e4192fe06 --- /dev/null +++ b/lib/efi_client/efi_app_init.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI-app board implementation + * + * Copyright 2023 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 : "", + 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/lib/efi_client/efi_info.c b/lib/efi_client/efi_info.c new file mode 100644 index 00000000000..5b564c5651d --- /dev/null +++ b/lib/efi_client/efi_info.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2015 Google, Inc + * + * Access to the EFI information table + */ + +#include +#include +#include +#include + +int efi_info_get(enum efi_entry_t type, void **datap, int *sizep) +{ + struct efi_entry_hdr *entry; + struct efi_info_hdr *info; + int ret; + + if (!gd->arch.table) + return -ENODATA; + + info = map_sysmem(gd->arch.table, 0); + if (info->version != EFI_TABLE_VERSION) { + ret = -EPROTONOSUPPORT; + goto err; + } + + entry = (struct efi_entry_hdr *)((ulong)info + info->hdr_size); + while (entry->type != EFIET_END) { + if (entry->type == type) { + if (entry->addr) + *datap = map_sysmem(entry->addr, entry->size); + else + *datap = entry + 1; + *sizep = entry->size; + return 0; + } + entry = (struct efi_entry_hdr *)((ulong)entry + entry->link); + } + + ret = -ENOENT; +err: + unmap_sysmem(info); + + return ret; +} diff --git a/lib/efi_client/efi_stub.c b/lib/efi_client/efi_stub.c new file mode 100644 index 00000000000..a083c7f1e9b --- /dev/null +++ b/lib/efi_client/efi_stub.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2015 Google, Inc + * + * EFI information obtained here: + * http://wiki.phoenix.com/wiki/index.php/EFI_BOOT_SERVICES + * + * Loads a payload (U-Boot) within the EFI environment. This is built as an + * EFI application. It can be built either in 32-bit or 64-bit mode. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CONFIG_X86 +/* + * Problem areas: + * - putc() uses the ns16550 address directly and assumed I/O access. Many + * platforms will use memory access + * get_codeseg32() is only meaningful on x86 + */ +#error "This file needs to be ported for use on architectures" +#endif + +static bool use_uart; + +struct __packed desctab_info { + uint16_t limit; + uint64_t addr; + uint16_t pad; +}; + +/* + * EFI uses Unicode and we don't. The easiest way to get a sensible output + * function is to use the U-Boot debug UART. We use EFI's console output + * function where available, and assume the built-in UART after that. We rely + * on EFI to set up the UART for us and just bring in the functions here. + * This last bit is a bit icky, but it's only for debugging anyway. We could + * build in ns16550.c with some effort, but this is a payload loader after + * all. + * + * Note: We avoid using printf() so we don't need to bring in lib/vsprintf.c. + * That would require some refactoring since we already build this for U-Boot. + * Building an EFI shared library version would have to be a separate stem. + * That might push us to using the SPL framework to build this stub. However + * that would involve a round of EFI-specific changes in SPL. Worth + * considering if we start needing more U-Boot functionality. Note that we + * could then move get_codeseg32() to arch/x86/cpu/cpu.c. + */ +void _debug_uart_init(void) +{ +} + +void putc(const char ch) +{ + struct efi_priv *priv = efi_get_priv(); + + if (ch == '\n') + putc('\r'); + + if (use_uart) { + struct ns16550 *com_port = (struct ns16550 *)0x3f8; + + while ((inb((ulong)&com_port->lsr) & UART_LSR_THRE) == 0) + ; + outb(ch, (ulong)&com_port->thr); + } else { + efi_putc(priv, ch); + } +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +static inline void _debug_uart_putc(int ch) +{ + putc(ch); +} + +DEBUG_UART_FUNCS + +void *memcpy(void *dest, const void *src, size_t size) +{ + unsigned char *dptr = dest; + const unsigned char *ptr = src; + const unsigned char *end = src + size; + + while (ptr < end) + *dptr++ = *ptr++; + + return dest; +} + +void *memset(void *inptr, int ch, size_t size) +{ + char *ptr = inptr; + char *end = ptr + size; + + while (ptr < end) + *ptr++ = ch; + + return ptr; +} + +static void jump_to_uboot(ulong cs32, ulong addr, ulong info) +{ +#ifdef CONFIG_EFI_STUB_32BIT + /* + * U-Boot requires these parameters in registers, not on the stack. + * See _x86boot_start() for this code. + */ + typedef void (*func_t)(int bist, int unused, ulong info) + __attribute__((regparm(3))); + + ((func_t)addr)(0, 0, info); +#else + cpu_call32(cs32, CONFIG_TEXT_BASE, info); +#endif +} + +#ifdef CONFIG_EFI_STUB_64BIT +static void get_gdt(struct desctab_info *info) +{ + asm volatile ("sgdt %0" : : "m"(*info) : "memory"); +} +#endif + +static inline unsigned long read_cr3(void) +{ + unsigned long val; + + asm volatile("mov %%cr3,%0" : "=r" (val) : : "memory"); + return val; +} + +/** + * get_codeseg32() - Find the code segment to use for 32-bit code + * + * U-Boot only works in 32-bit mode at present, so when booting from 64-bit + * EFI we must first change to 32-bit mode. To do this we need to find the + * correct code segment to use (an entry in the Global Descriptor Table). + * + * Return: code segment GDT offset, or 0 for 32-bit EFI, -ENOENT if not found + */ +static int get_codeseg32(void) +{ + int cs32 = 0; + +#ifdef CONFIG_EFI_STUB_64BIT + struct desctab_info gdt; + uint64_t *ptr; + int i; + + get_gdt(&gdt); + for (ptr = (uint64_t *)(unsigned long)gdt.addr, i = 0; i < gdt.limit; + i += 8, ptr++) { + uint64_t desc = *ptr; + uint64_t base, limit; + + /* + * Check that the target U-Boot jump address is within the + * selector and that the selector is of the right type. + */ + base = ((desc >> GDT_BASE_LOW_SHIFT) & GDT_BASE_LOW_MASK) | + ((desc >> GDT_BASE_HIGH_SHIFT) & GDT_BASE_HIGH_MASK) + << 16; + limit = ((desc >> GDT_LIMIT_LOW_SHIFT) & GDT_LIMIT_LOW_MASK) | + ((desc >> GDT_LIMIT_HIGH_SHIFT) & GDT_LIMIT_HIGH_MASK) + << 16; + base <<= 12; /* 4KB granularity */ + limit <<= 12; + if ((desc & GDT_PRESENT) && (desc & GDT_NOTSYS) && + !(desc & GDT_LONG) && (desc & GDT_4KB) && + (desc & GDT_32BIT) && (desc & GDT_CODE) && + CONFIG_TEXT_BASE > base && + CONFIG_TEXT_BASE + CONFIG_SYS_MONITOR_LEN < limit + ) { + cs32 = i; + break; + } + } + +#ifdef DEBUG + puts("\ngdt: "); + printhex8(gdt.limit); + puts(", addr: "); + printhex8(gdt.addr >> 32); + printhex8(gdt.addr); + for (i = 0; i < gdt.limit; i += 8) { + uint32_t *ptr = (uint32_t *)((unsigned long)gdt.addr + i); + + puts("\n"); + printhex2(i); + puts(": "); + printhex8(ptr[1]); + puts(" "); + printhex8(ptr[0]); + } + puts("\n "); + puts("32-bit code segment: "); + printhex2(cs32); + puts("\n "); + + puts("page_table: "); + printhex8(read_cr3()); + puts("\n "); +#endif + if (!cs32) { + puts("Can't find 32-bit code segment\n"); + return -ENOENT; + } +#endif + + return cs32; +} + +/** + * setup_info_table() - sets up a table containing information from EFI + * + * We must call exit_boot_services() before jumping out of the stub into U-Boot + * proper, so that U-Boot has full control of peripherals, memory, etc. + * + * Once we do this, we cannot call any boot-services functions so we must find + * out everything we need to before doing that. + * + * Set up a struct efi_info_hdr table which can hold various records (e.g. + * struct efi_entry_memmap) with information obtained from EFI. + * + * @priv: Pointer to our private information which contains the list + * @size: Size of the table to allocate + * Return: 0 if OK, non-zero on error + */ +static int setup_info_table(struct efi_priv *priv, int size) +{ + struct efi_info_hdr *info; + efi_status_t ret; + + /* Get some memory for our info table */ + priv->info_size = size; + info = efi_malloc(priv, priv->info_size, &ret); + if (ret) { + printhex2(ret); + puts(" No memory for info table: "); + return ret; + } + + memset(info, '\0', sizeof(*info)); + info->version = EFI_TABLE_VERSION; + info->hdr_size = sizeof(*info); + priv->info = info; + priv->next_hdr = (char *)info + info->hdr_size; + + return 0; +} + +/** + * add_entry_addr() - Add a new entry to the efi_info list + * + * This adds an entry, consisting of a tag and two lots of data. This avoids the + * caller having to coalesce the data first + * + * @priv: Pointer to our private information which contains the list + * @type: Type of the entry to add + * @ptr1: Pointer to first data block to add + * @size1: Size of first data block in bytes (can be 0) + * @ptr2: Pointer to second data block to add + * @size2: Size of second data block in bytes (can be 0) + */ +static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type, + void *ptr1, int size1, void *ptr2, int size2) +{ + struct efi_entry_hdr *hdr = priv->next_hdr; + + hdr->type = type; + hdr->size = size1 + size2; + hdr->addr = 0; + hdr->link = ALIGN(sizeof(*hdr) + hdr->size, 16); + priv->next_hdr += hdr->link; + memcpy(hdr + 1, ptr1, size1); + memcpy((void *)(hdr + 1) + size1, ptr2, size2); + priv->info->total_size = (ulong)priv->next_hdr - (ulong)priv->info; +} + +/** + * efi_main() - Start an EFI image + * + * This function is called by our EFI start-up code. It handles running + * U-Boot. If it returns, EFI will continue. + */ +efi_status_t EFIAPI efi_main(efi_handle_t image, + struct efi_system_table *sys_table) +{ + struct efi_priv local_priv, *priv = &local_priv; + struct efi_boot_services *boot = sys_table->boottime; + struct efi_entry_memmap map; + struct efi_gop *gop; + struct efi_entry_gopmode mode; + struct efi_entry_systable table; + efi_guid_t efi_gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + efi_status_t ret; + int cs32; + + ret = efi_init(priv, "Payload", image, sys_table); + if (ret) { + printhex2(ret); + puts(" efi_init() failed\n"); + return ret; + } + efi_set_priv(priv); + + cs32 = get_codeseg32(); + if (cs32 < 0) + return EFI_UNSUPPORTED; + + ret = efi_store_memory_map(priv); + if (ret) + return ret; + + ret = setup_info_table(priv, priv->memmap_size + 128); + if (ret) + return ret; + + ret = boot->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret) { + puts(" GOP unavailable\n"); + } else { + mode.fb_base = gop->mode->fb_base; + mode.fb_size = gop->mode->fb_size; + mode.info_size = gop->mode->info_size; + add_entry_addr(priv, EFIET_GOP_MODE, &mode, sizeof(mode), + gop->mode->info, + sizeof(struct efi_gop_mode_info)); + } + + table.sys_table = (ulong)sys_table; + add_entry_addr(priv, EFIET_SYS_TABLE, &table, sizeof(table), NULL, 0); + + ret = efi_call_exit_boot_services(); + if (ret) + return ret; + + /* The EFI UART won't work now, switch to a debug one */ + use_uart = true; + + map.version = priv->memmap_version; + map.desc_size = priv->memmap_desc_size; + add_entry_addr(priv, EFIET_MEMORY_MAP, &map, sizeof(map), + priv->memmap_desc, priv->memmap_size); + add_entry_addr(priv, EFIET_END, NULL, 0, 0, 0); + + memcpy((void *)CONFIG_TEXT_BASE, _binary_u_boot_bin_start, + (ulong)_binary_u_boot_bin_end - + (ulong)_binary_u_boot_bin_start); + +#ifdef DEBUG + puts("EFI table at "); + printhex8((ulong)priv->info); + puts(" size "); + printhex8(priv->info->total_size); +#endif + putc('\n'); + jump_to_uboot(cs32, CONFIG_TEXT_BASE, (ulong)priv->info); + + return EFI_LOAD_ERROR; +} diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 077466f01f0..250b9469134 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -595,6 +595,6 @@ config BOOTEFI_TESTAPP_COMPILE endif -source "lib/efi/Kconfig" +source "lib/efi_client/Kconfig" endmenu -- cgit v1.2.3 From 0029f2447bd4fac23d0ec6107c0b911c50c2c334 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 28 May 2025 10:03:15 -0600 Subject: efi: Rename CONFIG_EFI to CONFIG_EFI_CLIENT The generic name 'EFI' would be more useful for common EFI features. At present it just refers to the EFI app and stub, which is confusing. Rename it to EFI_CLIENT Signed-off-by: Simon Glass --- arch/x86/Kconfig | 6 +++--- arch/x86/cpu/Makefile | 2 +- arch/x86/cpu/efi/Kconfig | 2 +- arch/x86/cpu/x86_64/Makefile | 2 +- cmd/Makefile | 2 +- configs/efi-x86_app32_defconfig | 2 +- configs/efi-x86_app64_defconfig | 2 +- configs/efi-x86_payload32_defconfig | 2 +- configs/efi-x86_payload64_defconfig | 2 +- doc/develop/uefi/u-boot_on_efi.rst | 6 +++--- drivers/block/Kconfig | 2 +- include/init.h | 2 +- lib/Kconfig | 2 +- lib/Makefile | 2 +- lib/efi_client/Kconfig | 4 ++-- lib/uuid.c | 4 ++-- 16 files changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6ca0605466f..5aa134b6bcb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -368,7 +368,7 @@ config USE_HOB config HAVE_FSP bool "Add an Firmware Support Package binary" - depends on !EFI + depends on !EFI_CLIENT select USE_HOB select HAS_ROM help @@ -517,7 +517,7 @@ config FSP_BROKEN_HOB config ENABLE_MRC_CACHE bool "Enable MRC cache" - depends on !EFI && !SYS_COREBOOT + depends on !EFI_CLIENT && !SYS_COREBOOT help Enable this feature to cause MRC data to be cached in NV storage to be used for speeding up boot time on future reboots and/or @@ -756,7 +756,7 @@ config HAVE_P2SB devices. menu "System tables" - depends on !EFI && !SYS_COREBOOT + depends on !EFI_CLIENT && !SYS_COREBOOT config GENERATE_PIRQ_TABLE bool "Generate a PIRQ table" diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index cc55c8fa39c..5150edb833f 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -47,7 +47,7 @@ obj-$(CONFIG_INTEL_BRASWELL) += braswell/ obj-$(CONFIG_INTEL_BROADWELL) += broadwell/ obj-$(CONFIG_SYS_COREBOOT) += coreboot/ obj-$(CONFIG_SYS_SLIMBOOTLOADER) += slimbootloader/ -obj-$(CONFIG_EFI) += efi/ +obj-$(CONFIG_EFI_CLIENT) += efi/ obj-$(CONFIG_QEMU) += qemu/ obj-$(CONFIG_NORTHBRIDGE_INTEL_IVYBRIDGE) += ivybridge/ obj-$(CONFIG_INTEL_QUARK) += quark/ diff --git a/arch/x86/cpu/efi/Kconfig b/arch/x86/cpu/efi/Kconfig index e0975d34d36..f5288013a8a 100644 --- a/arch/x86/cpu/efi/Kconfig +++ b/arch/x86/cpu/efi/Kconfig @@ -1,4 +1,4 @@ -if EFI +if EFI_CLIENT config SYS_CAR_ADDR hex diff --git a/arch/x86/cpu/x86_64/Makefile b/arch/x86/cpu/x86_64/Makefile index e929563b2c1..cb23c071aa3 100644 --- a/arch/x86/cpu/x86_64/Makefile +++ b/arch/x86/cpu/x86_64/Makefile @@ -5,6 +5,6 @@ obj-y += cpu.o interrupts.o setjmp.o -ifndef CONFIG_EFI +ifndef CONFIG_EFI_CLIENT obj-y += misc.o endif diff --git a/cmd/Makefile b/cmd/Makefile index e4ecf2e0493..12e948fd1b9 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_CMD_EXTENSION) += extension_board.o obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o -obj-$(CONFIG_EFI) += efi.o efi_common.o +obj-$(CONFIG_EFI_CLIENT) += efi.o efi_common.o obj-$(CONFIG_CMD_EFIDEBUG) += efidebug.o efi_common.o obj-$(CONFIG_CMD_EFICONFIG) += eficonfig.o ifdef CONFIG_CMD_EFICONFIG diff --git a/configs/efi-x86_app32_defconfig b/configs/efi-x86_app32_defconfig index 71d1bbd956e..a06f1ccfe2a 100644 --- a/configs/efi-x86_app32_defconfig +++ b/configs/efi-x86_app32_defconfig @@ -7,7 +7,7 @@ CONFIG_DEBUG_UART_CLOCK=0 CONFIG_VENDOR_EFI=y CONFIG_TARGET_EFI_APP32=y CONFIG_DEBUG_UART=y -CONFIG_EFI=y +CONFIG_EFI_CLIENT=y CONFIG_FIT=y # CONFIG_BOOTSTD is not set CONFIG_SHOW_BOOT_PROGRESS=y diff --git a/configs/efi-x86_app64_defconfig b/configs/efi-x86_app64_defconfig index 9f7b53d0106..9bcf5162b50 100644 --- a/configs/efi-x86_app64_defconfig +++ b/configs/efi-x86_app64_defconfig @@ -8,7 +8,7 @@ CONFIG_X86_RUN_64BIT=y CONFIG_VENDOR_EFI=y CONFIG_TARGET_EFI_APP64=y CONFIG_DEBUG_UART=y -CONFIG_EFI=y +CONFIG_EFI_CLIENT=y CONFIG_EFI_APP_64BIT=y CONFIG_FIT=y # CONFIG_BOOTSTD is not set diff --git a/configs/efi-x86_payload32_defconfig b/configs/efi-x86_payload32_defconfig index e9c5ddf12ad..ce9b7ff939d 100644 --- a/configs/efi-x86_payload32_defconfig +++ b/configs/efi-x86_payload32_defconfig @@ -5,7 +5,7 @@ CONFIG_DEFAULT_DEVICE_TREE="efi-x86_payload" CONFIG_PRE_CON_BUF_ADDR=0x100000 CONFIG_VENDOR_EFI=y CONFIG_TARGET_EFI_PAYLOAD=y -CONFIG_EFI=y +CONFIG_EFI_CLIENT=y CONFIG_EFI_STUB=y CONFIG_FIT=y CONFIG_FIT_SIGNATURE=y diff --git a/configs/efi-x86_payload64_defconfig b/configs/efi-x86_payload64_defconfig index b82e10dc3a1..6ce00189886 100644 --- a/configs/efi-x86_payload64_defconfig +++ b/configs/efi-x86_payload64_defconfig @@ -5,7 +5,7 @@ CONFIG_DEFAULT_DEVICE_TREE="efi-x86_payload" CONFIG_PRE_CON_BUF_ADDR=0x100000 CONFIG_VENDOR_EFI=y CONFIG_TARGET_EFI_PAYLOAD=y -CONFIG_EFI=y +CONFIG_EFI_CLIENT=y CONFIG_EFI_STUB=y CONFIG_EFI_STUB_64BIT=y CONFIG_FIT=y diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 42e84c13049..9068894e408 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -45,7 +45,7 @@ First choose a board that has EFI support and obtain an EFI implementation for that board. It will be either 32-bit or 64-bit. Alternatively, you can opt for using QEMU [1] and the OVMF [2], as detailed below. -To build U-Boot as an EFI application, enable CONFIG_EFI and CONFIG_EFI_APP. +To build U-Boot as an EFI application, enable CONFIG_EFI_CLIENT and CONFIG_EFI_APP. The efi-x86_app32 and efi-x86_app64 configs are set up for this. Just build U-Boot as normal, e.g.:: @@ -53,7 +53,7 @@ U-Boot as normal, e.g.:: make To build U-Boot as an EFI payload (32-bit or 64-bit EFI can be used), enable -CONFIG_EFI, CONFIG_EFI_STUB, and select either CONFIG_EFI_STUB_32BIT or +CONFIG_EFI_CLIENT, CONFIG_EFI_STUB, and select either CONFIG_EFI_STUB_32BIT or CONFIG_EFI_STUB_64BIT. The efi-x86_payload configs (efi-x86_payload32_defconfig and efi-x86_payload32_defconfig) are set up for this. Then build U-Boot as normal, e.g.:: @@ -121,7 +121,7 @@ and board_init_r()). Since U-Boot limits its memory access to the allocated regions very little special code is needed. The CONFIG_EFI_APP option controls a few things that need to change so 'git grep CONFIG_EFI_APP' may be instructive. -The CONFIG_EFI option controls more general EFI adjustments. +The CONFIG_EFI_CLIENT option controls more general EFI adjustments. The only available driver is the serial driver. This calls back into EFI 'boot services' to send and receive characters. Although it is implemented diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 750b0bd2082..c6c148ebd17 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -96,7 +96,7 @@ config TPL_BLOCK_CACHE config EFI_MEDIA bool "Support EFI media drivers" - default y if EFI || SANDBOX + default y if EFI_CLIENT || SANDBOX select BLK help Enable this to support media devices on top of UEFI. This enables diff --git a/include/init.h b/include/init.h index 2c10171359c..1e375da4893 100644 --- a/include/init.h +++ b/include/init.h @@ -18,7 +18,7 @@ * In case of the EFI app the UEFI firmware provides the low-level * initialisation. */ -#ifdef CONFIG_EFI +#ifdef CONFIG_EFI_CLIENT #define ll_boot_init() false #else #include diff --git a/lib/Kconfig b/lib/Kconfig index 6a89f797bef..fbc9de90669 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -1096,7 +1096,7 @@ config VPL_OF_LIBFDT_ASSUME_MASK unsafe execution. See FDT_ASSUME_PERFECT, etc. in libfdt_internal.h menu "System tables" - depends on (!EFI && !SYS_COREBOOT) || (ARM && EFI_LOADER) + depends on (!EFI_CLIENT && !SYS_COREBOOT) || (ARM && EFI_LOADER) config BLOBLIST_TABLES bool "Put tables in a bloblist" diff --git a/lib/Makefile b/lib/Makefile index 1dd738a7cd1..2643bfc867c 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -5,7 +5,7 @@ ifndef CONFIG_XPL_BUILD -obj-$(CONFIG_EFI) += efi_client/ +obj-$(CONFIG_EFI_CLIENT) += efi_client/ obj-$(CONFIG_EFI_LOADER) += efi_driver/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/ diff --git a/lib/efi_client/Kconfig b/lib/efi_client/Kconfig index 81ed3e66b34..ec413639bfe 100644 --- a/lib/efi_client/Kconfig +++ b/lib/efi_client/Kconfig @@ -1,7 +1,7 @@ menu "U-Boot as UEFI application" depends on X86 -config EFI +config EFI_CLIENT bool "Support running U-Boot from EFI" depends on X86 imply X86_TSC_READ_BASE @@ -13,7 +13,7 @@ config EFI choice prompt "Select EFI mode to use" - depends on X86 && EFI + depends on X86 && EFI_CLIENT config EFI_APP bool "Support running as an EFI application" diff --git a/lib/uuid.c b/lib/uuid.c index a1c88b9a622..8d99b540d9f 100644 --- a/lib/uuid.c +++ b/lib/uuid.c @@ -94,7 +94,7 @@ static const struct { "system", "EFI System Partition", PARTITION_SYSTEM_GUID, }, -#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI) +#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_CLIENT) { NULL, "Device Path", PARTITION_SYSTEM_GUID, @@ -281,7 +281,7 @@ static const struct { EFI_CERT_TYPE_PKCS7_GUID, }, #endif -#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI) +#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_CLIENT) { "EFI_LZMA_COMPRESSED", NULL, EFI_LZMA_COMPRESSED }, { "EFI_DXE_SERVICES", NULL, EFI_DXE_SERVICES }, { "EFI_HOB_LIST", NULL, EFI_HOB_LIST }, -- cgit v1.2.3 From 81ce639e61c990e4d3b88cc975bf552e8b509090 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 28 May 2025 10:03:16 -0600 Subject: efi: Create a new CONFIG_EFI Create a Kconfig which indicates that EFI functionality is in use, either as a client (EFI app / stub) or provider (EFI loader). This will make it easier to share code between these two parts of U-Boot Signed-off-by: Simon Glass --- doc/develop/uefi/u-boot_on_efi.rst | 6 +++--- lib/efi/Kconfig | 12 ++++++++++++ lib/efi_client/Kconfig | 1 + lib/efi_loader/Kconfig | 3 +++ 4 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 lib/efi/Kconfig diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index 9068894e408..177e887ebd9 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -45,9 +45,9 @@ First choose a board that has EFI support and obtain an EFI implementation for that board. It will be either 32-bit or 64-bit. Alternatively, you can opt for using QEMU [1] and the OVMF [2], as detailed below. -To build U-Boot as an EFI application, enable CONFIG_EFI_CLIENT and CONFIG_EFI_APP. -The efi-x86_app32 and efi-x86_app64 configs are set up for this. Just build -U-Boot as normal, e.g.:: +To build U-Boot as an EFI application, enable CONFIG_EFI_CLIENT and +CONFIG_EFI_APP. The efi-x86_app32 and efi-x86_app64 configs are set up for +this. Just build U-Boot as normal, e.g.:: make efi-x86_app32_defconfig make diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig new file mode 100644 index 00000000000..fc6d5b6d6c2 --- /dev/null +++ b/lib/efi/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright 2025 Simon Glass +# + +config EFI + bool + help + Indicates that EFI functionality is enabled, either via EFI_CLIENT or + EFI_LOADER + + This is used to provide libraries shared by both. diff --git a/lib/efi_client/Kconfig b/lib/efi_client/Kconfig index ec413639bfe..723c98d2a75 100644 --- a/lib/efi_client/Kconfig +++ b/lib/efi_client/Kconfig @@ -5,6 +5,7 @@ config EFI_CLIENT bool "Support running U-Boot from EFI" depends on X86 imply X86_TSC_READ_BASE + select EFI help U-Boot can be started from EFI on certain platforms. This allows EFI to perform most of the system init and then jump to U-Boot for diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 250b9469134..c2aa88f59fb 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -16,6 +16,7 @@ config EFI_LOADER depends on !EFI_STUB || !X86 || X86_64 || EFI_STUB_32BIT depends on !EFI_APP default y if !ARM || SYS_CPU = armv7 || SYS_CPU = armv8 + select EFI select CHARSET # We need to send DM events, dynamically, in the EFI block driver select DM_EVENT @@ -597,4 +598,6 @@ endif source "lib/efi_client/Kconfig" +source "lib/efi/Kconfig" + endmenu -- cgit v1.2.3 From ca0b03ba60b9d684df3205a02766ffbe90d6e85a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 28 May 2025 10:03:17 -0600 Subject: efi: Update maintainers for EFI_CLIENT The 'EFI PAYLOAD' entry really refers to the EFI loader and EFI APP refers to the app and the payload. Rename 'EFI PAYLOAD' to 'EFI LOADER' and 'EFI APP' to 'EFI CLIENT' Signed-off-by: Simon Glass Acked-by: Ilias Apalodimas --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 3e555596a1c..f31dc74bec1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1094,7 +1094,7 @@ F: drivers/core/ F: include/dm/ F: test/dm/ -EFI APP +EFI CLIENT M: Simon Glass M: Heinrich Schuchardt S: Maintained @@ -1108,7 +1108,7 @@ F: lib/efi_client/ F: scripts/build-efi.sh F: test/dm/efi_media.c -EFI PAYLOAD +EFI LOADER M: Heinrich Schuchardt M: Ilias Apalodimas S: Maintained -- cgit v1.2.3 From 62b3dbfc5efd1343c2c92f8ca5b3aa122744dca5 Mon Sep 17 00:00:00 2001 From: Mattijs Korpershoek Date: Wed, 25 Jun 2025 16:58:15 +0200 Subject: doc: board: ti: Add defconfigs for AM69-SK The J784S4 and AM69 Platforms page only details the defconfigs for J784S4. Mention the ones needed for AM69-SK as well, to guide users on how to build for that board. Signed-off-by: Mattijs Korpershoek Reviewed-by: Neha Malcom Francis --- doc/board/ti/j784s4_evm.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/board/ti/j784s4_evm.rst b/doc/board/ti/j784s4_evm.rst index 349fb394d74..22442874110 100644 --- a/doc/board/ti/j784s4_evm.rst +++ b/doc/board/ti/j784s4_evm.rst @@ -90,6 +90,15 @@ Set the variables corresponding to this platform: export OPTEE_PLATFORM=k3-j784s4 export OPTEE_EXTRA_ARGS="CFG_CONSOLE_UART=0x8" +.. note:: + + For AM69-SK, use the following U_BOOT_CFG instead: + + .. prompt:: bash + + export UBOOT_CFG_CORTEXR=am69_sk_r5_defconfig + export UBOOT_CFG_CORTEXA=am69_sk_a72_defconfig + .. j784s4_evm_rst_include_start_build_steps 1. Trusted Firmware-A -- cgit v1.2.3 From b9bb2627bbb672a8dce58c7da5c0e48b921a6b29 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 4 Jul 2025 16:22:12 +0200 Subject: efi_selftest: check system table pointer Enhance the debug support unit test. Acked-by: Ilias Apalodimas Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/efi_selftest_debug_support.c | 68 ++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/lib/efi_selftest/efi_selftest_debug_support.c b/lib/efi_selftest/efi_selftest_debug_support.c index 9ca8b3f82f5..ac77caaf561 100644 --- a/lib/efi_selftest/efi_selftest_debug_support.c +++ b/lib/efi_selftest/efi_selftest_debug_support.c @@ -9,6 +9,7 @@ #include #include +#include /** * efi_st_debug_support_execute() - execute test @@ -21,6 +22,12 @@ static int efi_st_debug_support_execute(void) { struct efi_debug_image_info_table_header *efi_st_debug_info_table_header = NULL; efi_guid_t efi_debug_image_info_table_guid = EFI_DEBUG_IMAGE_INFO_TABLE_GUID; + struct efi_mem_desc *memory_map; + efi_uintn_t map_size = 0; + efi_uintn_t map_key; + efi_uintn_t desc_size; + u32 desc_version; + efi_status_t ret; /* get EFI_DEBUG_IMAGE_INFO_TABLE */ efi_st_debug_info_table_header = efi_st_get_config_table(&efi_debug_image_info_table_guid); @@ -30,7 +37,66 @@ static int efi_st_debug_support_execute(void) return EFI_ST_FAILURE; } - return EFI_ST_SUCCESS; + /* Load memory map */ + ret = st_boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error + ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); + return EFI_ST_FAILURE; + } + /* Allocate extra space for newly allocated memory */ + map_size += sizeof(struct efi_mem_desc); + ret = st_boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + (void **)&memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool failed\n"); + return EFI_ST_FAILURE; + } + ret = st_boottime->get_memory_map(&map_size, memory_map, &map_key, + &desc_size, &desc_version); + if (ret != EFI_SUCCESS) { + efi_st_error("GetMemoryMap failed\n"); + return EFI_ST_FAILURE; + } + /* Find the system table pointer */ + for (efi_uintn_t i = 0; map_size; ++i, map_size -= desc_size) { + struct efi_mem_desc *entry = &memory_map[i]; + u64 end; + + if (entry->type != EFI_RUNTIME_SERVICES_DATA) + continue; + + end = entry->physical_start + + (entry->num_pages << EFI_PAGE_SHIFT); + for (u64 pos = ALIGN(entry->physical_start, SZ_4M); + pos <= end; pos += SZ_4M) { + struct efi_system_table_pointer *systab_pointer = + (void *)(uintptr_t)pos; + + /* check for overflow */ + if (pos < entry->physical_start) + break; + if (systab_pointer->signature == + EFI_SYSTEM_TABLE_SIGNATURE) { + if (systab_pointer->efi_system_table_base != + (uintptr_t)st_systable) { + efi_st_error("Wrong system table address\n"); + ret = EFI_ST_FAILURE; + goto out; + } + ret = EFI_ST_SUCCESS; + goto out; + } + } + } + efi_st_error("System table pointer not found\n"); + ret = EFI_ST_FAILURE; + +out: + st_boottime->free_pool(memory_map); + + return ret; } EFI_UNIT_TEST(debug_support) = { -- cgit v1.2.3 From aa703a816a62deb876a1e77ccff030a7cc60f344 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Jul 2025 12:08:20 +0200 Subject: efi_loader: efi_realloc() must check efi_alloc() return value Avoid copying to NULL if out of memory. Fixes: 3c08df58cc43 ("lib: efi_loader: efi_memory.c: add efi_realloc() for realloc memory") Addresses-Coverity-ID: 569499: Null pointer dereferences (NULL_RETURNS) Reviewed-by: Ilias Apalodimas Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_memory.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 6dfc698a247..b77c2f980cc 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -714,6 +714,8 @@ efi_status_t efi_realloc(void **ptr, size_t size) sizeof(struct efi_pool_allocation); new_ptr = efi_alloc(size); + if (!new_ptr) + return EFI_OUT_OF_RESOURCES; /* copy old data to new alloced buffer */ memcpy(new_ptr, *ptr, min(size, old_size)); -- cgit v1.2.3 From 7e2506e3a247c787a9ad4b4db00bc8e6a348df90 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Jul 2025 13:14:35 +0200 Subject: efi_loader: correct EFI_DEBUG_TABLE_ENTRY_SIZE With the current code we allocate to little memory when adding entries to the EFI_DEBUG_INFO_TABLE and we fail to correctly move entries when an entry is removed. EFI_DEBUG_TABLE_ENTRY_SIZE must be the size of an entry in the EFI_DEBUG_INFO_TABLE, not the size of a pointer. Fixes: 146546138af5 ("efi: add EFI_DEBUG_IMAGE_INFO for debug") Addresses-Coverity-ID: CID 569498: Code maintainability issues (SIZEOF_MISMATCH) Reviewed-by: Ilias Apalodimas Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_debug_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_debug_support.c b/lib/efi_loader/efi_debug_support.c index 186bdbce750..490b0bb7088 100644 --- a/lib/efi_loader/efi_debug_support.c +++ b/lib/efi_loader/efi_debug_support.c @@ -22,7 +22,7 @@ struct efi_debug_image_info_table_header efi_m_debug_info_table_header = { */ static u32 efi_m_max_table_entries; -#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof(union efi_debug_image_info *)) +#define EFI_DEBUG_TABLE_ENTRY_SIZE (sizeof(union efi_debug_image_info)) /** * efi_initialize_system_table_pointer() - Initialize system table pointer -- cgit v1.2.3 From ca01c847f6c76fbcfc6e3b483b791f070621bda6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Jul 2025 13:37:32 +0200 Subject: efi_selftest: fix ESRT creation tests The code foresees that parameters descriptor_size and descriptor_count might be NULL and then dereferences them without further check. The size check must take into account the descriptor count. ImageInfo might be NULL. In this case we must not dereference it. Fixes: 4ac6041c3cbf ("efi: ESRT creation tests") Addresses-Coverity-ID: CID 569497: Null pointer dereferences (FORWARD_NULL) Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/efi_selftest_esrt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_esrt.c b/lib/efi_selftest/efi_selftest_esrt.c index b7688deb496..7eadac90fbc 100644 --- a/lib/efi_selftest/efi_selftest_esrt.c +++ b/lib/efi_selftest/efi_selftest_esrt.c @@ -69,10 +69,12 @@ EFIAPI efi_test_fmp_get_image_info(struct efi_firmware_management_protocol *this if (package_version_name) *package_version_name = NULL; - if (*image_info_size < sizeof(*image_info)) { - *image_info_size = *descriptor_size * *descriptor_count; + if (*image_info_size < sizeof(*image_info) * TEST_ESRT_NUM_ENTRIES) { + *image_info_size = sizeof(*image_info) * TEST_ESRT_NUM_ENTRIES; return EFI_BUFFER_TOO_SMALL; } + if (!image_info) + return EFI_INVALID_PARAMETER; for (int idx = 0; idx < TEST_ESRT_NUM_ENTRIES; idx++) image_info[idx] = static_img_info[idx]; -- cgit v1.2.3 From 5bab07296c1469562536b80480d625eadc823202 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Jul 2025 13:48:50 +0200 Subject: efi_loader: add missing check in FMP.GetImageInfo() The UEFI 2.11 specification, chapter 23.1.3 requires EFI_FIRMWARE_MANAGEMENT_PROTOCOL.GetImageInfo() to return EFI_INVALID_PARAMETER if *ImageInfoSize is not too small and ImageInfo is NULL. Fixes: f27c20148511 ("efi_loader: add firmware management protocol for FIT image") Reviewed-by: Ilias Apalodimas Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_firmware.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index 75501e21557..216df83de67 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -332,6 +332,8 @@ static efi_status_t efi_fill_image_desc_array( return EFI_BUFFER_TOO_SMALL; } + if (!image_info) + return EFI_INVALID_PARAMETER; *image_info_size = total_size; ret = efi_gen_capsule_guids(); -- cgit v1.2.3 From afd5426043b3ef6aa57f2a731f94125ae983395c Mon Sep 17 00:00:00 2001 From: Enric Balletbo i Serra Date: Wed, 16 Jul 2025 15:12:06 +0200 Subject: docs: Update FIT signature testing instructions Update the FIT signature testing instructions to use the pytest suite instead of the old vboot_test.sh script. Signed-off-by: Enric Balletbo i Serra Reviewed-by: Mattijs Korpershoek --- doc/usage/fit/signature.rst | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/doc/usage/fit/signature.rst b/doc/usage/fit/signature.rst index b868dcbf9fd..e5b5a8432e9 100644 --- a/doc/usage/fit/signature.rst +++ b/doc/usage/fit/signature.rst @@ -433,16 +433,14 @@ CONFIG_LEGACY_IMAGE_FORMAT Testing ------- -An easy way to test signing and verification is to use the test script -provided in test/vboot/vboot_test.sh. This uses sandbox (a special version +An easy way to test signing and verification is to use the vboot tests +provided in the pytest suite. This uses sandbox (a special version of U-Boot which runs under Linux) to show the operation of a 'bootm' command loading and verifying images. A sample run is show below:: - $ make O=sandbox sandbox_config - $ make O=sandbox - $ O=sandbox ./test/vboot/vboot_test.sh + $ ./test/py/test.py --bd sandbox --build -k vboot Simple Verified Boot Test -- cgit v1.2.3