From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH v1 45/54] efi: loader: implement bootm handler
Date: Thu, 18 Dec 2025 11:38:05 +0100 [thread overview]
Message-ID: <20251218111242.1527495-46-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20251218111242.1527495-1-a.fatoum@pengutronix.de>
As counterpart to the EFI-less bootm handlers for the different
architectures, define EFI-enabled variants that will initialize the EFI
loader support and load the PE by EFI means.
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
efi/loader/Makefile | 1 +
efi/loader/bootm.c | 358 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 359 insertions(+)
create mode 100644 efi/loader/bootm.c
diff --git a/efi/loader/Makefile b/efi/loader/Makefile
index 62483057b426..2a78361e58d5 100644
--- a/efi/loader/Makefile
+++ b/efi/loader/Makefile
@@ -14,3 +14,4 @@ obj-y += pe.o
obj-y += loadopts.o
obj-$(CONFIG_BOOT) += bootesp.o
obj-$(CONFIG_EFI_LOADER_BOOTMGR) += efibootmgr.o
+obj-$(CONFIG_BOOTM) += bootm.o
diff --git a/efi/loader/bootm.c b/efi/loader/bootm.c
new file mode 100644
index 000000000000..dffe53bcf9c8
--- /dev/null
+++ b/efi/loader/bootm.c
@@ -0,0 +1,358 @@
+// SPDX-License-Identifier: GPL-2.0
+// SPDX-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/162a6b3df349295bf766c1d128d71b4547e8d56e/lib/efi_loader/efi_helper.c
+/*
+ * Copyright (c) 2016 Alexander Graf
+ */
+#define pr_fmt(fmt) "efi-loader: bootm: " fmt
+
+#include <clock.h>
+#include <linux/sizes.h>
+#include <memory.h>
+#include <command.h>
+#include <magicvar.h>
+#include <init.h>
+#include <driver.h>
+#include <io.h>
+#include <bootargs.h>
+#include <malloc.h>
+#include <string.h>
+#include <linux/err.h>
+#include <fs.h>
+#include <filetype.h>
+#include <libfile.h>
+#include <bootm.h>
+#include <wchar.h>
+#include <efi/mode.h>
+#include <efi/loader.h>
+#include <efi/loader/object.h>
+#include <efi/loader/option.h>
+#include <efi/loader/table.h>
+#include <efi/loader/devicepath.h>
+#include <efi/loader/image.h>
+#include <efi/loader/event.h>
+#include <efi/guid.h>
+#include <efi/services.h>
+#include <efi/error.h>
+#include <efi/initrd.h>
+#include <efi/devicepath.h>
+
+/**
+ * copy_fdt() - Copy the device tree to a new location available to EFI
+ *
+ * The FDT is copied to a suitable location within the EFI memory map.
+ * Additional 12 KiB are added to the space in case the device tree needs to be
+ * expanded later with fdt_open_into().
+ *
+ * @fdtp: On entry a pointer to the flattened device tree.
+ * On exit a pointer to the copy of the flattened device tree.
+ * FDT start
+ * Return: status code
+ */
+static efi_status_t copy_fdt(void **fdtp)
+{
+ efi_status_t efiret;
+ void *fdt, *new_fdt;
+ static u64 new_fdt_addr;
+ static efi_uintn_t fdt_pages;
+ size_t fdt_size;
+
+ /*
+ * Remove the configuration table that might already be
+ * installed, ignoring EFI_NOT_FOUND if no device-tree
+ * is installed
+ */
+ efi_install_configuration_table(&efi_fdt_guid, NULL);
+
+ if (new_fdt_addr) {
+ pr_debug("%s: Found allocated memory at %#llx, with %#zx pages\n",
+ __func__, new_fdt_addr, fdt_pages);
+
+ efiret = efi_free_pages(new_fdt_addr, fdt_pages);
+ if (efiret != EFI_SUCCESS)
+ pr_err("Unable to free up existing FDT memory region\n");
+
+ new_fdt_addr = 0;
+ fdt_pages = 0;
+ }
+
+ /*
+ * Give us at least 12 KiB of breathing room in case the device tree
+ * needs to be expanded later.
+ */
+ fdt = *fdtp;
+ fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
+ fdt_size = fdt_pages << EFI_PAGE_SHIFT;
+
+ /*
+ * Safe fdt location is at 127 MiB.
+ * On the sandbox convert from the sandbox address space.
+ */
+ efiret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
+ EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
+ &new_fdt_addr, "FDT");
+ if (efiret != EFI_SUCCESS) {
+ pr_err("Failed to reserve space for FDT\n");
+ goto done;
+ }
+
+ new_fdt = (void *)(uintptr_t)new_fdt_addr;
+ memcpy(new_fdt, fdt, fdt_totalsize(fdt));
+ fdt_set_totalsize(new_fdt, fdt_size);
+
+ *fdtp = new_fdt;
+
+done:
+ return efiret;
+}
+
+/**
+ * efi_install_fdt() - install device tree
+ *
+ * If fdt is not NULL, the device tree located at that memory
+ * address will will be installed as configuration table, otherwise the device
+ * tree located at the address indicated by environment variable fdt_addr or as
+ * fallback fdtcontroladdr will be used.
+ *
+ * On architectures using ACPI tables device trees shall not be installed as
+ * configuration table.
+ *
+ * @fdt: address of device tree
+ * the hardware device tree as indicated by environment variable
+ * fdt_addr or as fallback the internal device tree as indicated by
+ * the environment variable fdtcontroladdr
+ * Return: status code
+ */
+static efi_status_t efi_install_fdt(void *fdt)
+{
+ /*
+ * The EBBR spec requires that we have either an FDT or an ACPI table
+ * but not both.
+ */
+ efi_status_t ret;
+
+ /* Install device tree */
+ if (fdt_check_header(fdt)) {
+ pr_err("invalid device tree\n");
+ return EFI_LOAD_ERROR;
+ }
+
+ /* Prepare device tree for payload */
+ ret = copy_fdt(&fdt);
+ if (ret) {
+ pr_err("out of memory\n");
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ /* Install device tree as UEFI table */
+ ret = efi_install_configuration_table(&efi_fdt_guid, fdt);
+ if (ret != EFI_SUCCESS) {
+ pr_err("failed to install device tree\n");
+ return ret;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_install_initrd() - install initrd
+ *
+ * Install the initrd located at @initrd using the EFI_LOAD_FILE2
+ * protocol.
+ *
+ * @initrd: address of initrd or NULL if none is provided
+ * @initrd_sz: size of initrd
+ * Return: status code
+ */
+static efi_status_t efi_install_initrd(struct image_data *data,
+ struct resource *source)
+{
+ const struct resource *initrd_res;
+ unsigned long initrd_start;
+
+ if (!IS_ENABLED(CONFIG_BOOTM_INITRD))
+ return EFI_SUCCESS;
+
+ if (UIMAGE_IS_ADDRESS_VALID(data->initrd_address))
+ initrd_start = data->initrd_address;
+ else
+ initrd_start = EFI_PAGE_ALIGN(source->end + 1);
+
+ initrd_res = bootm_load_initrd(data, initrd_start);
+ if (IS_ERR(initrd_res))
+ return PTR_ERR(initrd_res);
+ if (initrd_res)
+ efi_initrd_register((void *)initrd_res->start,
+ resource_size(initrd_res));
+
+ return EFI_SUCCESS;
+}
+
+static int efi_loader_bootm(struct image_data *data)
+{
+ resource_size_t start, end;
+ void *load_option = NULL;
+ u32 load_option_size = 0;
+ efi_handle_t handle;
+ struct efi_device_path *file_path = NULL;
+ struct resource *source;
+ struct efi_event *evt;
+ size_t exit_data_size = 0;
+ u16 *exit_data = NULL;
+ efi_status_t efiret;
+ int ret = 0;
+ void *fdt;
+ int flags = 0;
+
+ memory_bank_first_find_space(&start, &end);
+ data->os_address = start;
+
+ source = file_to_sdram(data->os_file, data->os_address, MEMTYPE_LOADER_CODE);
+ if (!source)
+ return -EINVAL;
+
+ if (filetype_is_linux_efi_image(data->os_type)) {
+ const char *options;
+
+ options = linux_bootargs_get();
+ if (options) {
+ load_option = xstrdup_char_to_wchar(options);
+ load_option_size = (strlen(options) + 1) * sizeof(wchar_t);
+ }
+ }
+
+ file_path = efi_dp_from_file(AT_FDCWD, data->os_file);
+
+ pr_info("Loading %pD\n", file_path);
+
+ /* Initialize EFI drivers */
+ efiret = efi_init_obj_list();
+ if (efiret) {
+ pr_err("Cannot initialize UEFI sub-system: %pe\n",
+ ERR_PTR(-efi_errno(ret)));
+ goto out;
+ }
+
+ ret = -EINVAL;
+
+ fdt = bootm_get_devicetree(data);
+ if (IS_ERR(fdt))
+ return PTR_ERR(fdt);
+ if (fdt) {
+ ret = efi_install_fdt(fdt);
+ if (ret)
+ return ret;
+ }
+
+ efiret = efi_install_initrd(data, source);
+ if(efiret != EFI_SUCCESS)
+ goto out;
+
+ if (data->verbose >= 1)
+ flags |= EFI_VERBOSE_RUN;
+ if (data->dryrun)
+ flags |= EFI_DRYRUN;
+
+ efiret = efiloader_load_image(false, efi_root, file_path,
+ (void *)source->start,
+ resource_size(source), &handle);
+ if (efiret != EFI_SUCCESS) {
+ pr_err("Loading image failed\n");
+ goto out;
+ }
+
+ efiret = efi_set_load_options(handle, load_option_size, load_option);
+ if (efiret)
+ goto out;
+
+ /* On ARM, PBL should have already moved us into EL2 here, so
+ * no need to switch modes
+ */
+
+ /*
+ * The UEFI standard requires that the watchdog timer is set to five
+ * minutes when invoking an EFI boot option.
+ *
+ * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
+ * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
+ */
+ ret = efi_set_watchdog(300);
+ if (ret != EFI_SUCCESS) {
+ pr_err("failed to set watchdog timer\n");
+ goto out;
+ }
+
+ /* Call our payload! */
+ ret = __efi_start_image(handle, &exit_data_size, &exit_data, flags);
+ if (ret != EFI_SUCCESS) {
+ pr_err("## Application failed, r = %lu\n",
+ ret & ~EFI_ERROR_MASK);
+ if (exit_data) {
+ pr_err("## %ls\n", exit_data);
+ efi_free_pool(exit_data);
+ }
+ }
+
+ /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
+ list_for_each_entry(evt, &efi_events, link) {
+ if (evt->group &&
+ !efi_guidcmp(*evt->group,
+ efi_guid_event_group_return_to_efibootmgr)) {
+ efi_signal_event(evt);
+ systab.boottime->close_event(evt);
+ break;
+ }
+ }
+
+ /* Control is returned to us, disable EFI watchdog */
+ efi_set_watchdog(0);
+
+ return ret;
+
+out:
+ efi_initrd_unregister();
+ efi_install_configuration_table(&efi_fdt_guid, NULL);
+ efi_free_pool(file_path);
+ free(load_option);
+ release_sdram_region(source);
+
+ return ret ?: -efi_errno(efiret);
+}
+
+static struct image_handler riscv_linux_efi_handler = {
+ .name = "RISC-V Linux/EFI image",
+ .bootm = efi_loader_bootm,
+ .check_image = bootm_efi_check_image,
+ .filetype = filetype_riscv_efi_linux_image,
+};
+
+static struct image_handler aarch64_linux_efi_handler = {
+ .name = "ARM aarch64 Linux/EFI image",
+ .bootm = efi_loader_bootm,
+ .check_image = bootm_efi_check_image,
+ .filetype = filetype_arm64_efi_linux_image,
+};
+
+static struct image_handler arm32_linux_efi_handler = {
+ .name = "ARM arm32 Linux/EFI image",
+ .bootm = efi_loader_bootm,
+ .check_image = bootm_efi_check_image,
+ .filetype = filetype_arm_efi_zimage,
+};
+
+static struct image_handler efi_image_loader = {
+ .name = "EFI Application",
+ .bootm = efi_loader_bootm,
+ .filetype = filetype_exe,
+};
+
+static int efiloader_bootm_register(void)
+{
+ if (IS_ENABLED(CONFIG_ARM32))
+ register_image_handler(&arm32_linux_efi_handler);
+ if (IS_ENABLED(CONFIG_ARM64))
+ register_image_handler(&aarch64_linux_efi_handler);
+ if (IS_ENABLED(CONFIG_RISCV))
+ register_image_handler(&riscv_linux_efi_handler);
+ return register_image_handler(&efi_image_loader);
+}
+late_initcall(efiloader_bootm_register);
--
2.47.3
next prev parent reply other threads:[~2025-12-18 11:40 UTC|newest]
Thread overview: 55+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-18 10:37 [PATCH v1 00/54] efi: implement EFI loader support in barebox Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 01/54] efi: payload: initrd: fix type mismatch on 32-bit Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 02/54] efi: loader: switch over event/memory key type to efi_uintn_t Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 03/54] lib: vsprintf: print human-readable EFI GUIDs with %pUs Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 04/54] fs: fat: don't duplicate dentries when resolving differently cased paths Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 05/54] efi: loader: add memory accounting Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 06/54] efi: loader: add pool allocator Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 07/54] efi: types: add EFI_RUNTIME_SECTION Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 08/54] resource: assign memory banks a default type and attr Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 09/54] ARM: lds: add EFI runtime service section Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 10/54] ARM: move needed assembly routines into EFI runtime section Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 11/54] crypto: crc32: implement position independent CRC32 Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 12/54] efi: loader: add support for tracing calls back into UEFI Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 13/54] efi: loader: add table utility functions Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 14/54] lib: add charset helpers Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 15/54] efi: loader: add object handling API Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 16/54] efi: loader: add devicepath support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 17/54] efi: loader: add debug support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 18/54] efi: loader: add boot services support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 19/54] efi: loader: add support for runtime services before ExitBootServices Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 20/54] efi: loader: setup root node Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 21/54] efi: loader: add watchdog support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 22/54] efi: loader: move PE implementation out of common code Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 23/54] efi: loader: protocol: add file protocol support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 24/54] efi: loader: protocol: add Block IO support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 25/54] efi: loader: protocol: implement efi_file_from_path Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 26/54] efi: loader: boot: implement LoadImage BootService Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 27/54] efi: loader: add EFI load option handling Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 28/54] efi: loader: protocol: add graphical output protocol support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 29/54] efi: loader: protocol: add console support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 30/54] efi: loader: protocol: add HII support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 31/54] efi: loader: protocol: add unicode collation support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 32/54] efi: loader: protocol: add random number generator protocol Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 33/54] efi: loader: protocol: add device_path_utilities Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 34/54] efi: loader: support formatting only first device path node to text Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 35/54] efi: loader: protocol: add efi_device_path_to_text support Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 36/54] restart: allow drivers to register runtime restart handler Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 37/54] poweroff: allow drivers to register runtime poweroff handler Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 38/54] ARM: psci: client: register runtime service " Ahmad Fatoum
2025-12-18 10:37 ` [PATCH v1 39/54] ARM: psci: client: register runtime service restart handler Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 40/54] hardening: disable some features when EFI runtime support is enabled Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 41/54] filetype: add new filetype for efi-stubbed ARM zImages Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 42/54] bootm: add global.bootm.efi toggle Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 43/54] efi: loader: add ESP boot entry provider Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 44/54] efi: loader: add rudimentary EFI boot manager Ahmad Fatoum
2025-12-18 10:38 ` Ahmad Fatoum [this message]
2025-12-18 10:38 ` [PATCH v1 46/54] efi: runtime: add EFI variable support Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 47/54] efi: loader: populate OsIndicationsSupported/PlatformLang variables Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 48/54] ARM: don't disable MMU when EFI booting Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 49/54] efi: runtime: add runtime service support after ExitBootServices Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 50/54] efi: runtime: add relocation check Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 51/54] efi: loader: CONFIG_EFI_RT_VOLATILE_STORE Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 52/54] efi: loader: support ExitBootServices Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 53/54] efi: loader: pass along SMBIOS table Ahmad Fatoum
2025-12-18 10:38 ` [PATCH v1 54/54] ARM: configs: add multi_v7/8_efiloader_defconfig Ahmad Fatoum
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251218111242.1527495-46-a.fatoum@pengutronix.de \
--to=a.fatoum@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox