blob: bf96f61d3d0eddea1aaead0188154518f4e46713 [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;
Simon Glass8aa8a332024-11-07 14:31:44 -070094
95 return -EINVAL;
96}
97
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +020098/**
99 * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by
100 * the value of BootCurrent
101 *
102 * @var_name: variable name
103 * @var_name_size: size of var_name
104 *
105 * Return: Status code
106 */
107static efi_status_t efi_create_current_boot_var(u16 var_name[],
108 size_t var_name_size)
109{
110 efi_uintn_t boot_current_size;
111 efi_status_t ret;
112 u16 boot_current;
113 u16 *pos;
114
115 boot_current_size = sizeof(boot_current);
Simon Glass156ccbc2022-01-23 12:55:12 -0700116 ret = efi_get_variable_int(u"BootCurrent",
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200117 &efi_global_variable_guid, NULL,
118 &boot_current_size, &boot_current, NULL);
119 if (ret != EFI_SUCCESS)
120 goto out;
121
122 pos = efi_create_indexed_name(var_name, var_name_size, "Boot",
123 boot_current);
124 if (!pos) {
125 ret = EFI_OUT_OF_RESOURCES;
126 goto out;
127 }
128
129out:
130 return ret;
131}
132
133/**
134 * efi_get_dp_from_boot() - Retrieve and return a device path from an EFI
135 * Boot### variable.
136 * A boot option may contain an array of device paths.
137 * We use a VenMedia() with a specific GUID to identify
138 * the usage of the array members. This function is
139 * used to extract a specific device path
140 *
141 * @guid: vendor GUID of the VenMedia() device path node identifying the
142 * device path
143 *
144 * Return: device path or NULL. Caller must free the returned value
145 */
Heinrich Schuchardt8745f132024-04-26 16:13:08 +0200146struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t *guid)
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200147{
Ilias Apalodimas3a8ad052024-08-12 23:57:59 +0300148 struct efi_device_path *file_path = NULL;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200149 struct efi_load_option lo;
Heinrich Schuchardtdb61e702021-10-15 02:59:15 +0200150 void *var_value;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200151 efi_uintn_t size;
152 efi_status_t ret;
153 u16 var_name[16];
154
155 ret = efi_create_current_boot_var(var_name, sizeof(var_name));
156 if (ret != EFI_SUCCESS)
157 return NULL;
158
159 var_value = efi_get_var(var_name, &efi_global_variable_guid, &size);
160 if (!var_value)
161 return NULL;
162
163 ret = efi_deserialize_load_option(&lo, var_value, &size);
164 if (ret != EFI_SUCCESS)
Heinrich Schuchardtdb61e702021-10-15 02:59:15 +0200165 goto err;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200166
Ilias Apalodimas3a8ad052024-08-12 23:57:59 +0300167 file_path = efi_dp_from_lo(&lo, guid);
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200168
Heinrich Schuchardtdb61e702021-10-15 02:59:15 +0200169err:
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200170 free(var_value);
Ilias Apalodimas3a8ad052024-08-12 23:57:59 +0300171 return file_path;
Ilias Apalodimas37c3ca52021-03-17 21:54:59 +0200172}
Ilias Apalodimasb436cc62022-05-06 15:36:00 +0300173
Heinrich Schuchardt58bef192024-04-26 16:13:11 +0200174/**
175 * efi_load_option_dp_join() - join device-paths for load option
176 *
177 * @dp: in: binary device-path, out: joined device-path
178 * @dp_size: size of joined device-path
179 * @initrd_dp: initrd device-path or NULL
180 * @fdt_dp: device-tree device-path or NULL
181 * Return: status_code
182 */
183efi_status_t efi_load_option_dp_join(struct efi_device_path **dp,
184 size_t *dp_size,
185 struct efi_device_path *initrd_dp,
186 struct efi_device_path *fdt_dp)
187{
188 if (!dp)
189 return EFI_INVALID_PARAMETER;
190
191 *dp_size = efi_dp_size(*dp);
192
193 if (initrd_dp) {
194 struct efi_device_path *tmp_dp = *dp;
195
196 *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size);
197 efi_free_pool(tmp_dp);
198 if (!*dp)
199 return EFI_OUT_OF_RESOURCES;
200 *dp_size += efi_dp_size(initrd_dp) + sizeof(END);
201 }
202
203 if (fdt_dp) {
204 struct efi_device_path *tmp_dp = *dp;
205
206 *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size);
207 efi_free_pool(tmp_dp);
Heinrich Schuchardt48940c62024-07-24 15:26:04 +0200208 if (!*dp)
Heinrich Schuchardt58bef192024-04-26 16:13:11 +0200209 return EFI_OUT_OF_RESOURCES;
210 *dp_size += efi_dp_size(fdt_dp) + sizeof(END);
211 }
212
213 *dp_size += sizeof(END);
214
215 return EFI_SUCCESS;
216}
217
Ilias Apalodimasb436cc62022-05-06 15:36:00 +0300218const struct guid_to_hash_map {
219 efi_guid_t guid;
220 const char algo[32];
221 u32 bits;
222} guid_to_hash[] = {
223 {
224 EFI_CERT_X509_SHA256_GUID,
225 "sha256",
226 SHA256_SUM_LEN * 8,
227 },
228 {
229 EFI_CERT_SHA256_GUID,
230 "sha256",
231 SHA256_SUM_LEN * 8,
232 },
233 {
234 EFI_CERT_X509_SHA384_GUID,
235 "sha384",
236 SHA384_SUM_LEN * 8,
237 },
238 {
239 EFI_CERT_X509_SHA512_GUID,
240 "sha512",
241 SHA512_SUM_LEN * 8,
242 },
243};
244
245#define MAX_GUID_TO_HASH_COUNT ARRAY_SIZE(guid_to_hash)
246
247/** guid_to_sha_str - return the sha string e.g "sha256" for a given guid
248 * used on EFI security databases
249 *
250 * @guid: guid to check
251 *
252 * Return: len or 0 if no match is found
253 */
254const char *guid_to_sha_str(const efi_guid_t *guid)
255{
256 size_t i;
257
258 for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
259 if (!guidcmp(guid, &guid_to_hash[i].guid))
260 return guid_to_hash[i].algo;
261 }
262
263 return NULL;
264}
265
266/** algo_to_len - return the sha size in bytes for a given string
267 *
268 * @algo: string indicating hashing algorithm to check
269 *
270 * Return: length of hash in bytes or 0 if no match is found
271 */
272int algo_to_len(const char *algo)
273{
274 size_t i;
275
276 for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
277 if (!strcmp(algo, guid_to_hash[i].algo))
278 return guid_to_hash[i].bits / 8;
279 }
280
281 return 0;
282}
Masahisa Kojimaee576662022-07-22 11:39:10 +0900283
284/** efi_link_dev - link the efi_handle_t and udevice
285 *
286 * @handle: efi handle to associate with udevice
287 * @dev: udevice to associate with efi handle
288 *
289 * Return: 0 on success, negative on failure
290 */
291int efi_link_dev(efi_handle_t handle, struct udevice *dev)
292{
293 handle->dev = dev;
294 return dev_tag_set_ptr(dev, DM_TAG_EFI, handle);
295}
Heinrich Schuchardt16b27b62022-10-03 09:47:51 +0200296
297/**
298 * efi_unlink_dev() - unlink udevice and handle
299 *
300 * @handle: EFI handle to unlink
301 *
302 * Return: 0 on success, negative on failure
303 */
304int efi_unlink_dev(efi_handle_t handle)
305{
306 int ret;
307
308 ret = dev_tag_del(handle->dev, DM_TAG_EFI);
309 if (ret)
310 return ret;
311 handle->dev = NULL;
312
313 return 0;
314}
Masahisa Kojima3ac026a2022-12-02 13:59:35 +0900315
316static int u16_tohex(u16 c)
317{
318 if (c >= '0' && c <= '9')
319 return c - '0';
320 if (c >= 'A' && c <= 'F')
321 return c - 'A' + 10;
322
323 /* not hexadecimal */
324 return -1;
325}
326
327bool efi_varname_is_load_option(u16 *var_name16, int *index)
328{
329 int id, i, digit;
330
331 if (memcmp(var_name16, u"Boot", 8))
332 return false;
333
334 for (id = 0, i = 0; i < 4; i++) {
335 digit = u16_tohex(var_name16[4 + i]);
336 if (digit < 0)
337 break;
338 id = (id << 4) + digit;
339 }
340 if (i == 4 && !var_name16[8]) {
341 if (index)
342 *index = id;
343 return true;
344 }
345
346 return false;
347}
Masahisa Kojimace327082022-12-19 11:33:12 +0900348
349/**
350 * efi_next_variable_name() - get next variable name
351 *
352 * This function is a wrapper of efi_get_next_variable_name_int().
353 * If efi_get_next_variable_name_int() returns EFI_BUFFER_TOO_SMALL,
354 * @size and @buf are updated by new buffer size and realloced buffer.
355 *
356 * @size: pointer to the buffer size
357 * @buf: pointer to the buffer
358 * @guid: pointer to the guid
359 * Return: status code
360 */
361efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf, efi_guid_t *guid)
362{
363 u16 *p;
364 efi_status_t ret;
365 efi_uintn_t buf_size = *size;
366
367 ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
368 if (ret == EFI_NOT_FOUND)
369 return ret;
370 if (ret == EFI_BUFFER_TOO_SMALL) {
371 p = realloc(*buf, buf_size);
372 if (!p)
373 return EFI_OUT_OF_RESOURCES;
374
375 *buf = p;
376 *size = buf_size;
377 ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
378 }
379
380 return ret;
381}
Raymond Mao339b5272023-06-19 14:22:58 -0700382
383/**
384 * efi_search_bootorder() - search the boot option index in BootOrder
385 *
386 * @bootorder: pointer to the BootOrder variable
387 * @num: number of BootOrder entry
388 * @target: target boot option index to search
389 * @index: pointer to store the index of BootOrder variable
390 * Return: true if exists, false otherwise
391 */
392bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
393{
394 u32 i;
395
396 for (i = 0; i < num; i++) {
397 if (target == bootorder[i]) {
398 if (index)
399 *index = i;
400
401 return true;
402 }
403 }
404
405 return false;
406}
AKASHI Takahiro64228202024-01-17 13:39:41 +0900407
408/**
409 * efi_env_set_load_options() - set load options from environment variable
410 *
411 * @handle: the image handle
412 * @env_var: name of the environment variable
413 * @load_options: pointer to load options (output)
414 * Return: status code
415 */
416efi_status_t efi_env_set_load_options(efi_handle_t handle,
417 const char *env_var,
418 u16 **load_options)
419{
420 const char *env = env_get(env_var);
421 size_t size;
422 u16 *pos;
423 efi_status_t ret;
424
425 *load_options = NULL;
426 if (!env)
427 return EFI_SUCCESS;
428 size = sizeof(u16) * (utf8_utf16_strlen(env) + 1);
429 pos = calloc(size, 1);
430 if (!pos)
431 return EFI_OUT_OF_RESOURCES;
432 *load_options = pos;
433 utf8_utf16_strcpy(&pos, env);
434 ret = efi_set_load_options(handle, size, *load_options);
435 if (ret != EFI_SUCCESS) {
436 free(*load_options);
437 *load_options = NULL;
438 }
439 return ret;
440}
441
442/**
443 * copy_fdt() - Copy the device tree to a new location available to EFI
444 *
445 * The FDT is copied to a suitable location within the EFI memory map.
446 * Additional 12 KiB are added to the space in case the device tree needs to be
447 * expanded later with fdt_open_into().
448 *
449 * @fdtp: On entry a pointer to the flattened device tree.
450 * On exit a pointer to the copy of the flattened device tree.
451 * FDT start
452 * Return: status code
453 */
454static efi_status_t copy_fdt(void **fdtp)
455{
456 unsigned long fdt_ram_start = -1L, fdt_pages;
457 efi_status_t ret = 0;
458 void *fdt, *new_fdt;
459 u64 new_fdt_addr;
460 uint fdt_size;
461 int i;
462
463 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
464 u64 ram_start = gd->bd->bi_dram[i].start;
465 u64 ram_size = gd->bd->bi_dram[i].size;
466
467 if (!ram_size)
468 continue;
469
470 if (ram_start < fdt_ram_start)
471 fdt_ram_start = ram_start;
472 }
473
474 /*
475 * Give us at least 12 KiB of breathing room in case the device tree
476 * needs to be expanded later.
477 */
478 fdt = *fdtp;
479 fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000);
480 fdt_size = fdt_pages << EFI_PAGE_SHIFT;
481
482 ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
483 EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
484 &new_fdt_addr);
485 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200486 log_err("Failed to reserve space for FDT\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900487 goto done;
488 }
489 new_fdt = (void *)(uintptr_t)new_fdt_addr;
490 memcpy(new_fdt, fdt, fdt_totalsize(fdt));
491 fdt_set_totalsize(new_fdt, fdt_size);
492
493 *fdtp = (void *)(uintptr_t)new_fdt_addr;
494done:
495 return ret;
496}
497
498/**
Heinrich Schuchardtfa077212024-01-26 08:54:30 +0100499 * efi_get_configuration_table() - get configuration table
AKASHI Takahiro64228202024-01-17 13:39:41 +0900500 *
501 * @guid: GUID of the configuration table
502 * Return: pointer to configuration table or NULL
503 */
Heinrich Schuchardtfa077212024-01-26 08:54:30 +0100504void *efi_get_configuration_table(const efi_guid_t *guid)
AKASHI Takahiro64228202024-01-17 13:39:41 +0900505{
506 size_t i;
507
508 for (i = 0; i < systab.nr_tables; i++) {
509 if (!guidcmp(guid, &systab.tables[i].guid))
510 return systab.tables[i].table;
511 }
512 return NULL;
513}
514
515/**
516 * efi_install_fdt() - install device tree
517 *
518 * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
519 * address will be installed as configuration table, otherwise the device
520 * tree located at the address indicated by environment variable fdt_addr or as
521 * fallback fdtcontroladdr will be used.
522 *
523 * On architectures using ACPI tables device trees shall not be installed as
524 * configuration table.
525 *
526 * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use
527 * the hardware device tree as indicated by environment variable
528 * fdt_addr or as fallback the internal device tree as indicated by
529 * the environment variable fdtcontroladdr
530 * Return: status code
531 */
532efi_status_t efi_install_fdt(void *fdt)
533{
534 struct bootm_headers img = { 0 };
535 efi_status_t ret;
536
537 /*
538 * The EBBR spec requires that we have either an FDT or an ACPI table
539 * but not both.
540 */
541 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) && fdt)
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200542 log_warning("Can't have ACPI table and device tree - ignoring DT.\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900543
544 if (fdt == EFI_FDT_USE_INTERNAL) {
545 const char *fdt_opt;
546 uintptr_t fdt_addr;
547
548 /* Look for device tree that is already installed */
Heinrich Schuchardtfa077212024-01-26 08:54:30 +0100549 if (efi_get_configuration_table(&efi_guid_fdt))
AKASHI Takahiro64228202024-01-17 13:39:41 +0900550 return EFI_SUCCESS;
551 /* Check if there is a hardware device tree */
552 fdt_opt = env_get("fdt_addr");
553 /* Use our own device tree as fallback */
554 if (!fdt_opt) {
555 fdt_opt = env_get("fdtcontroladdr");
556 if (!fdt_opt) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200557 log_err("need device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900558 return EFI_NOT_FOUND;
559 }
560 }
561 fdt_addr = hextoul(fdt_opt, NULL);
562 if (!fdt_addr) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200563 log_err("invalid $fdt_addr or $fdtcontroladdr\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900564 return EFI_LOAD_ERROR;
565 }
566 fdt = map_sysmem(fdt_addr, 0);
567 }
568
569 /* Install device tree */
570 if (fdt_check_header(fdt)) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200571 log_err("invalid device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900572 return EFI_LOAD_ERROR;
573 }
574
Mark Kettenis1431ab82024-02-16 00:25:34 +0100575 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)) {
576 /* Create memory reservations as indicated by the device tree */
577 efi_carve_out_dt_rsv(fdt);
AKASHI Takahiro64228202024-01-17 13:39:41 +0900578 return EFI_SUCCESS;
Mark Kettenis1431ab82024-02-16 00:25:34 +0100579 }
AKASHI Takahiro64228202024-01-17 13:39:41 +0900580
581 /* Prepare device tree for payload */
582 ret = copy_fdt(&fdt);
583 if (ret) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200584 log_err("out of memory\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900585 return EFI_OUT_OF_RESOURCES;
586 }
587
Sughosh Ganued17a332024-08-26 17:29:18 +0530588 if (image_setup_libfdt(&img, fdt, false)) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200589 log_err("failed to process device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900590 return EFI_LOAD_ERROR;
591 }
592
Mark Kettenis1431ab82024-02-16 00:25:34 +0100593 /* Create memory reservations as indicated by the device tree */
594 efi_carve_out_dt_rsv(fdt);
595
Heinrich Schuchardtb03b2a42024-09-17 10:49:29 +0200596 efi_try_purge_rng_seed(fdt);
AKASHI Takahiro64228202024-01-17 13:39:41 +0900597
598 if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
599 ret = efi_tcg2_measure_dtb(fdt);
600 if (ret == EFI_SECURITY_VIOLATION) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200601 log_err("failed to measure DTB\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900602 return ret;
603 }
604 }
605
606 /* Install device tree as UEFI table */
607 ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
608 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200609 log_err("failed to install device tree\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900610 return ret;
611 }
612
613 return EFI_SUCCESS;
614}
615
616/**
617 * do_bootefi_exec() - execute EFI binary
618 *
619 * The image indicated by @handle is started. When it returns the allocated
620 * memory for the @load_options is freed.
621 *
622 * @handle: handle of loaded image
623 * @load_options: load options
624 * Return: status code
625 *
626 * Load the EFI binary into a newly assigned memory unwinding the relocation
627 * information, install the loaded image protocol, and call the binary.
628 */
629efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
630{
631 efi_status_t ret;
632 efi_uintn_t exit_data_size = 0;
633 u16 *exit_data = NULL;
634 struct efi_event *evt;
635
636 /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
637 switch_to_non_secure_mode();
638
639 /*
640 * The UEFI standard requires that the watchdog timer is set to five
641 * minutes when invoking an EFI boot option.
642 *
643 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
644 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
645 */
646 ret = efi_set_watchdog(300);
647 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt76a692a2024-10-17 20:13:05 +0200648 log_err("failed to set watchdog timer\n");
AKASHI Takahiro64228202024-01-17 13:39:41 +0900649 goto out;
650 }
651
652 /* Call our payload! */
653 ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
654 if (ret != EFI_SUCCESS) {
655 log_err("## Application failed, r = %lu\n",
656 ret & ~EFI_ERROR_MASK);
657 if (exit_data) {
658 log_err("## %ls\n", exit_data);
659 efi_free_pool(exit_data);
660 }
661 }
662
AKASHI Takahiro64228202024-01-17 13:39:41 +0900663out:
664 free(load_options);
665
AKASHI Takahiro64228202024-01-17 13:39:41 +0900666 /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
667 list_for_each_entry(evt, &efi_events, link) {
668 if (evt->group &&
669 !guidcmp(evt->group,
670 &efi_guid_event_group_return_to_efibootmgr)) {
671 efi_signal_event(evt);
672 EFI_CALL(systab.boottime->close_event(evt));
673 break;
674 }
675 }
676
677 /* Control is returned to U-Boot, disable EFI watchdog */
678 efi_set_watchdog(0);
679
680 return ret;
681}