blob: ab5678eb66c4341d031607de3ef79a4c817721f3 [file] [log] [blame]
Ilias Apalodimas37c3ca52021-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
AKASHI Takahiro64228202024-01-17 13:39:41 +09007#include <bootm.h>
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +02008#include <env.h>
AKASHI Takahiro64228202024-01-17 13:39:41 +09009#include <image.h>
10#include <log.h>
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +020011#include <malloc.h>
AKASHI Takahiro64228202024-01-17 13:39:41 +090012#include <mapmem.h>
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +020013#include <dm.h>
14#include <fs.h>
Simon Glass9fd623a2024-11-07 14:31:43 -070015#include <efi.h>
AKASHI Takahiro64228202024-01-17 13:39:41 +090016#include <efi_api.h>
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +020017#include <efi_load_initrd.h>
18#include <efi_loader.h>
19#include <efi_variable.h>
Simon Glass9fd623a2024-11-07 14:31:43 -070020#include <host_arch.h>
AKASHI Takahiro64228202024-01-17 13:39:41 +090021#include <linux/libfdt.h>
22#include <linux/list.h>
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +020023
Simon Glass8aa8a332024-11-07 14:31:44 -070024#undef BOOTEFI_NAME
25
Simon Glass9fd623a2024-11-07 14:31:43 -070026#if HOST_ARCH == HOST_ARCH_X86_64
Simon Glass7506c152024-11-07 14:31:46 -070027#define HOST_BOOTEFI_NAME "BOOTX64.EFI"
28#define HOST_PXE_ARCH 0x6
Simon Glass9fd623a2024-11-07 14:31:43 -070029#elif HOST_ARCH == HOST_ARCH_X86
Simon Glass7506c152024-11-07 14:31:46 -070030#define HOST_BOOTEFI_NAME "BOOTIA32.EFI"
31#define HOST_PXE_ARCH 0x7
Simon Glass9fd623a2024-11-07 14:31:43 -070032#elif HOST_ARCH == HOST_ARCH_AARCH64
Simon Glass7506c152024-11-07 14:31:46 -070033#define HOST_BOOTEFI_NAME "BOOTAA64.EFI"
34#define HOST_PXE_ARCH 0xb
Simon Glass9fd623a2024-11-07 14:31:43 -070035#elif HOST_ARCH == HOST_ARCH_ARM
Simon Glass7506c152024-11-07 14:31:46 -070036#define HOST_BOOTEFI_NAME "BOOTARM.EFI"
37#define HOST_PXE_ARCH 0xa
Simon Glass9fd623a2024-11-07 14:31:43 -070038#elif HOST_ARCH == HOST_ARCH_RISCV32
Simon Glass7506c152024-11-07 14:31:46 -070039#define HOST_BOOTEFI_NAME "BOOTRISCV32.EFI"
40#define HOST_PXE_ARCH 0x19
Simon Glass9fd623a2024-11-07 14:31:43 -070041#elif HOST_ARCH == HOST_ARCH_RISCV64
Simon Glass7506c152024-11-07 14:31:46 -070042#define HOST_BOOTEFI_NAME "BOOTRISCV64.EFI"
43#define HOST_PXE_ARCH 0x1b
Simon Glass9fd623a2024-11-07 14:31:43 -070044#else
Simon Glass7506c152024-11-07 14:31:46 -070045#error Unsupported Host architecture
Simon Glass9fd623a2024-11-07 14:31:43 -070046#endif
47
Simon Glass7506c152024-11-07 14:31:46 -070048#if defined(CONFIG_SANDBOX)
49#define BOOTEFI_NAME "BOOTSBOX.EFI"
50#elif defined(CONFIG_ARM64)
Simon Glass9fd623a2024-11-07 14:31:43 -070051#define BOOTEFI_NAME "BOOTAA64.EFI"
52#elif defined(CONFIG_ARM)
53#define BOOTEFI_NAME "BOOTARM.EFI"
54#elif defined(CONFIG_X86_64)
55#define BOOTEFI_NAME "BOOTX64.EFI"
56#elif defined(CONFIG_X86)
57#define BOOTEFI_NAME "BOOTIA32.EFI"
58#elif defined(CONFIG_ARCH_RV32I)
59#define BOOTEFI_NAME "BOOTRISCV32.EFI"
60#elif defined(CONFIG_ARCH_RV64I)
61#define BOOTEFI_NAME "BOOTRISCV64.EFI"
62#else
63#error Unsupported UEFI architecture
64#endif
65
Heinrich Schuchardt9ad37fe2021-10-15 02:33:33 +020066#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD)
67/* GUID used by Linux to identify the LoadFile2 protocol with the initrd */
68const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
69#endif
70
Simon Glass9fd623a2024-11-07 14:31:43 -070071const char *efi_get_basename(void)
72{
Simon Glass7506c152024-11-07 14:31:46 -070073 return efi_use_host_arch() ? HOST_BOOTEFI_NAME : BOOTEFI_NAME;
Simon Glass9fd623a2024-11-07 14:31:43 -070074}
75
Simon Glass8aa8a332024-11-07 14:31:44 -070076int efi_get_pxe_arch(void)
77{
Simon Glass7506c152024-11-07 14:31:46 -070078 if (efi_use_host_arch())
79 return HOST_PXE_ARCH;
80
Simon Glass8aa8a332024-11-07 14:31:44 -070081 /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */
82 if (IS_ENABLED(CONFIG_ARM64))
83 return 0xb;
84 else if (IS_ENABLED(CONFIG_ARM))
85 return 0xa;
86 else if (IS_ENABLED(CONFIG_X86_64))
87 return 0x6;
88 else if (IS_ENABLED(CONFIG_X86))
89 return 0x7;
90 else if (IS_ENABLED(CONFIG_ARCH_RV32I))
91 return 0x19;
92 else if (IS_ENABLED(CONFIG_ARCH_RV64I))
93 return 0x1b;
94 else if (IS_ENABLED(CONFIG_SANDBOX))
95 return 0; /* not used */
96
97 return -EINVAL;
98}
99
Ilias Apalodimas37c3ca52021-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 Glass156ccbc2022-01-23 12:55:12 -0700118 ret = efi_get_variable_int(u"BootCurrent",
Ilias Apalodimas37c3ca52021-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 Schuchardt8745f132024-04-26 16:13:08 +0200148struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t *guid)
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200149{
Ilias Apalodimas3a8ad052024-08-12 23:57:59 +0300150 struct efi_device_path *file_path = NULL;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200151 struct efi_load_option lo;
Heinrich Schuchardtdb61e702021-10-15 02:59:15 +0200152 void *var_value;
Ilias Apalodimas37c3ca52021-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 Schuchardtdb61e702021-10-15 02:59:15 +0200167 goto err;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200168
Ilias Apalodimas3a8ad052024-08-12 23:57:59 +0300169 file_path = efi_dp_from_lo(&lo, guid);
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200170
Heinrich Schuchardtdb61e702021-10-15 02:59:15 +0200171err:
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200172 free(var_value);
Ilias Apalodimas3a8ad052024-08-12 23:57:59 +0300173 return file_path;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200174}
Ilias Apalodimasb436cc62022-05-06 15:36:00 +0300175
Heinrich Schuchardt58bef192024-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 Schuchardt48940c62024-07-24 15:26:04 +0200210 if (!*dp)
Heinrich Schuchardt58bef192024-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 Apalodimasb436cc62022-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 Kojimaee576662022-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 Schuchardt16b27b62022-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 Kojima3ac026a2022-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 Kojimace327082022-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 Mao339b5272023-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 Takahiro64228202024-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{
458 unsigned long fdt_ram_start = -1L, fdt_pages;
459 efi_status_t ret = 0;
460 void *fdt, *new_fdt;
461 u64 new_fdt_addr;
462 uint fdt_size;
463 int i;
464
465 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
466 u64 ram_start = gd->bd->bi_dram[i].start;
467 u64 ram_size = gd->bd->bi_dram[i].size;
468
469 if (!ram_size)
470 continue;
471
472 if (ram_start < fdt_ram_start)
473 fdt_ram_start = ram_start;
474 }
475
476 /*
477 * Give us at least 12 KiB of breathing room in case the device tree
478 * needs to be expanded later.
479 */
480 fdt = *fdtp;
481 fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
482 fdt_size = fdt_pages << EFI_PAGE_SHIFT;
483
484 ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
485 EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
486 &new_fdt_addr);
487 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200488 log_err("Failed to reserve space for FDT\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900489 goto done;
490 }
491 new_fdt = (void *)(uintptr_t)new_fdt_addr;
492 memcpy(new_fdt, fdt, fdt_totalsize(fdt));
493 fdt_set_totalsize(new_fdt, fdt_size);
494
495 *fdtp = (void *)(uintptr_t)new_fdt_addr;
496done:
497 return ret;
498}
499
500/**
Heinrich Schuchardtfa077212024-01-26 08:54:30 +0100501 * efi_get_configuration_table() - get configuration table
AKASHI Takahiro64228202024-01-17 13:39:41 +0900502 *
503 * @guid: GUID of the configuration table
504 * Return: pointer to configuration table or NULL
505 */
Heinrich Schuchardtfa077212024-01-26 08:54:30 +0100506void *efi_get_configuration_table(const efi_guid_t *guid)
AKASHI Takahiro64228202024-01-17 13:39:41 +0900507{
508 size_t i;
509
510 for (i = 0; i < systab.nr_tables; i++) {
511 if (!guidcmp(guid, &systab.tables[i].guid))
512 return systab.tables[i].table;
513 }
514 return NULL;
515}
516
517/**
518 * efi_install_fdt() - install device tree
519 *
520 * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
521 * address will be installed as configuration table, otherwise the device
522 * tree located at the address indicated by environment variable fdt_addr or as
523 * fallback fdtcontroladdr will be used.
524 *
525 * On architectures using ACPI tables device trees shall not be installed as
526 * configuration table.
527 *
528 * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use
529 * the hardware device tree as indicated by environment variable
530 * fdt_addr or as fallback the internal device tree as indicated by
531 * the environment variable fdtcontroladdr
532 * Return: status code
533 */
534efi_status_t efi_install_fdt(void *fdt)
535{
536 struct bootm_headers img = { 0 };
537 efi_status_t ret;
538
539 /*
540 * The EBBR spec requires that we have either an FDT or an ACPI table
541 * but not both.
542 */
543 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) && fdt)
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200544 log_warning("Can't have ACPI table and device tree - ignoring DT.\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900545
546 if (fdt == EFI_FDT_USE_INTERNAL) {
547 const char *fdt_opt;
548 uintptr_t fdt_addr;
549
550 /* Look for device tree that is already installed */
Heinrich Schuchardtfa077212024-01-26 08:54:30 +0100551 if (efi_get_configuration_table(&efi_guid_fdt))
AKASHI Takahiro64228202024-01-17 13:39:41 +0900552 return EFI_SUCCESS;
553 /* Check if there is a hardware device tree */
554 fdt_opt = env_get("fdt_addr");
555 /* Use our own device tree as fallback */
556 if (!fdt_opt) {
557 fdt_opt = env_get("fdtcontroladdr");
558 if (!fdt_opt) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200559 log_err("need device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900560 return EFI_NOT_FOUND;
561 }
562 }
563 fdt_addr = hextoul(fdt_opt, NULL);
564 if (!fdt_addr) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200565 log_err("invalid $fdt_addr or $fdtcontroladdr\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900566 return EFI_LOAD_ERROR;
567 }
568 fdt = map_sysmem(fdt_addr, 0);
569 }
570
571 /* Install device tree */
572 if (fdt_check_header(fdt)) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200573 log_err("invalid device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900574 return EFI_LOAD_ERROR;
575 }
576
Mark Kettenis1431ab82024-02-16 00:25:34 +0100577 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)) {
578 /* Create memory reservations as indicated by the device tree */
579 efi_carve_out_dt_rsv(fdt);
AKASHI Takahiro64228202024-01-17 13:39:41 +0900580 return EFI_SUCCESS;
Mark Kettenis1431ab82024-02-16 00:25:34 +0100581 }
AKASHI Takahiro64228202024-01-17 13:39:41 +0900582
583 /* Prepare device tree for payload */
584 ret = copy_fdt(&fdt);
585 if (ret) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200586 log_err("out of memory\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900587 return EFI_OUT_OF_RESOURCES;
588 }
589
Sughosh Ganued17a332024-08-26 17:29:18 +0530590 if (image_setup_libfdt(&img, fdt, false)) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200591 log_err("failed to process device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900592 return EFI_LOAD_ERROR;
593 }
594
Mark Kettenis1431ab82024-02-16 00:25:34 +0100595 /* Create memory reservations as indicated by the device tree */
596 efi_carve_out_dt_rsv(fdt);
597
Heinrich Schuchardtb03b2a42024-09-17 10:49:29 +0200598 efi_try_purge_rng_seed(fdt);
AKASHI Takahiro64228202024-01-17 13:39:41 +0900599
600 if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
601 ret = efi_tcg2_measure_dtb(fdt);
602 if (ret == EFI_SECURITY_VIOLATION) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200603 log_err("failed to measure DTB\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900604 return ret;
605 }
606 }
607
608 /* Install device tree as UEFI table */
609 ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
610 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200611 log_err("failed to install device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900612 return ret;
613 }
614
615 return EFI_SUCCESS;
616}
617
618/**
619 * do_bootefi_exec() - execute EFI binary
620 *
621 * The image indicated by @handle is started. When it returns the allocated
622 * memory for the @load_options is freed.
623 *
624 * @handle: handle of loaded image
625 * @load_options: load options
626 * Return: status code
627 *
628 * Load the EFI binary into a newly assigned memory unwinding the relocation
629 * information, install the loaded image protocol, and call the binary.
630 */
631efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
632{
633 efi_status_t ret;
634 efi_uintn_t exit_data_size = 0;
635 u16 *exit_data = NULL;
636 struct efi_event *evt;
637
638 /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
639 switch_to_non_secure_mode();
640
641 /*
642 * The UEFI standard requires that the watchdog timer is set to five
643 * minutes when invoking an EFI boot option.
644 *
645 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
646 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
647 */
648 ret = efi_set_watchdog(300);
649 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200650 log_err("failed to set watchdog timer\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900651 goto out;
652 }
653
654 /* Call our payload! */
655 ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
656 if (ret != EFI_SUCCESS) {
657 log_err("## Application failed, r = %lu\n",
658 ret & ~EFI_ERROR_MASK);
659 if (exit_data) {
660 log_err("## %ls\n", exit_data);
661 efi_free_pool(exit_data);
662 }
663 }
664
AKASHI Takahiro64228202024-01-17 13:39:41 +0900665out:
666 free(load_options);
667
AKASHI Takahiro64228202024-01-17 13:39:41 +0900668 /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
669 list_for_each_entry(evt, &efi_events, link) {
670 if (evt->group &&
671 !guidcmp(evt->group,
672 &efi_guid_event_group_return_to_efibootmgr)) {
673 efi_signal_event(evt);
674 EFI_CALL(systab.boottime->close_event(evt));
675 break;
676 }
677 }
678
679 /* Control is returned to U-Boot, disable EFI watchdog */
680 efi_set_watchdog(0);
681
682 return ret;
683}