mail archive of the barebox mailing list
 help / color / mirror / Atom feed
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




  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