blob: 8c32059eddab866a74609b13b435a7cc5b9ba92b [file] [log] [blame]
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2020, Linaro Limited
4 */
5
6#define LOG_CATEGORY LOGC_EFI
Heinrich Schuchardt955a3212025-01-16 20:26:59 +01007
Sughosh Ganu8231d032025-03-17 14:04:02 +05308#include <blkmap.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +09009#include <bootm.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020010#include <env.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090011#include <image.h>
12#include <log.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020013#include <malloc.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090014#include <mapmem.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020015#include <dm.h>
16#include <fs.h>
Simon Glass3b1e60b2024-11-07 14:31:43 -070017#include <efi.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090018#include <efi_api.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020019#include <efi_load_initrd.h>
20#include <efi_loader.h>
21#include <efi_variable.h>
Simon Glass3b1e60b2024-11-07 14:31:43 -070022#include <host_arch.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090023#include <linux/libfdt.h>
24#include <linux/list.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020025
Simon Glass1824bf62024-11-07 14:31:44 -070026#undef BOOTEFI_NAME
27
Simon Glass3b1e60b2024-11-07 14:31:43 -070028#if HOST_ARCH == HOST_ARCH_X86_64
Simon Glass52b53af2024-11-07 14:31:46 -070029#define HOST_BOOTEFI_NAME "BOOTX64.EFI"
30#define HOST_PXE_ARCH 0x6
Simon Glass3b1e60b2024-11-07 14:31:43 -070031#elif HOST_ARCH == HOST_ARCH_X86
Simon Glass52b53af2024-11-07 14:31:46 -070032#define HOST_BOOTEFI_NAME "BOOTIA32.EFI"
33#define HOST_PXE_ARCH 0x7
Simon Glass3b1e60b2024-11-07 14:31:43 -070034#elif HOST_ARCH == HOST_ARCH_AARCH64
Simon Glass52b53af2024-11-07 14:31:46 -070035#define HOST_BOOTEFI_NAME "BOOTAA64.EFI"
36#define HOST_PXE_ARCH 0xb
Simon Glass3b1e60b2024-11-07 14:31:43 -070037#elif HOST_ARCH == HOST_ARCH_ARM
Simon Glass52b53af2024-11-07 14:31:46 -070038#define HOST_BOOTEFI_NAME "BOOTARM.EFI"
39#define HOST_PXE_ARCH 0xa
Simon Glass3b1e60b2024-11-07 14:31:43 -070040#elif HOST_ARCH == HOST_ARCH_RISCV32
Simon Glass52b53af2024-11-07 14:31:46 -070041#define HOST_BOOTEFI_NAME "BOOTRISCV32.EFI"
42#define HOST_PXE_ARCH 0x19
Simon Glass3b1e60b2024-11-07 14:31:43 -070043#elif HOST_ARCH == HOST_ARCH_RISCV64
Simon Glass52b53af2024-11-07 14:31:46 -070044#define HOST_BOOTEFI_NAME "BOOTRISCV64.EFI"
45#define HOST_PXE_ARCH 0x1b
Simon Glass3b1e60b2024-11-07 14:31:43 -070046#else
Simon Glass52b53af2024-11-07 14:31:46 -070047#error Unsupported Host architecture
Simon Glass3b1e60b2024-11-07 14:31:43 -070048#endif
49
Simon Glass52b53af2024-11-07 14:31:46 -070050#if defined(CONFIG_SANDBOX)
51#define BOOTEFI_NAME "BOOTSBOX.EFI"
52#elif defined(CONFIG_ARM64)
Simon Glass3b1e60b2024-11-07 14:31:43 -070053#define BOOTEFI_NAME "BOOTAA64.EFI"
54#elif defined(CONFIG_ARM)
55#define BOOTEFI_NAME "BOOTARM.EFI"
56#elif defined(CONFIG_X86_64)
57#define BOOTEFI_NAME "BOOTX64.EFI"
58#elif defined(CONFIG_X86)
59#define BOOTEFI_NAME "BOOTIA32.EFI"
60#elif defined(CONFIG_ARCH_RV32I)
61#define BOOTEFI_NAME "BOOTRISCV32.EFI"
62#elif defined(CONFIG_ARCH_RV64I)
63#define BOOTEFI_NAME "BOOTRISCV64.EFI"
64#else
65#error Unsupported UEFI architecture
66#endif
67
Heinrich Schuchardt6c405cb2021-10-15 02:33:33 +020068#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD)
69/* GUID used by Linux to identify the LoadFile2 protocol with the initrd */
70const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
71#endif
72
Simon Glass3b1e60b2024-11-07 14:31:43 -070073const char *efi_get_basename(void)
74{
Simon Glass52b53af2024-11-07 14:31:46 -070075 return efi_use_host_arch() ? HOST_BOOTEFI_NAME : BOOTEFI_NAME;
Simon Glass3b1e60b2024-11-07 14:31:43 -070076}
77
Simon Glass1824bf62024-11-07 14:31:44 -070078int efi_get_pxe_arch(void)
79{
Simon Glass52b53af2024-11-07 14:31:46 -070080 if (efi_use_host_arch())
81 return HOST_PXE_ARCH;
82
Simon Glass1824bf62024-11-07 14:31:44 -070083 /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */
84 if (IS_ENABLED(CONFIG_ARM64))
85 return 0xb;
86 else if (IS_ENABLED(CONFIG_ARM))
87 return 0xa;
88 else if (IS_ENABLED(CONFIG_X86_64))
89 return 0x6;
90 else if (IS_ENABLED(CONFIG_X86))
91 return 0x7;
92 else if (IS_ENABLED(CONFIG_ARCH_RV32I))
93 return 0x19;
94 else if (IS_ENABLED(CONFIG_ARCH_RV64I))
95 return 0x1b;
Simon Glass1824bf62024-11-07 14:31:44 -070096
97 return -EINVAL;
98}
99
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200100/**
101 * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by
102 * the value of BootCurrent
103 *
104 * @var_name: variable name
105 * @var_name_size: size of var_name
106 *
107 * Return: Status code
108 */
109static efi_status_t efi_create_current_boot_var(u16 var_name[],
110 size_t var_name_size)
111{
112 efi_uintn_t boot_current_size;
113 efi_status_t ret;
114 u16 boot_current;
115 u16 *pos;
116
117 boot_current_size = sizeof(boot_current);
Simon Glass90975372022-01-23 12:55:12 -0700118 ret = efi_get_variable_int(u"BootCurrent",
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200119 &efi_global_variable_guid, NULL,
120 &boot_current_size, &boot_current, NULL);
121 if (ret != EFI_SUCCESS)
122 goto out;
123
124 pos = efi_create_indexed_name(var_name, var_name_size, "Boot",
125 boot_current);
126 if (!pos) {
127 ret = EFI_OUT_OF_RESOURCES;
128 goto out;
129 }
130
131out:
132 return ret;
133}
134
135/**
136 * efi_get_dp_from_boot() - Retrieve and return a device path from an EFI
137 * Boot### variable.
138 * A boot option may contain an array of device paths.
139 * We use a VenMedia() with a specific GUID to identify
140 * the usage of the array members. This function is
141 * used to extract a specific device path
142 *
143 * @guid: vendor GUID of the VenMedia() device path node identifying the
144 * device path
145 *
146 * Return: device path or NULL. Caller must free the returned value
147 */
Heinrich Schuchardtefd90d72024-04-26 16:13:08 +0200148struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t *guid)
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200149{
Ilias Apalodimasb92f7ba2024-08-12 23:57:59 +0300150 struct efi_device_path *file_path = NULL;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200151 struct efi_load_option lo;
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +0200152 void *var_value;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200153 efi_uintn_t size;
154 efi_status_t ret;
155 u16 var_name[16];
156
157 ret = efi_create_current_boot_var(var_name, sizeof(var_name));
158 if (ret != EFI_SUCCESS)
159 return NULL;
160
161 var_value = efi_get_var(var_name, &efi_global_variable_guid, &size);
162 if (!var_value)
163 return NULL;
164
165 ret = efi_deserialize_load_option(&lo, var_value, &size);
166 if (ret != EFI_SUCCESS)
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +0200167 goto err;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200168
Ilias Apalodimasb92f7ba2024-08-12 23:57:59 +0300169 file_path = efi_dp_from_lo(&lo, guid);
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200170
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +0200171err:
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200172 free(var_value);
Ilias Apalodimasb92f7ba2024-08-12 23:57:59 +0300173 return file_path;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200174}
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300175
Heinrich Schuchardtf7529f72024-04-26 16:13:11 +0200176/**
177 * efi_load_option_dp_join() - join device-paths for load option
178 *
179 * @dp: in: binary device-path, out: joined device-path
180 * @dp_size: size of joined device-path
181 * @initrd_dp: initrd device-path or NULL
182 * @fdt_dp: device-tree device-path or NULL
183 * Return: status_code
184 */
185efi_status_t efi_load_option_dp_join(struct efi_device_path **dp,
186 size_t *dp_size,
187 struct efi_device_path *initrd_dp,
188 struct efi_device_path *fdt_dp)
189{
190 if (!dp)
191 return EFI_INVALID_PARAMETER;
192
193 *dp_size = efi_dp_size(*dp);
194
195 if (initrd_dp) {
196 struct efi_device_path *tmp_dp = *dp;
197
198 *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size);
199 efi_free_pool(tmp_dp);
200 if (!*dp)
201 return EFI_OUT_OF_RESOURCES;
202 *dp_size += efi_dp_size(initrd_dp) + sizeof(END);
203 }
204
205 if (fdt_dp) {
206 struct efi_device_path *tmp_dp = *dp;
207
208 *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size);
209 efi_free_pool(tmp_dp);
Heinrich Schuchardt9b4e1f52024-07-24 15:26:04 +0200210 if (!*dp)
Heinrich Schuchardtf7529f72024-04-26 16:13:11 +0200211 return EFI_OUT_OF_RESOURCES;
212 *dp_size += efi_dp_size(fdt_dp) + sizeof(END);
213 }
214
215 *dp_size += sizeof(END);
216
217 return EFI_SUCCESS;
218}
219
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300220const struct guid_to_hash_map {
221 efi_guid_t guid;
222 const char algo[32];
223 u32 bits;
224} guid_to_hash[] = {
225 {
226 EFI_CERT_X509_SHA256_GUID,
227 "sha256",
228 SHA256_SUM_LEN * 8,
229 },
230 {
231 EFI_CERT_SHA256_GUID,
232 "sha256",
233 SHA256_SUM_LEN * 8,
234 },
235 {
236 EFI_CERT_X509_SHA384_GUID,
237 "sha384",
238 SHA384_SUM_LEN * 8,
239 },
240 {
241 EFI_CERT_X509_SHA512_GUID,
242 "sha512",
243 SHA512_SUM_LEN * 8,
244 },
245};
246
247#define MAX_GUID_TO_HASH_COUNT ARRAY_SIZE(guid_to_hash)
248
249/** guid_to_sha_str - return the sha string e.g "sha256" for a given guid
250 * used on EFI security databases
251 *
252 * @guid: guid to check
253 *
254 * Return: len or 0 if no match is found
255 */
256const char *guid_to_sha_str(const efi_guid_t *guid)
257{
258 size_t i;
259
260 for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
261 if (!guidcmp(guid, &guid_to_hash[i].guid))
262 return guid_to_hash[i].algo;
263 }
264
265 return NULL;
266}
267
268/** algo_to_len - return the sha size in bytes for a given string
269 *
270 * @algo: string indicating hashing algorithm to check
271 *
272 * Return: length of hash in bytes or 0 if no match is found
273 */
274int algo_to_len(const char *algo)
275{
276 size_t i;
277
278 for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
279 if (!strcmp(algo, guid_to_hash[i].algo))
280 return guid_to_hash[i].bits / 8;
281 }
282
283 return 0;
284}
Masahisa Kojimac9611082022-07-22 11:39:10 +0900285
286/** efi_link_dev - link the efi_handle_t and udevice
287 *
288 * @handle: efi handle to associate with udevice
289 * @dev: udevice to associate with efi handle
290 *
291 * Return: 0 on success, negative on failure
292 */
293int efi_link_dev(efi_handle_t handle, struct udevice *dev)
294{
295 handle->dev = dev;
296 return dev_tag_set_ptr(dev, DM_TAG_EFI, handle);
297}
Heinrich Schuchardt34f34622022-10-03 09:47:51 +0200298
299/**
300 * efi_unlink_dev() - unlink udevice and handle
301 *
302 * @handle: EFI handle to unlink
303 *
304 * Return: 0 on success, negative on failure
305 */
306int efi_unlink_dev(efi_handle_t handle)
307{
308 int ret;
309
310 ret = dev_tag_del(handle->dev, DM_TAG_EFI);
311 if (ret)
312 return ret;
313 handle->dev = NULL;
314
315 return 0;
316}
Masahisa Kojima2f407f02022-12-02 13:59:35 +0900317
318static int u16_tohex(u16 c)
319{
320 if (c >= '0' && c <= '9')
321 return c - '0';
322 if (c >= 'A' && c <= 'F')
323 return c - 'A' + 10;
324
325 /* not hexadecimal */
326 return -1;
327}
328
329bool efi_varname_is_load_option(u16 *var_name16, int *index)
330{
331 int id, i, digit;
332
333 if (memcmp(var_name16, u"Boot", 8))
334 return false;
335
336 for (id = 0, i = 0; i < 4; i++) {
337 digit = u16_tohex(var_name16[4 + i]);
338 if (digit < 0)
339 break;
340 id = (id << 4) + digit;
341 }
342 if (i == 4 && !var_name16[8]) {
343 if (index)
344 *index = id;
345 return true;
346 }
347
348 return false;
349}
Masahisa Kojima7ec3c6f2022-12-19 11:33:12 +0900350
351/**
352 * efi_next_variable_name() - get next variable name
353 *
354 * This function is a wrapper of efi_get_next_variable_name_int().
355 * If efi_get_next_variable_name_int() returns EFI_BUFFER_TOO_SMALL,
356 * @size and @buf are updated by new buffer size and realloced buffer.
357 *
358 * @size: pointer to the buffer size
359 * @buf: pointer to the buffer
360 * @guid: pointer to the guid
361 * Return: status code
362 */
363efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf, efi_guid_t *guid)
364{
365 u16 *p;
366 efi_status_t ret;
367 efi_uintn_t buf_size = *size;
368
369 ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
370 if (ret == EFI_NOT_FOUND)
371 return ret;
372 if (ret == EFI_BUFFER_TOO_SMALL) {
373 p = realloc(*buf, buf_size);
374 if (!p)
375 return EFI_OUT_OF_RESOURCES;
376
377 *buf = p;
378 *size = buf_size;
379 ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
380 }
381
382 return ret;
383}
Raymond Mao70a76c52023-06-19 14:22:58 -0700384
385/**
386 * efi_search_bootorder() - search the boot option index in BootOrder
387 *
388 * @bootorder: pointer to the BootOrder variable
389 * @num: number of BootOrder entry
390 * @target: target boot option index to search
391 * @index: pointer to store the index of BootOrder variable
392 * Return: true if exists, false otherwise
393 */
394bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
395{
396 u32 i;
397
398 for (i = 0; i < num; i++) {
399 if (target == bootorder[i]) {
400 if (index)
401 *index = i;
402
403 return true;
404 }
405 }
406
407 return false;
408}
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900409
410/**
411 * efi_env_set_load_options() - set load options from environment variable
412 *
413 * @handle: the image handle
414 * @env_var: name of the environment variable
415 * @load_options: pointer to load options (output)
416 * Return: status code
417 */
418efi_status_t efi_env_set_load_options(efi_handle_t handle,
419 const char *env_var,
420 u16 **load_options)
421{
422 const char *env = env_get(env_var);
423 size_t size;
424 u16 *pos;
425 efi_status_t ret;
426
427 *load_options = NULL;
428 if (!env)
429 return EFI_SUCCESS;
430 size = sizeof(u16) * (utf8_utf16_strlen(env) + 1);
431 pos = calloc(size, 1);
432 if (!pos)
433 return EFI_OUT_OF_RESOURCES;
434 *load_options = pos;
435 utf8_utf16_strcpy(&pos, env);
436 ret = efi_set_load_options(handle, size, *load_options);
437 if (ret != EFI_SUCCESS) {
438 free(*load_options);
439 *load_options = NULL;
440 }
441 return ret;
442}
443
444/**
445 * copy_fdt() - Copy the device tree to a new location available to EFI
446 *
447 * The FDT is copied to a suitable location within the EFI memory map.
448 * Additional 12 KiB are added to the space in case the device tree needs to be
449 * expanded later with fdt_open_into().
450 *
451 * @fdtp: On entry a pointer to the flattened device tree.
452 * On exit a pointer to the copy of the flattened device tree.
453 * FDT start
454 * Return: status code
455 */
456static efi_status_t copy_fdt(void **fdtp)
457{
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900458 efi_status_t ret = 0;
459 void *fdt, *new_fdt;
Sughosh Ganu007604e2025-03-17 14:03:56 +0530460 static u64 new_fdt_addr;
461 static efi_uintn_t fdt_pages;
462 ulong fdt_size;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900463
464 /*
Sughosh Ganu007604e2025-03-17 14:03:56 +0530465 * Remove the configuration table that might already be
466 * installed, ignoring EFI_NOT_FOUND if no device-tree
467 * is installed
468 */
469 efi_install_configuration_table(&efi_guid_fdt, NULL);
470
471 if (new_fdt_addr) {
472 log_debug("%s: Found allocated memory at %#llx, with %#zx pages\n",
473 __func__, new_fdt_addr, fdt_pages);
474
475 ret = efi_free_pages(new_fdt_addr, fdt_pages);
476 if (ret != EFI_SUCCESS)
477 log_err("Unable to free up existing FDT memory region\n");
478
479 new_fdt_addr = 0;
480 fdt_pages = 0;
481 }
482
483 /*
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900484 * Give us at least 12 KiB of breathing room in case the device tree
485 * needs to be expanded later.
486 */
487 fdt = *fdtp;
488 fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
489 fdt_size = fdt_pages << EFI_PAGE_SHIFT;
490
491 ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
492 EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
493 &new_fdt_addr);
494 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200495 log_err("Failed to reserve space for FDT\n");
Sughosh Ganu007604e2025-03-17 14:03:56 +0530496 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900497 }
Sughosh Ganu007604e2025-03-17 14:03:56 +0530498 log_debug("%s: Allocated memory at %#llx, with %#zx pages\n",
499 __func__, new_fdt_addr, fdt_pages);
500
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900501 new_fdt = (void *)(uintptr_t)new_fdt_addr;
502 memcpy(new_fdt, fdt, fdt_totalsize(fdt));
503 fdt_set_totalsize(new_fdt, fdt_size);
504
Sughosh Ganu007604e2025-03-17 14:03:56 +0530505 *fdtp = new_fdt;
506
507 return EFI_SUCCESS;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900508}
509
510/**
Heinrich Schuchardt0a4a2f32024-01-26 08:54:30 +0100511 * efi_get_configuration_table() - get configuration table
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900512 *
513 * @guid: GUID of the configuration table
514 * Return: pointer to configuration table or NULL
515 */
Heinrich Schuchardt0a4a2f32024-01-26 08:54:30 +0100516void *efi_get_configuration_table(const efi_guid_t *guid)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900517{
518 size_t i;
519
520 for (i = 0; i < systab.nr_tables; i++) {
521 if (!guidcmp(guid, &systab.tables[i].guid))
522 return systab.tables[i].table;
523 }
524 return NULL;
525}
526
527/**
528 * efi_install_fdt() - install device tree
529 *
530 * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
531 * address will be installed as configuration table, otherwise the device
532 * tree located at the address indicated by environment variable fdt_addr or as
533 * fallback fdtcontroladdr will be used.
534 *
535 * On architectures using ACPI tables device trees shall not be installed as
536 * configuration table.
537 *
538 * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use
539 * the hardware device tree as indicated by environment variable
540 * fdt_addr or as fallback the internal device tree as indicated by
541 * the environment variable fdtcontroladdr
542 * Return: status code
543 */
544efi_status_t efi_install_fdt(void *fdt)
545{
546 struct bootm_headers img = { 0 };
547 efi_status_t ret;
548
549 /*
550 * The EBBR spec requires that we have either an FDT or an ACPI table
551 * but not both.
552 */
553 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) && fdt)
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200554 log_warning("Can't have ACPI table and device tree - ignoring DT.\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900555
556 if (fdt == EFI_FDT_USE_INTERNAL) {
557 const char *fdt_opt;
558 uintptr_t fdt_addr;
559
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900560 /* Check if there is a hardware device tree */
561 fdt_opt = env_get("fdt_addr");
562 /* Use our own device tree as fallback */
563 if (!fdt_opt) {
564 fdt_opt = env_get("fdtcontroladdr");
565 if (!fdt_opt) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200566 log_err("need device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900567 return EFI_NOT_FOUND;
568 }
569 }
570 fdt_addr = hextoul(fdt_opt, NULL);
571 if (!fdt_addr) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200572 log_err("invalid $fdt_addr or $fdtcontroladdr\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900573 return EFI_LOAD_ERROR;
574 }
575 fdt = map_sysmem(fdt_addr, 0);
576 }
577
578 /* Install device tree */
579 if (fdt_check_header(fdt)) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200580 log_err("invalid device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900581 return EFI_LOAD_ERROR;
582 }
583
Mark Kettenis98c598c2024-02-16 00:25:34 +0100584 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)) {
585 /* Create memory reservations as indicated by the device tree */
586 efi_carve_out_dt_rsv(fdt);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900587 return EFI_SUCCESS;
Mark Kettenis98c598c2024-02-16 00:25:34 +0100588 }
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900589
590 /* Prepare device tree for payload */
591 ret = copy_fdt(&fdt);
592 if (ret) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200593 log_err("out of memory\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900594 return EFI_OUT_OF_RESOURCES;
595 }
596
Sughosh Ganu291bf9c2024-08-26 17:29:18 +0530597 if (image_setup_libfdt(&img, fdt, false)) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200598 log_err("failed to process device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900599 return EFI_LOAD_ERROR;
600 }
601
Mark Kettenis98c598c2024-02-16 00:25:34 +0100602 /* Create memory reservations as indicated by the device tree */
603 efi_carve_out_dt_rsv(fdt);
604
Heinrich Schuchardt069079c2024-09-17 10:49:29 +0200605 efi_try_purge_rng_seed(fdt);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900606
607 if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
608 ret = efi_tcg2_measure_dtb(fdt);
609 if (ret == EFI_SECURITY_VIOLATION) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200610 log_err("failed to measure DTB\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900611 return ret;
612 }
613 }
614
615 /* Install device tree as UEFI table */
616 ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
617 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200618 log_err("failed to install device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900619 return ret;
620 }
621
622 return EFI_SUCCESS;
623}
624
625/**
626 * do_bootefi_exec() - execute EFI binary
627 *
628 * The image indicated by @handle is started. When it returns the allocated
629 * memory for the @load_options is freed.
630 *
631 * @handle: handle of loaded image
632 * @load_options: load options
633 * Return: status code
634 *
635 * Load the EFI binary into a newly assigned memory unwinding the relocation
636 * information, install the loaded image protocol, and call the binary.
637 */
638efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
639{
640 efi_status_t ret;
641 efi_uintn_t exit_data_size = 0;
642 u16 *exit_data = NULL;
643 struct efi_event *evt;
644
645 /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
646 switch_to_non_secure_mode();
647
648 /*
649 * The UEFI standard requires that the watchdog timer is set to five
650 * minutes when invoking an EFI boot option.
651 *
652 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
653 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
654 */
655 ret = efi_set_watchdog(300);
656 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200657 log_err("failed to set watchdog timer\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900658 goto out;
659 }
660
661 /* Call our payload! */
662 ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
663 if (ret != EFI_SUCCESS) {
664 log_err("## Application failed, r = %lu\n",
665 ret & ~EFI_ERROR_MASK);
666 if (exit_data) {
667 log_err("## %ls\n", exit_data);
668 efi_free_pool(exit_data);
669 }
670 }
671
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900672out:
673 free(load_options);
674
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900675 /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
676 list_for_each_entry(evt, &efi_events, link) {
677 if (evt->group &&
678 !guidcmp(evt->group,
679 &efi_guid_event_group_return_to_efibootmgr)) {
680 efi_signal_event(evt);
681 EFI_CALL(systab.boottime->close_event(evt));
682 break;
683 }
684 }
685
686 /* Control is returned to U-Boot, disable EFI watchdog */
687 efi_set_watchdog(0);
688
689 return ret;
690}
Sughosh Ganu8231d032025-03-17 14:04:02 +0530691
692/**
693 * pmem_node_efi_memmap_setup() - Add pmem node and tweak EFI memmap
694 * @fdt: The devicetree to which pmem node is added
695 * @addr: start address of the pmem node
696 * @size: size of the memory of the pmem node
697 *
698 * The function adds the pmem node to the device-tree along with removing
699 * the corresponding region from the EFI memory map. Used primarily to
700 * pass the information of a RAM based ISO image to the OS.
701 *
702 * Return: 0 on success, -ve value on error
703 */
704static int pmem_node_efi_memmap_setup(void *fdt, u64 addr, u64 size)
705{
706 int ret;
707 u64 pages;
708 efi_status_t status;
709
710 ret = fdt_fixup_pmem_region(fdt, addr, size);
711 if (ret) {
712 log_err("Failed to setup pmem node for addr %#llx, size %#llx, err %d\n",
713 addr, size, ret);
714 return ret;
715 }
716
717 /* Remove the pmem region from the EFI memory map */
718 pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
719 status = efi_update_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY,
720 false, true);
721 if (status != EFI_SUCCESS)
722 return -1;
723
724 return 0;
725}
726
727int fdt_efi_pmem_setup(void *fdt)
728{
729 return blkmap_get_preserved_pmem_slices(pmem_node_efi_memmap_setup,
730 fdt);
731}