blob: 69977b2af0ee0c8c3b120fafaae717ea3db49ce0 [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Grafe2b04f22016-03-10 00:27:20 +01002/*
3 * EFI application loader
4 *
5 * Copyright (c) 2016 Alexander Graf
Alexander Grafe2b04f22016-03-10 00:27:20 +01006 */
7
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +02008#define LOG_CATEGORY LOGC_EFI
9
Alexander Grafe2b04f22016-03-10 00:27:20 +010010#include <common.h>
Heinrich Schuchardtaf64c3e2021-01-24 14:34:12 +000011#include <bootm.h>
Heinrich Schuchardtaa0b11b2019-01-08 18:13:06 +010012#include <charset.h>
Alexander Grafe2b04f22016-03-10 00:27:20 +010013#include <command.h>
Simon Glass11c89f32017-05-17 17:18:03 -060014#include <dm.h>
Alexander Grafe2b04f22016-03-10 00:27:20 +010015#include <efi_loader.h>
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +020016#include <efi_selftest.h>
Simon Glass0af6e2d2019-08-01 09:46:52 -060017#include <env.h>
Alexander Grafe2b04f22016-03-10 00:27:20 +010018#include <errno.h>
Simon Glass2dc9c342020-05-10 11:40:01 -060019#include <image.h>
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +020020#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070021#include <malloc.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060022#include <asm/global_data.h>
Masahiro Yamada75f82d02018-03-05 01:20:11 +090023#include <linux/libfdt.h>
24#include <linux/libfdt_env.h>
Alexander Grafa2414512018-06-18 17:22:58 +020025#include <mapmem.h>
Alexander Graffdbae012016-04-11 23:51:01 +020026#include <memalign.h>
Simon Glassc2194bf2016-09-25 15:27:32 -060027#include <asm-generic/sections.h>
28#include <linux/linkage.h>
Alexander Graf2ff5cc32016-04-11 16:55:26 +020029
30DECLARE_GLOBAL_DATA_PTR;
Alexander Grafe2b04f22016-03-10 00:27:20 +010031
AKASHI Takahiro203d1962023-11-21 10:29:43 +090032static struct efi_device_path *test_image_path;
33static struct efi_device_path *test_device_path;
Rob Clarkf8db9222017-09-13 18:05:33 -040034static struct efi_device_path *bootefi_image_path;
35static struct efi_device_path *bootefi_device_path;
Heinrich Schuchardt6b821592021-01-12 12:46:24 +010036static void *image_addr;
37static size_t image_size;
Alexander Grafe2b04f22016-03-10 00:27:20 +010038
Heinrich Schuchardt031ea8f2019-07-14 13:00:44 +020039/**
Rui Miguel Silva433f15a2022-05-11 10:55:40 +010040 * efi_get_image_parameters() - return image parameters
41 *
42 * @img_addr: address of loaded image in memory
43 * @img_size: size of loaded image
44 */
45void efi_get_image_parameters(void **img_addr, size_t *img_size)
46{
47 *img_addr = image_addr;
48 *img_size = image_size;
49}
50
51/**
Heinrich Schuchardt6b821592021-01-12 12:46:24 +010052 * efi_clear_bootdev() - clear boot device
53 */
54static void efi_clear_bootdev(void)
55{
56 efi_free_pool(bootefi_device_path);
57 efi_free_pool(bootefi_image_path);
58 bootefi_device_path = NULL;
59 bootefi_image_path = NULL;
60 image_addr = NULL;
61 image_size = 0;
62}
63
64/**
65 * efi_set_bootdev() - set boot device
66 *
67 * This function is called when a file is loaded, e.g. via the 'load' command.
68 * We use the path to this file to inform the UEFI binary about the boot device.
69 *
70 * @dev: device, e.g. "MMC"
71 * @devnr: number of the device, e.g. "1:2"
72 * @path: path to file loaded
73 * @buffer: buffer with file loaded
74 * @buffer_size: size of file loaded
75 */
76void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
77 void *buffer, size_t buffer_size)
78{
79 struct efi_device_path *device, *image;
80 efi_status_t ret;
81
Simon Glass95c1d252022-01-29 14:58:37 -070082 log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
83 devnr, path, buffer, buffer_size);
84
Heinrich Schuchardt6b821592021-01-12 12:46:24 +010085 /* Forget overwritten image */
86 if (buffer + buffer_size >= image_addr &&
87 image_addr + image_size >= buffer)
88 efi_clear_bootdev();
89
90 /* Remember only PE-COFF and FIT images */
91 if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
Simon Glass95c1d252022-01-29 14:58:37 -070092 if (IS_ENABLED(CONFIG_FIT) &&
93 !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
94 /*
95 * FIT images of type EFI_OS are started via command
96 * bootm. We should not use their boot device with the
97 * bootefi command.
98 */
99 buffer = 0;
100 buffer_size = 0;
101 } else {
102 log_debug("- not remembering image\n");
Heinrich Schuchardt6b821592021-01-12 12:46:24 +0100103 return;
Simon Glass95c1d252022-01-29 14:58:37 -0700104 }
Heinrich Schuchardt6b821592021-01-12 12:46:24 +0100105 }
106
107 /* efi_set_bootdev() is typically called repeatedly, recover memory */
108 efi_clear_bootdev();
109
110 image_addr = buffer;
111 image_size = buffer_size;
112
113 ret = efi_dp_from_name(dev, devnr, path, &device, &image);
114 if (ret == EFI_SUCCESS) {
115 bootefi_device_path = device;
116 if (image) {
117 /* FIXME: image should not contain device */
118 struct efi_device_path *image_tmp = image;
119
120 efi_dp_split_file_path(image, &device, &image);
121 efi_free_pool(image_tmp);
122 }
123 bootefi_image_path = image;
Heinrich Schuchardtb274e772022-07-10 15:46:57 +0200124 log_debug("- boot device %pD\n", device);
Simon Glass95c1d252022-01-29 14:58:37 -0700125 if (image)
Heinrich Schuchardtb274e772022-07-10 15:46:57 +0200126 log_debug("- image %pD\n", image);
Heinrich Schuchardt6b821592021-01-12 12:46:24 +0100127 } else {
Simon Glass95c1d252022-01-29 14:58:37 -0700128 log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
Heinrich Schuchardt6b821592021-01-12 12:46:24 +0100129 efi_clear_bootdev();
130 }
131}
132
133/**
Heinrich Schuchardt25c6be52020-08-07 17:47:13 +0200134 * efi_env_set_load_options() - set load options from environment variable
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200135 *
Heinrich Schuchardte6263952020-01-03 22:53:42 +0100136 * @handle: the image handle
137 * @env_var: name of the environment variable
138 * @load_options: pointer to load options (output)
139 * Return: status code
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200140 */
Heinrich Schuchardt25c6be52020-08-07 17:47:13 +0200141static efi_status_t efi_env_set_load_options(efi_handle_t handle,
142 const char *env_var,
143 u16 **load_options)
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200144{
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200145 const char *env = env_get(env_var);
Heinrich Schuchardt25c6be52020-08-07 17:47:13 +0200146 size_t size;
Heinrich Schuchardtde527802018-08-31 21:31:33 +0200147 u16 *pos;
AKASHI Takahiroe25a7b82019-04-19 12:22:28 +0900148 efi_status_t ret;
149
Heinrich Schuchardte6263952020-01-03 22:53:42 +0100150 *load_options = NULL;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200151 if (!env)
Heinrich Schuchardt25c6be52020-08-07 17:47:13 +0200152 return EFI_SUCCESS;
153 size = sizeof(u16) * (utf8_utf16_strlen(env) + 1);
154 pos = calloc(size, 1);
155 if (!pos)
AKASHI Takahiroe25a7b82019-04-19 12:22:28 +0900156 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardte6263952020-01-03 22:53:42 +0100157 *load_options = pos;
Heinrich Schuchardtde527802018-08-31 21:31:33 +0200158 utf8_utf16_strcpy(&pos, env);
Heinrich Schuchardt25c6be52020-08-07 17:47:13 +0200159 ret = efi_set_load_options(handle, size, *load_options);
160 if (ret != EFI_SUCCESS) {
161 free(*load_options);
162 *load_options = NULL;
163 }
164 return ret;
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200165}
166
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200167#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
168
Simon Glass5d618df2018-08-08 03:54:30 -0600169/**
170 * copy_fdt() - Copy the device tree to a new location available to EFI
171 *
Heinrich Schuchardtb23f9b72018-11-18 17:58:52 +0100172 * The FDT is copied to a suitable location within the EFI memory map.
Heinrich Schuchardtdcdca292018-11-18 17:58:49 +0100173 * Additional 12 KiB are added to the space in case the device tree needs to be
Simon Glass5d618df2018-08-08 03:54:30 -0600174 * expanded later with fdt_open_into().
175 *
Heinrich Schuchardtb23f9b72018-11-18 17:58:52 +0100176 * @fdtp: On entry a pointer to the flattened device tree.
177 * On exit a pointer to the copy of the flattened device tree.
Heinrich Schuchardt96af56e2018-11-12 18:55:22 +0100178 * FDT start
179 * Return: status code
Simon Glass5d618df2018-08-08 03:54:30 -0600180 */
Heinrich Schuchardtb23f9b72018-11-18 17:58:52 +0100181static efi_status_t copy_fdt(void **fdtp)
Alexander Graf2ff5cc32016-04-11 16:55:26 +0200182{
Alexander Graffdbae012016-04-11 23:51:01 +0200183 unsigned long fdt_ram_start = -1L, fdt_pages;
Simon Glass5d618df2018-08-08 03:54:30 -0600184 efi_status_t ret = 0;
185 void *fdt, *new_fdt;
Alexander Graffdbae012016-04-11 23:51:01 +0200186 u64 new_fdt_addr;
Simon Glass5d618df2018-08-08 03:54:30 -0600187 uint fdt_size;
Alexander Graffdbae012016-04-11 23:51:01 +0200188 int i;
Alexander Graf2ff5cc32016-04-11 16:55:26 +0200189
Simon Glass5d618df2018-08-08 03:54:30 -0600190 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
191 u64 ram_start = gd->bd->bi_dram[i].start;
192 u64 ram_size = gd->bd->bi_dram[i].size;
Alexander Graf2ff5cc32016-04-11 16:55:26 +0200193
Alexander Graffdbae012016-04-11 23:51:01 +0200194 if (!ram_size)
195 continue;
196
197 if (ram_start < fdt_ram_start)
198 fdt_ram_start = ram_start;
199 }
200
Simon Glass56bbcc12018-06-18 08:08:25 -0600201 /*
Heinrich Schuchardtdcdca292018-11-18 17:58:49 +0100202 * Give us at least 12 KiB of breathing room in case the device tree
203 * needs to be expanded later.
Simon Glass56bbcc12018-06-18 08:08:25 -0600204 */
Heinrich Schuchardtb23f9b72018-11-18 17:58:52 +0100205 fdt = *fdtp;
Heinrich Schuchardtdcdca292018-11-18 17:58:49 +0100206 fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
207 fdt_size = fdt_pages << EFI_PAGE_SHIFT;
Alexander Graffdbae012016-04-11 23:51:01 +0200208
Heinrich Schuchardt45a755d2023-02-23 20:27:38 +0100209 ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
Heinrich Schuchardte00764b2020-05-06 20:32:31 +0200210 EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
Simon Glass5d618df2018-08-08 03:54:30 -0600211 &new_fdt_addr);
212 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt45a755d2023-02-23 20:27:38 +0100213 log_err("ERROR: Failed to reserve space for FDT\n");
214 goto done;
Alexander Graffdbae012016-04-11 23:51:01 +0200215 }
Heinrich Schuchardtb23f9b72018-11-18 17:58:52 +0100216 new_fdt = (void *)(uintptr_t)new_fdt_addr;
Alexander Graf2ff5cc32016-04-11 16:55:26 +0200217 memcpy(new_fdt, fdt, fdt_totalsize(fdt));
218 fdt_set_totalsize(new_fdt, fdt_size);
219
Heinrich Schuchardtb23f9b72018-11-18 17:58:52 +0100220 *fdtp = (void *)(uintptr_t)new_fdt_addr;
Simon Glass5d618df2018-08-08 03:54:30 -0600221done:
222 return ret;
Alexander Graf2ff5cc32016-04-11 16:55:26 +0200223}
224
Heinrich Schuchardt928de7d2020-08-27 12:52:20 +0200225/**
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200226 * get_config_table() - get configuration table
227 *
228 * @guid: GUID of the configuration table
229 * Return: pointer to configuration table or NULL
230 */
231static void *get_config_table(const efi_guid_t *guid)
232{
233 size_t i;
234
235 for (i = 0; i < systab.nr_tables; i++) {
236 if (!guidcmp(guid, &systab.tables[i].guid))
237 return systab.tables[i].table;
238 }
239 return NULL;
Alexander Graf22c88bf2018-04-06 09:40:51 +0200240}
241
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200242#endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */
243
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900244/**
Heinrich Schuchardt6fbb8ac2019-11-28 06:46:09 +0100245 * efi_install_fdt() - install device tree
Heinrich Schuchardta3086cd2019-05-12 20:16:25 +0200246 *
Heinrich Schuchardtb112ac22020-02-07 22:10:49 +0100247 * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
248 * address will will be installed as configuration table, otherwise the device
249 * tree located at the address indicated by environment variable fdt_addr or as
250 * fallback fdtcontroladdr will be used.
Heinrich Schuchardta3086cd2019-05-12 20:16:25 +0200251 *
Heinrich Schuchardt6fbb8ac2019-11-28 06:46:09 +0100252 * On architectures using ACPI tables device trees shall not be installed as
253 * configuration table.
Heinrich Schuchardta3086cd2019-05-12 20:16:25 +0200254 *
Heinrich Schuchardtb112ac22020-02-07 22:10:49 +0100255 * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use the
Heinrich Schuchardte478ad52019-12-04 12:31:12 +0100256 * the hardware device tree as indicated by environment variable
257 * fdt_addr or as fallback the internal device tree as indicated by
258 * the environment variable fdtcontroladdr
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900259 * Return: status code
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900260 */
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100261efi_status_t efi_install_fdt(void *fdt)
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900262{
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200263 /*
264 * The EBBR spec requires that we have either an FDT or an ACPI table
265 * but not both.
266 */
267#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100268 if (fdt) {
Alexander Graf08994972022-02-27 13:18:56 +0100269 log_warning("WARNING: Can't have ACPI table and device tree - ignoring DT.\n");
270 return EFI_SUCCESS;
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200271 }
272#else
Simon Glassdf00afa2022-09-06 20:26:50 -0600273 struct bootm_headers img = { 0 };
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900274 efi_status_t ret;
275
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100276 if (fdt == EFI_FDT_USE_INTERNAL) {
Heinrich Schuchardt6fbb8ac2019-11-28 06:46:09 +0100277 const char *fdt_opt;
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100278 uintptr_t fdt_addr;
Heinrich Schuchardt6fbb8ac2019-11-28 06:46:09 +0100279
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200280 /* Look for device tree that is already installed */
281 if (get_config_table(&efi_guid_fdt))
282 return EFI_SUCCESS;
Heinrich Schuchardte478ad52019-12-04 12:31:12 +0100283 /* Check if there is a hardware device tree */
284 fdt_opt = env_get("fdt_addr");
285 /* Use our own device tree as fallback */
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200286 if (!fdt_opt) {
Heinrich Schuchardte478ad52019-12-04 12:31:12 +0100287 fdt_opt = env_get("fdtcontroladdr");
288 if (!fdt_opt) {
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200289 log_err("ERROR: need device tree\n");
Heinrich Schuchardte478ad52019-12-04 12:31:12 +0100290 return EFI_NOT_FOUND;
291 }
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200292 }
Simon Glass3ff49ec2021-07-24 09:03:29 -0600293 fdt_addr = hextoul(fdt_opt, NULL);
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200294 if (!fdt_addr) {
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200295 log_err("ERROR: invalid $fdt_addr or $fdtcontroladdr\n");
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200296 return EFI_LOAD_ERROR;
AKASHI Takahiro451e9912019-04-19 12:22:30 +0900297 }
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100298 fdt = map_sysmem(fdt_addr, 0);
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200299 }
AKASHI Takahiro451e9912019-04-19 12:22:30 +0900300
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200301 /* Install device tree */
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200302 if (fdt_check_header(fdt)) {
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200303 log_err("ERROR: invalid device tree\n");
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200304 return EFI_LOAD_ERROR;
305 }
AKASHI Takahiro451e9912019-04-19 12:22:30 +0900306
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200307 /* Prepare device tree for payload */
308 ret = copy_fdt(&fdt);
309 if (ret) {
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200310 log_err("ERROR: out of memory\n");
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200311 return EFI_OUT_OF_RESOURCES;
312 }
AKASHI Takahiro451e9912019-04-19 12:22:30 +0900313
Simon Glass30762dd2023-11-12 08:27:44 -0700314 if (image_setup_libfdt(&img, fdt, NULL)) {
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200315 log_err("ERROR: failed to process device tree\n");
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200316 return EFI_LOAD_ERROR;
317 }
318
Heinrich Schuchardt74811c82020-03-14 10:59:34 +0100319 /* Create memory reservations as indicated by the device tree */
320 efi_carve_out_dt_rsv(fdt);
321
Ilias Apalodimase4e56602022-01-03 14:07:37 +0200322 efi_try_purge_kaslr_seed(fdt);
323
Etienne Carriereb9064352023-02-16 17:29:48 +0100324 if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
325 ret = efi_tcg2_measure_dtb(fdt);
326 if (ret == EFI_SECURITY_VIOLATION) {
327 log_err("ERROR: failed to measure DTB\n");
328 return ret;
329 }
330 }
331
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200332 /* Install device tree as UEFI table */
333 ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
334 if (ret != EFI_SUCCESS) {
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200335 log_err("ERROR: failed to install device tree\n");
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200336 return ret;
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900337 }
Heinrich Schuchardt4420a332019-04-20 13:33:55 +0200338#endif /* GENERATE_ACPI_TABLE */
AKASHI Takahirocc02f172019-04-19 12:22:29 +0900339
340 return EFI_SUCCESS;
341}
342
Simon Glass4d77ee62018-11-25 20:14:39 -0700343/**
Heinrich Schuchardt3c3a7352018-09-23 17:21:51 +0200344 * do_bootefi_exec() - execute EFI binary
345 *
Heinrich Schuchardtaa4a66c2020-08-15 23:10:22 +0200346 * The image indicated by @handle is started. When it returns the allocated
347 * memory for the @load_options is freed.
348 *
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900349 * @handle: handle of loaded image
Heinrich Schuchardtaa4a66c2020-08-15 23:10:22 +0200350 * @load_options: load options
Heinrich Schuchardt3c3a7352018-09-23 17:21:51 +0200351 * Return: status code
352 *
353 * Load the EFI binary into a newly assigned memory unwinding the relocation
354 * information, install the loaded image protocol, and call the binary.
Alexander Grafe2b04f22016-03-10 00:27:20 +0100355 */
Heinrich Schuchardta7647a72020-08-07 17:49:39 +0200356static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
Alexander Grafe2b04f22016-03-10 00:27:20 +0100357{
Heinrich Schuchardt4b055a22018-03-03 15:29:01 +0100358 efi_status_t ret;
Heinrich Schuchardt3d445122019-04-30 17:57:30 +0200359 efi_uintn_t exit_data_size = 0;
360 u16 *exit_data = NULL;
Masahisa Kojima1923f362023-11-10 13:25:39 +0900361 struct efi_event *evt;
Rob Clark18ceba72017-10-10 08:23:06 -0400362
Heinrich Schuchardtaf64c3e2021-01-24 14:34:12 +0000363 /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
364 switch_to_non_secure_mode();
365
Masahisa Kojimad250a8f2022-02-22 09:58:30 +0900366 /*
367 * The UEFI standard requires that the watchdog timer is set to five
368 * minutes when invoking an EFI boot option.
369 *
370 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
371 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
372 */
373 ret = efi_set_watchdog(300);
374 if (ret != EFI_SUCCESS) {
375 log_err("ERROR: Failed to set watchdog timer\n");
376 goto out;
377 }
378
Alexander Grafe2b04f22016-03-10 00:27:20 +0100379 /* Call our payload! */
Heinrich Schuchardt3d445122019-04-30 17:57:30 +0200380 ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
Heinrich Schuchardtbb38a1f2020-07-17 20:21:00 +0200381 if (ret != EFI_SUCCESS) {
382 log_err("## Application failed, r = %lu\n",
383 ret & ~EFI_ERROR_MASK);
384 if (exit_data) {
385 log_err("## %ls\n", exit_data);
386 efi_free_pool(exit_data);
387 }
Heinrich Schuchardt3d445122019-04-30 17:57:30 +0200388 }
Rob Clarkf8db9222017-09-13 18:05:33 -0400389
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900390 efi_restore_gd();
Simon Glass4d77ee62018-11-25 20:14:39 -0700391
Masahisa Kojimad250a8f2022-02-22 09:58:30 +0900392out:
Heinrich Schuchardte6263952020-01-03 22:53:42 +0100393 free(load_options);
Rob Clarkf8db9222017-09-13 18:05:33 -0400394
Ilias Apalodimas7e052792022-10-16 11:36:32 +0300395 if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) {
396 if (efi_initrd_deregister() != EFI_SUCCESS)
397 log_err("Failed to remove loadfile2 for initrd\n");
398 }
Ilias Apalodimasb307e3d2021-03-17 21:55:00 +0200399
Masahisa Kojima1923f362023-11-10 13:25:39 +0900400 /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
401 list_for_each_entry(evt, &efi_events, link) {
402 if (evt->group &&
403 !guidcmp(evt->group,
404 &efi_guid_event_group_return_to_efibootmgr)) {
405 efi_signal_event(evt);
406 EFI_CALL(systab.boottime->close_event(evt));
407 break;
408 }
409 }
410
Masahisa Kojimad250a8f2022-02-22 09:58:30 +0900411 /* Control is returned to U-Boot, disable EFI watchdog */
412 efi_set_watchdog(0);
413
Rob Clarkf8db9222017-09-13 18:05:33 -0400414 return ret;
Alexander Grafe2b04f22016-03-10 00:27:20 +0100415}
416
AKASHI Takahirocf819832019-04-19 12:22:33 +0900417/**
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900418 * efi_bootmgr_run() - execute EFI boot manager
419 * fdt: Flat device tree
420 *
421 * Invoke EFI boot manager and execute a binary depending on
422 * boot options. If @fdt is not NULL, it will be passed to
423 * the executed binary.
AKASHI Takahirocf819832019-04-19 12:22:33 +0900424 *
AKASHI Takahirocf819832019-04-19 12:22:33 +0900425 * Return: status code
AKASHI Takahirocf819832019-04-19 12:22:33 +0900426 */
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900427static efi_status_t efi_bootmgr_run(void *fdt)
AKASHI Takahiro758733d2019-04-19 12:22:32 +0900428{
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900429 efi_handle_t handle;
Heinrich Schuchardta7647a72020-08-07 17:49:39 +0200430 void *load_options;
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900431 efi_status_t ret;
AKASHI Takahirocf819832019-04-19 12:22:33 +0900432
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900433 /* Initialize EFI drivers */
434 ret = efi_init_obj_list();
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900435 if (ret != EFI_SUCCESS) {
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900436 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
437 ret & ~EFI_ERROR_MASK);
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900438 return CMD_RET_FAILURE;
439 }
AKASHI Takahiro758733d2019-04-19 12:22:32 +0900440
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900441 ret = efi_install_fdt(fdt);
AKASHI Takahirocf819832019-04-19 12:22:33 +0900442 if (ret != EFI_SUCCESS)
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900443 return ret;
444
445 ret = efi_bootmgr_load(&handle, &load_options);
446 if (ret != EFI_SUCCESS) {
447 log_notice("EFI boot manager: Cannot load any image\n");
448 return ret;
449 }
AKASHI Takahiro758733d2019-04-19 12:22:32 +0900450
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900451 return do_bootefi_exec(handle, load_options);
AKASHI Takahiro758733d2019-04-19 12:22:32 +0900452}
453
Heinrich Schuchardt031ea8f2019-07-14 13:00:44 +0200454/**
Heinrich Schuchardtffb90592019-12-07 20:51:06 +0100455 * efi_run_image() - run loaded UEFI image
456 *
457 * @source_buffer: memory address of the UEFI image
458 * @source_size: size of the UEFI image
459 * Return: status code
460 */
461efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
462{
463 efi_handle_t mem_handle = NULL, handle;
464 struct efi_device_path *file_path = NULL;
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000465 struct efi_device_path *msg_path;
Ilias Apalodimas3e2c20f2022-10-06 16:08:44 +0300466 efi_status_t ret, ret2;
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000467 u16 *load_options;
Heinrich Schuchardtffb90592019-12-07 20:51:06 +0100468
469 if (!bootefi_device_path || !bootefi_image_path) {
Simon Glass95c1d252022-01-29 14:58:37 -0700470 log_debug("Not loaded from disk\n");
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900471 /*
472 * Special case for efi payload not loaded from disk,
473 * such as 'bootefi hello' or for example payload
474 * loaded directly into memory via JTAG, etc:
475 */
476 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
Heinrich Schuchardtffb90592019-12-07 20:51:06 +0100477 (uintptr_t)source_buffer,
478 source_size);
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900479 /*
480 * Make sure that device for device_path exist
481 * in load_image(). Otherwise, shell and grub will fail.
482 */
Ilias Apalodimas3e2c20f2022-10-06 16:08:44 +0300483 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
484 &efi_guid_device_path,
485 file_path, NULL);
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900486 if (ret != EFI_SUCCESS)
487 goto out;
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000488 msg_path = file_path;
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900489 } else {
Heinrich Schuchardtffb90592019-12-07 20:51:06 +0100490 file_path = efi_dp_append(bootefi_device_path,
491 bootefi_image_path);
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000492 msg_path = bootefi_image_path;
Simon Glass95c1d252022-01-29 14:58:37 -0700493 log_debug("Loaded from disk\n");
AKASHI Takahirofbd3ba52019-04-19 12:22:34 +0900494 }
495
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000496 log_info("Booting %pD\n", msg_path);
497
Heinrich Schuchardtffb90592019-12-07 20:51:06 +0100498 ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
499 source_size, &handle));
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000500 if (ret != EFI_SUCCESS) {
501 log_err("Loading image failed\n");
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900502 goto out;
Heinrich Schuchardtc3a9c9c2020-08-25 17:54:05 +0000503 }
Heinrich Schuchardta7647a72020-08-07 17:49:39 +0200504
505 /* Transfer environment variable as load options */
506 ret = efi_env_set_load_options(handle, "bootargs", &load_options);
507 if (ret != EFI_SUCCESS)
508 goto out;
509
510 ret = do_bootefi_exec(handle, load_options);
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900511
512out:
Ilias Apalodimas3e2c20f2022-10-06 16:08:44 +0300513 ret2 = efi_uninstall_multiple_protocol_interfaces(mem_handle,
514 &efi_guid_device_path,
515 file_path, NULL);
Heinrich Schuchardt6e35d3b2020-04-20 12:44:56 +0200516 efi_free_pool(file_path);
Ilias Apalodimas3e2c20f2022-10-06 16:08:44 +0300517 return (ret != EFI_SUCCESS) ? ret : ret2;
AKASHI Takahirofbd3ba52019-04-19 12:22:34 +0900518}
519
AKASHI Takahirod52dacb2023-11-21 10:29:42 +0900520/**
521 * efi_binary_run() - run loaded UEFI image
522 *
523 * @image: memory address of the UEFI image
524 * @size: size of the UEFI image
525 *
526 * Execute an EFI binary image loaded at @image.
527 * @size may be zero if the binary is loaded with U-Boot load command.
528 *
529 * Return: status code
530 */
531static efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
532{
533 efi_status_t ret;
534
535 /* Initialize EFI drivers */
536 ret = efi_init_obj_list();
537 if (ret != EFI_SUCCESS) {
538 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
539 ret & ~EFI_ERROR_MASK);
540 return ret;
541 }
542
543 ret = efi_install_fdt(fdt);
544 if (ret != EFI_SUCCESS)
545 return ret;
546
547 return efi_run_image(image, size);
548}
549
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900550static efi_status_t bootefi_run_prepare(const char *load_options_path,
551 struct efi_device_path *device_path,
552 struct efi_device_path *image_path,
553 struct efi_loaded_image_obj **image_objp,
554 struct efi_loaded_image **loaded_image_infop)
555{
556 efi_status_t ret;
Heinrich Schuchardte6263952020-01-03 22:53:42 +0100557 u16 *load_options;
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900558
559 ret = efi_setup_loaded_image(device_path, image_path, image_objp,
560 loaded_image_infop);
561 if (ret != EFI_SUCCESS)
562 return ret;
563
564 /* Transfer environment variable as load options */
Heinrich Schuchardt25c6be52020-08-07 17:47:13 +0200565 return efi_env_set_load_options((efi_handle_t)*image_objp,
566 load_options_path,
567 &load_options);
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900568}
569
Simon Glass93f25592018-11-25 20:14:37 -0700570/**
571 * bootefi_test_prepare() - prepare to run an EFI test
572 *
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100573 * Prepare to run a test as if it were provided by a loaded image.
Simon Glass93f25592018-11-25 20:14:37 -0700574 *
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100575 * @image_objp: pointer to be set to the loaded image handle
576 * @loaded_image_infop: pointer to be set to the loaded image protocol
577 * @path: dummy file path used to construct the device path
578 * set in the loaded image protocol
579 * @load_options_path: name of a U-Boot environment variable. Its value is
580 * set as load options in the loaded image protocol.
581 * Return: status code
Simon Glass93f25592018-11-25 20:14:37 -0700582 */
583static efi_status_t bootefi_test_prepare
584 (struct efi_loaded_image_obj **image_objp,
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100585 struct efi_loaded_image **loaded_image_infop, const char *path,
586 const char *load_options_path)
Simon Glass93f25592018-11-25 20:14:37 -0700587{
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100588 efi_status_t ret;
589
Simon Glass93f25592018-11-25 20:14:37 -0700590 /* Construct a dummy device path */
AKASHI Takahiro203d1962023-11-21 10:29:43 +0900591 test_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0);
592 if (!test_device_path)
Simon Glass93f25592018-11-25 20:14:37 -0700593 return EFI_OUT_OF_RESOURCES;
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100594
AKASHI Takahiro203d1962023-11-21 10:29:43 +0900595 test_image_path = efi_dp_from_file(NULL, path);
596 if (!test_image_path) {
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100597 ret = EFI_OUT_OF_RESOURCES;
598 goto failure;
599 }
600
AKASHI Takahiro203d1962023-11-21 10:29:43 +0900601 ret = bootefi_run_prepare(load_options_path, test_device_path,
602 test_image_path, image_objp,
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100603 loaded_image_infop);
604 if (ret == EFI_SUCCESS)
605 return ret;
Simon Glass93f25592018-11-25 20:14:37 -0700606
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100607failure:
AKASHI Takahiro203d1962023-11-21 10:29:43 +0900608 efi_free_pool(test_device_path);
609 efi_free_pool(test_image_path);
610 /* TODO: not sure calling clear function is necessary */
Heinrich Schuchardt6b821592021-01-12 12:46:24 +0100611 efi_clear_bootdev();
Heinrich Schuchardtfd9cbe32019-01-12 14:42:40 +0100612 return ret;
Simon Glass93f25592018-11-25 20:14:37 -0700613}
614
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900615/**
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200616 * do_efi_selftest() - execute EFI selftest
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900617 *
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900618 * Return: status code
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900619 */
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200620static int do_efi_selftest(void)
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900621{
622 struct efi_loaded_image_obj *image_obj;
623 struct efi_loaded_image *loaded_image_info;
624 efi_status_t ret;
625
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900626 ret = bootefi_test_prepare(&image_obj, &loaded_image_info,
627 "\\selftest", "efi_selftest");
628 if (ret != EFI_SUCCESS)
629 return CMD_RET_FAILURE;
630
631 /* Execute the test */
632 ret = EFI_CALL(efi_selftest(&image_obj->header, &systab));
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300633 efi_restore_gd();
634 free(loaded_image_info->load_options);
AKASHI Takahiro203d1962023-11-21 10:29:43 +0900635 efi_free_pool(test_device_path);
636 efi_free_pool(test_image_path);
Ilias Apalodimasb09ecf12023-07-24 13:17:36 +0300637 if (ret != EFI_SUCCESS)
638 efi_delete_handle(&image_obj->header);
639 else
640 ret = efi_delete_handle(&image_obj->header);
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900641
642 return ret != EFI_SUCCESS;
643}
Simon Glass93f25592018-11-25 20:14:37 -0700644
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200645/**
646 * do_bootefi() - execute `bootefi` command
647 *
648 * @cmdtp: table entry describing command
649 * @flag: bitmap indicating how the command was invoked
650 * @argc: number of arguments
651 * @argv: command line arguments
652 * Return: status code
653 */
Simon Glassed38aef2020-05-10 11:40:03 -0600654static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc,
655 char *const argv[])
Alexander Grafe2b04f22016-03-10 00:27:20 +0100656{
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200657 efi_status_t ret;
AKASHI Takahiro28cb4a82023-11-21 10:29:39 +0900658 char *p;
659 void *fdt, *image_buf;
660 unsigned long addr, size;
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200661
AKASHI Takahiro09a81c72019-04-19 12:22:31 +0900662 if (argc < 2)
663 return CMD_RET_USAGE;
AKASHI Takahirocf819832019-04-19 12:22:33 +0900664
Heinrich Schuchardt3ea20e72022-05-19 08:00:56 +0200665 if (argc > 2) {
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100666 uintptr_t fdt_addr;
667
Simon Glass3ff49ec2021-07-24 09:03:29 -0600668 fdt_addr = hextoul(argv[2], NULL);
Heinrich Schuchardt62467412019-12-08 01:07:01 +0100669 fdt = map_sysmem(fdt_addr, 0);
670 } else {
671 fdt = EFI_FDT_USE_INTERNAL;
672 }
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900673
674 if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) &&
675 !strcmp(argv[1], "bootmgr")) {
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900676 ret = efi_bootmgr_run(fdt);
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200677
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900678 if (ret == EFI_INVALID_PARAMETER)
679 return CMD_RET_USAGE;
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900680 else if (ret)
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900681 return CMD_RET_FAILURE;
682
AKASHI Takahiro4ab6c5b2023-11-21 10:29:41 +0900683 return CMD_RET_SUCCESS;
Heinrich Schuchardtb2625e82021-01-15 19:02:50 +0100684 }
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900685
686 if (IS_ENABLED(CONFIG_CMD_BOOTEFI_SELFTEST) &&
687 !strcmp(argv[1], "selftest")) {
688 /* Initialize EFI drivers */
689 ret = efi_init_obj_list();
690 if (ret != EFI_SUCCESS) {
691 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
692 ret & ~EFI_ERROR_MASK);
693 return CMD_RET_FAILURE;
694 }
695
696 ret = efi_install_fdt(fdt);
697 if (ret == EFI_INVALID_PARAMETER)
698 return CMD_RET_USAGE;
699 else if (ret != EFI_SUCCESS)
700 return CMD_RET_FAILURE;
701
Heinrich Schuchardt8fc56c62019-05-12 20:16:25 +0200702 return do_efi_selftest();
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900703 }
AKASHI Takahiro28cb4a82023-11-21 10:29:39 +0900704
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900705 if (!IS_ENABLED(CONFIG_CMD_BOOTEFI_BINARY))
706 return CMD_RET_SUCCESS;
707
708 if (IS_ENABLED(CONFIG_CMD_BOOTEFI_HELLO) &&
709 !strcmp(argv[1], "hello")) {
AKASHI Takahiro28cb4a82023-11-21 10:29:39 +0900710 image_buf = __efi_helloworld_begin;
711 size = __efi_helloworld_end - __efi_helloworld_begin;
712 efi_clear_bootdev();
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900713 } else {
AKASHI Takahiro28cb4a82023-11-21 10:29:39 +0900714 addr = strtoul(argv[1], NULL, 16);
715 /* Check that a numeric value was passed */
716 if (!addr)
717 return CMD_RET_USAGE;
718 image_buf = map_sysmem(addr, 0);
719
720 p = strchr(argv[1], ':');
721 if (p) {
722 size = strtoul(++p, NULL, 16);
723 if (!size)
724 return CMD_RET_USAGE;
725 efi_clear_bootdev();
726 } else {
727 if (image_buf != image_addr) {
728 log_err("No UEFI binary known at %s\n",
729 argv[1]);
730 return CMD_RET_FAILURE;
731 }
732 size = image_size;
733 }
Heinrich Schuchardt3ea20e72022-05-19 08:00:56 +0200734 }
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900735
AKASHI Takahirod52dacb2023-11-21 10:29:42 +0900736 ret = efi_binary_run(image_buf, size, fdt);
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900737
AKASHI Takahiro6a6858e2023-11-21 10:29:40 +0900738 if (ret == EFI_INVALID_PARAMETER)
739 return CMD_RET_USAGE;
AKASHI Takahirod52dacb2023-11-21 10:29:42 +0900740 else if (ret)
AKASHI Takahiro28cb4a82023-11-21 10:29:39 +0900741 return CMD_RET_FAILURE;
742
743 return CMD_RET_SUCCESS;
Alexander Grafe2b04f22016-03-10 00:27:20 +0100744}
745
Tom Rini03f146c2023-10-07 15:13:08 -0400746U_BOOT_LONGHELP(bootefi,
Heinrich Schuchardt3ea20e72022-05-19 08:00:56 +0200747 "<image address>[:<image size>] [<fdt address>]\n"
748 " - boot EFI payload\n"
Simon Glassfac4ced2016-11-07 08:47:08 -0700749#ifdef CONFIG_CMD_BOOTEFI_HELLO
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200750 "bootefi hello\n"
751 " - boot a sample Hello World application stored within U-Boot\n"
752#endif
753#ifdef CONFIG_CMD_BOOTEFI_SELFTEST
Heinrich Schuchardt44ab21b2018-03-03 15:29:03 +0100754 "bootefi selftest [fdt address]\n"
Heinrich Schuchardtd33ae3e2017-09-15 10:06:11 +0200755 " - boot an EFI selftest application stored within U-Boot\n"
Heinrich Schuchardt02efd5d2017-10-18 18:13:13 +0200756 " Use environment variable efi_selftest to select a single test.\n"
757 " Use 'setenv efi_selftest list' to enumerate all tests.\n"
Simon Glassfac4ced2016-11-07 08:47:08 -0700758#endif
Heinrich Schuchardtb2625e82021-01-15 19:02:50 +0100759#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR
AKASHI Takahiro14ff23b2019-04-19 12:22:35 +0900760 "bootefi bootmgr [fdt address]\n"
Rob Clarkc84c1102017-09-13 18:05:38 -0400761 " - load and boot EFI payload based on BootOrder/BootXXXX variables.\n"
762 "\n"
763 " If specified, the device tree located at <fdt address> gets\n"
Heinrich Schuchardtb2625e82021-01-15 19:02:50 +0100764 " exposed as EFI configuration table.\n"
765#endif
Tom Rini03f146c2023-10-07 15:13:08 -0400766 );
Alexander Grafe2b04f22016-03-10 00:27:20 +0100767
768U_BOOT_CMD(
Kyle Evans2c3bf4e2022-04-10 16:05:55 -0500769 bootefi, 4, 0, do_bootefi,
Sergey Kubushyn268f19e2016-06-07 11:14:31 -0700770 "Boots an EFI payload from memory",
Alexander Grafe2b04f22016-03-10 00:27:20 +0100771 bootefi_help_text
772);