blob: 2acae7856f988465ec4e0e2b770a67269b2c7282 [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>
Simon Glass37972f42025-05-24 11:28:21 -060010#include <efi_device_path.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020011#include <env.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090012#include <image.h>
13#include <log.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020014#include <malloc.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090015#include <mapmem.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020016#include <dm.h>
17#include <fs.h>
Simon Glass3b1e60b2024-11-07 14:31:43 -070018#include <efi.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090019#include <efi_api.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020020#include <efi_load_initrd.h>
21#include <efi_loader.h>
22#include <efi_variable.h>
Simon Glass3b1e60b2024-11-07 14:31:43 -070023#include <host_arch.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090024#include <linux/libfdt.h>
25#include <linux/list.h>
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +020026
Simon Glass1824bf62024-11-07 14:31:44 -070027#undef BOOTEFI_NAME
28
Simon Glass3b1e60b2024-11-07 14:31:43 -070029#if HOST_ARCH == HOST_ARCH_X86_64
Simon Glass52b53af2024-11-07 14:31:46 -070030#define HOST_BOOTEFI_NAME "BOOTX64.EFI"
31#define HOST_PXE_ARCH 0x6
Simon Glass3b1e60b2024-11-07 14:31:43 -070032#elif HOST_ARCH == HOST_ARCH_X86
Simon Glass52b53af2024-11-07 14:31:46 -070033#define HOST_BOOTEFI_NAME "BOOTIA32.EFI"
34#define HOST_PXE_ARCH 0x7
Simon Glass3b1e60b2024-11-07 14:31:43 -070035#elif HOST_ARCH == HOST_ARCH_AARCH64
Simon Glass52b53af2024-11-07 14:31:46 -070036#define HOST_BOOTEFI_NAME "BOOTAA64.EFI"
37#define HOST_PXE_ARCH 0xb
Simon Glass3b1e60b2024-11-07 14:31:43 -070038#elif HOST_ARCH == HOST_ARCH_ARM
Simon Glass52b53af2024-11-07 14:31:46 -070039#define HOST_BOOTEFI_NAME "BOOTARM.EFI"
40#define HOST_PXE_ARCH 0xa
Simon Glass3b1e60b2024-11-07 14:31:43 -070041#elif HOST_ARCH == HOST_ARCH_RISCV32
Simon Glass52b53af2024-11-07 14:31:46 -070042#define HOST_BOOTEFI_NAME "BOOTRISCV32.EFI"
43#define HOST_PXE_ARCH 0x19
Simon Glass3b1e60b2024-11-07 14:31:43 -070044#elif HOST_ARCH == HOST_ARCH_RISCV64
Simon Glass52b53af2024-11-07 14:31:46 -070045#define HOST_BOOTEFI_NAME "BOOTRISCV64.EFI"
46#define HOST_PXE_ARCH 0x1b
Simon Glass3b1e60b2024-11-07 14:31:43 -070047#else
Simon Glass52b53af2024-11-07 14:31:46 -070048#error Unsupported Host architecture
Simon Glass3b1e60b2024-11-07 14:31:43 -070049#endif
50
Simon Glass52b53af2024-11-07 14:31:46 -070051#if defined(CONFIG_SANDBOX)
52#define BOOTEFI_NAME "BOOTSBOX.EFI"
53#elif defined(CONFIG_ARM64)
Simon Glass3b1e60b2024-11-07 14:31:43 -070054#define BOOTEFI_NAME "BOOTAA64.EFI"
55#elif defined(CONFIG_ARM)
56#define BOOTEFI_NAME "BOOTARM.EFI"
57#elif defined(CONFIG_X86_64)
58#define BOOTEFI_NAME "BOOTX64.EFI"
59#elif defined(CONFIG_X86)
60#define BOOTEFI_NAME "BOOTIA32.EFI"
61#elif defined(CONFIG_ARCH_RV32I)
62#define BOOTEFI_NAME "BOOTRISCV32.EFI"
63#elif defined(CONFIG_ARCH_RV64I)
64#define BOOTEFI_NAME "BOOTRISCV64.EFI"
65#else
66#error Unsupported UEFI architecture
67#endif
68
Heinrich Schuchardt6c405cb2021-10-15 02:33:33 +020069#if defined(CONFIG_CMD_EFIDEBUG) || defined(CONFIG_EFI_LOAD_FILE2_INITRD)
70/* GUID used by Linux to identify the LoadFile2 protocol with the initrd */
71const efi_guid_t efi_lf2_initrd_guid = EFI_INITRD_MEDIA_GUID;
72#endif
73
Simon Glass3b1e60b2024-11-07 14:31:43 -070074const char *efi_get_basename(void)
75{
Simon Glass52b53af2024-11-07 14:31:46 -070076 return efi_use_host_arch() ? HOST_BOOTEFI_NAME : BOOTEFI_NAME;
Simon Glass3b1e60b2024-11-07 14:31:43 -070077}
78
Simon Glass1824bf62024-11-07 14:31:44 -070079int efi_get_pxe_arch(void)
80{
Simon Glass52b53af2024-11-07 14:31:46 -070081 if (efi_use_host_arch())
82 return HOST_PXE_ARCH;
83
Simon Glass1824bf62024-11-07 14:31:44 -070084 /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */
85 if (IS_ENABLED(CONFIG_ARM64))
86 return 0xb;
87 else if (IS_ENABLED(CONFIG_ARM))
88 return 0xa;
89 else if (IS_ENABLED(CONFIG_X86_64))
90 return 0x6;
91 else if (IS_ENABLED(CONFIG_X86))
92 return 0x7;
93 else if (IS_ENABLED(CONFIG_ARCH_RV32I))
94 return 0x19;
95 else if (IS_ENABLED(CONFIG_ARCH_RV64I))
96 return 0x1b;
Simon Glass1824bf62024-11-07 14:31:44 -070097
98 return -EINVAL;
99}
100
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200101/**
102 * efi_create_current_boot_var() - Return Boot#### name were #### is replaced by
103 * the value of BootCurrent
104 *
105 * @var_name: variable name
106 * @var_name_size: size of var_name
107 *
108 * Return: Status code
109 */
110static efi_status_t efi_create_current_boot_var(u16 var_name[],
111 size_t var_name_size)
112{
113 efi_uintn_t boot_current_size;
114 efi_status_t ret;
115 u16 boot_current;
116 u16 *pos;
117
118 boot_current_size = sizeof(boot_current);
Simon Glass90975372022-01-23 12:55:12 -0700119 ret = efi_get_variable_int(u"BootCurrent",
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200120 &efi_global_variable_guid, NULL,
121 &boot_current_size, &boot_current, NULL);
122 if (ret != EFI_SUCCESS)
123 goto out;
124
125 pos = efi_create_indexed_name(var_name, var_name_size, "Boot",
126 boot_current);
127 if (!pos) {
128 ret = EFI_OUT_OF_RESOURCES;
129 goto out;
130 }
131
132out:
133 return ret;
134}
135
136/**
137 * efi_get_dp_from_boot() - Retrieve and return a device path from an EFI
138 * Boot### variable.
139 * A boot option may contain an array of device paths.
140 * We use a VenMedia() with a specific GUID to identify
141 * the usage of the array members. This function is
142 * used to extract a specific device path
143 *
144 * @guid: vendor GUID of the VenMedia() device path node identifying the
145 * device path
146 *
147 * Return: device path or NULL. Caller must free the returned value
148 */
Heinrich Schuchardtefd90d72024-04-26 16:13:08 +0200149struct efi_device_path *efi_get_dp_from_boot(const efi_guid_t *guid)
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200150{
Ilias Apalodimasb92f7ba2024-08-12 23:57:59 +0300151 struct efi_device_path *file_path = NULL;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200152 struct efi_load_option lo;
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +0200153 void *var_value;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200154 efi_uintn_t size;
155 efi_status_t ret;
156 u16 var_name[16];
157
158 ret = efi_create_current_boot_var(var_name, sizeof(var_name));
159 if (ret != EFI_SUCCESS)
160 return NULL;
161
162 var_value = efi_get_var(var_name, &efi_global_variable_guid, &size);
163 if (!var_value)
164 return NULL;
165
166 ret = efi_deserialize_load_option(&lo, var_value, &size);
167 if (ret != EFI_SUCCESS)
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +0200168 goto err;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200169
Ilias Apalodimasb92f7ba2024-08-12 23:57:59 +0300170 file_path = efi_dp_from_lo(&lo, guid);
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200171
Heinrich Schuchardt35dd3222021-10-15 02:59:15 +0200172err:
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200173 free(var_value);
Ilias Apalodimasb92f7ba2024-08-12 23:57:59 +0300174 return file_path;
Ilias Apalodimasaa0f7552021-03-17 21:54:59 +0200175}
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300176
Heinrich Schuchardtf7529f72024-04-26 16:13:11 +0200177/**
178 * efi_load_option_dp_join() - join device-paths for load option
179 *
180 * @dp: in: binary device-path, out: joined device-path
181 * @dp_size: size of joined device-path
182 * @initrd_dp: initrd device-path or NULL
183 * @fdt_dp: device-tree device-path or NULL
184 * Return: status_code
185 */
186efi_status_t efi_load_option_dp_join(struct efi_device_path **dp,
187 size_t *dp_size,
188 struct efi_device_path *initrd_dp,
189 struct efi_device_path *fdt_dp)
190{
191 if (!dp)
192 return EFI_INVALID_PARAMETER;
193
194 *dp_size = efi_dp_size(*dp);
195
196 if (initrd_dp) {
197 struct efi_device_path *tmp_dp = *dp;
198
199 *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size);
200 efi_free_pool(tmp_dp);
201 if (!*dp)
202 return EFI_OUT_OF_RESOURCES;
203 *dp_size += efi_dp_size(initrd_dp) + sizeof(END);
204 }
205
206 if (fdt_dp) {
207 struct efi_device_path *tmp_dp = *dp;
208
209 *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size);
210 efi_free_pool(tmp_dp);
Heinrich Schuchardt9b4e1f52024-07-24 15:26:04 +0200211 if (!*dp)
Heinrich Schuchardtf7529f72024-04-26 16:13:11 +0200212 return EFI_OUT_OF_RESOURCES;
213 *dp_size += efi_dp_size(fdt_dp) + sizeof(END);
214 }
215
216 *dp_size += sizeof(END);
217
218 return EFI_SUCCESS;
219}
220
Ilias Apalodimas34db9b12022-05-06 15:36:00 +0300221const struct guid_to_hash_map {
222 efi_guid_t guid;
223 const char algo[32];
224 u32 bits;
225} guid_to_hash[] = {
226 {
227 EFI_CERT_X509_SHA256_GUID,
228 "sha256",
229 SHA256_SUM_LEN * 8,
230 },
231 {
232 EFI_CERT_SHA256_GUID,
233 "sha256",
234 SHA256_SUM_LEN * 8,
235 },
236 {
237 EFI_CERT_X509_SHA384_GUID,
238 "sha384",
239 SHA384_SUM_LEN * 8,
240 },
241 {
242 EFI_CERT_X509_SHA512_GUID,
243 "sha512",
244 SHA512_SUM_LEN * 8,
245 },
246};
247
248#define MAX_GUID_TO_HASH_COUNT ARRAY_SIZE(guid_to_hash)
249
250/** guid_to_sha_str - return the sha string e.g "sha256" for a given guid
251 * used on EFI security databases
252 *
253 * @guid: guid to check
254 *
255 * Return: len or 0 if no match is found
256 */
257const char *guid_to_sha_str(const efi_guid_t *guid)
258{
259 size_t i;
260
261 for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
262 if (!guidcmp(guid, &guid_to_hash[i].guid))
263 return guid_to_hash[i].algo;
264 }
265
266 return NULL;
267}
268
269/** algo_to_len - return the sha size in bytes for a given string
270 *
271 * @algo: string indicating hashing algorithm to check
272 *
273 * Return: length of hash in bytes or 0 if no match is found
274 */
275int algo_to_len(const char *algo)
276{
277 size_t i;
278
279 for (i = 0; i < MAX_GUID_TO_HASH_COUNT; i++) {
280 if (!strcmp(algo, guid_to_hash[i].algo))
281 return guid_to_hash[i].bits / 8;
282 }
283
284 return 0;
285}
Masahisa Kojimac9611082022-07-22 11:39:10 +0900286
287/** efi_link_dev - link the efi_handle_t and udevice
288 *
289 * @handle: efi handle to associate with udevice
290 * @dev: udevice to associate with efi handle
291 *
292 * Return: 0 on success, negative on failure
293 */
294int efi_link_dev(efi_handle_t handle, struct udevice *dev)
295{
296 handle->dev = dev;
297 return dev_tag_set_ptr(dev, DM_TAG_EFI, handle);
298}
Heinrich Schuchardt34f34622022-10-03 09:47:51 +0200299
300/**
301 * efi_unlink_dev() - unlink udevice and handle
302 *
303 * @handle: EFI handle to unlink
304 *
305 * Return: 0 on success, negative on failure
306 */
307int efi_unlink_dev(efi_handle_t handle)
308{
309 int ret;
310
311 ret = dev_tag_del(handle->dev, DM_TAG_EFI);
312 if (ret)
313 return ret;
314 handle->dev = NULL;
315
316 return 0;
317}
Masahisa Kojima2f407f02022-12-02 13:59:35 +0900318
319static int u16_tohex(u16 c)
320{
321 if (c >= '0' && c <= '9')
322 return c - '0';
323 if (c >= 'A' && c <= 'F')
324 return c - 'A' + 10;
325
326 /* not hexadecimal */
327 return -1;
328}
329
330bool efi_varname_is_load_option(u16 *var_name16, int *index)
331{
332 int id, i, digit;
333
334 if (memcmp(var_name16, u"Boot", 8))
335 return false;
336
337 for (id = 0, i = 0; i < 4; i++) {
338 digit = u16_tohex(var_name16[4 + i]);
339 if (digit < 0)
340 break;
341 id = (id << 4) + digit;
342 }
343 if (i == 4 && !var_name16[8]) {
344 if (index)
345 *index = id;
346 return true;
347 }
348
349 return false;
350}
Masahisa Kojima7ec3c6f2022-12-19 11:33:12 +0900351
352/**
353 * efi_next_variable_name() - get next variable name
354 *
355 * This function is a wrapper of efi_get_next_variable_name_int().
356 * If efi_get_next_variable_name_int() returns EFI_BUFFER_TOO_SMALL,
357 * @size and @buf are updated by new buffer size and realloced buffer.
358 *
359 * @size: pointer to the buffer size
360 * @buf: pointer to the buffer
361 * @guid: pointer to the guid
362 * Return: status code
363 */
364efi_status_t efi_next_variable_name(efi_uintn_t *size, u16 **buf, efi_guid_t *guid)
365{
366 u16 *p;
367 efi_status_t ret;
368 efi_uintn_t buf_size = *size;
369
370 ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
371 if (ret == EFI_NOT_FOUND)
372 return ret;
373 if (ret == EFI_BUFFER_TOO_SMALL) {
374 p = realloc(*buf, buf_size);
375 if (!p)
376 return EFI_OUT_OF_RESOURCES;
377
378 *buf = p;
379 *size = buf_size;
380 ret = efi_get_next_variable_name_int(&buf_size, *buf, guid);
381 }
382
383 return ret;
384}
Raymond Mao70a76c52023-06-19 14:22:58 -0700385
386/**
387 * efi_search_bootorder() - search the boot option index in BootOrder
388 *
389 * @bootorder: pointer to the BootOrder variable
390 * @num: number of BootOrder entry
391 * @target: target boot option index to search
392 * @index: pointer to store the index of BootOrder variable
393 * Return: true if exists, false otherwise
394 */
395bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index)
396{
397 u32 i;
398
399 for (i = 0; i < num; i++) {
400 if (target == bootorder[i]) {
401 if (index)
402 *index = i;
403
404 return true;
405 }
406 }
407
408 return false;
409}
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900410
411/**
412 * efi_env_set_load_options() - set load options from environment variable
413 *
414 * @handle: the image handle
415 * @env_var: name of the environment variable
416 * @load_options: pointer to load options (output)
417 * Return: status code
418 */
419efi_status_t efi_env_set_load_options(efi_handle_t handle,
420 const char *env_var,
421 u16 **load_options)
422{
423 const char *env = env_get(env_var);
424 size_t size;
425 u16 *pos;
426 efi_status_t ret;
427
428 *load_options = NULL;
429 if (!env)
430 return EFI_SUCCESS;
431 size = sizeof(u16) * (utf8_utf16_strlen(env) + 1);
432 pos = calloc(size, 1);
433 if (!pos)
434 return EFI_OUT_OF_RESOURCES;
435 *load_options = pos;
436 utf8_utf16_strcpy(&pos, env);
437 ret = efi_set_load_options(handle, size, *load_options);
438 if (ret != EFI_SUCCESS) {
439 free(*load_options);
440 *load_options = NULL;
441 }
442 return ret;
443}
444
445/**
446 * copy_fdt() - Copy the device tree to a new location available to EFI
447 *
448 * The FDT is copied to a suitable location within the EFI memory map.
449 * Additional 12 KiB are added to the space in case the device tree needs to be
450 * expanded later with fdt_open_into().
451 *
452 * @fdtp: On entry a pointer to the flattened device tree.
453 * On exit a pointer to the copy of the flattened device tree.
454 * FDT start
455 * Return: status code
456 */
457static efi_status_t copy_fdt(void **fdtp)
458{
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900459 efi_status_t ret = 0;
460 void *fdt, *new_fdt;
Sughosh Ganu007604e2025-03-17 14:03:56 +0530461 static u64 new_fdt_addr;
462 static efi_uintn_t fdt_pages;
463 ulong fdt_size;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900464
465 /*
Sughosh Ganu007604e2025-03-17 14:03:56 +0530466 * Remove the configuration table that might already be
467 * installed, ignoring EFI_NOT_FOUND if no device-tree
468 * is installed
469 */
470 efi_install_configuration_table(&efi_guid_fdt, NULL);
471
472 if (new_fdt_addr) {
473 log_debug("%s: Found allocated memory at %#llx, with %#zx pages\n",
474 __func__, new_fdt_addr, fdt_pages);
475
476 ret = efi_free_pages(new_fdt_addr, fdt_pages);
477 if (ret != EFI_SUCCESS)
478 log_err("Unable to free up existing FDT memory region\n");
479
480 new_fdt_addr = 0;
481 fdt_pages = 0;
482 }
483
484 /*
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900485 * Give us at least 12 KiB of breathing room in case the device tree
486 * needs to be expanded later.
487 */
488 fdt = *fdtp;
Pawel Kochanowski9a78d352025-03-18 10:22:18 +0100489 fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + CONFIG_SYS_FDT_PAD);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900490 fdt_size = fdt_pages << EFI_PAGE_SHIFT;
491
492 ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES,
493 EFI_ACPI_RECLAIM_MEMORY, fdt_pages,
494 &new_fdt_addr);
495 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200496 log_err("Failed to reserve space for FDT\n");
Sughosh Ganu007604e2025-03-17 14:03:56 +0530497 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900498 }
Sughosh Ganu007604e2025-03-17 14:03:56 +0530499 log_debug("%s: Allocated memory at %#llx, with %#zx pages\n",
500 __func__, new_fdt_addr, fdt_pages);
501
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900502 new_fdt = (void *)(uintptr_t)new_fdt_addr;
503 memcpy(new_fdt, fdt, fdt_totalsize(fdt));
504 fdt_set_totalsize(new_fdt, fdt_size);
505
Sughosh Ganu007604e2025-03-17 14:03:56 +0530506 *fdtp = new_fdt;
507
508 return EFI_SUCCESS;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900509}
510
511/**
Heinrich Schuchardt0a4a2f32024-01-26 08:54:30 +0100512 * efi_get_configuration_table() - get configuration table
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900513 *
514 * @guid: GUID of the configuration table
515 * Return: pointer to configuration table or NULL
516 */
Heinrich Schuchardt0a4a2f32024-01-26 08:54:30 +0100517void *efi_get_configuration_table(const efi_guid_t *guid)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900518{
519 size_t i;
520
521 for (i = 0; i < systab.nr_tables; i++) {
522 if (!guidcmp(guid, &systab.tables[i].guid))
523 return systab.tables[i].table;
524 }
525 return NULL;
526}
527
528/**
529 * efi_install_fdt() - install device tree
530 *
531 * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory
532 * address will be installed as configuration table, otherwise the device
533 * tree located at the address indicated by environment variable fdt_addr or as
534 * fallback fdtcontroladdr will be used.
535 *
536 * On architectures using ACPI tables device trees shall not be installed as
537 * configuration table.
538 *
539 * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use
540 * the hardware device tree as indicated by environment variable
541 * fdt_addr or as fallback the internal device tree as indicated by
542 * the environment variable fdtcontroladdr
543 * Return: status code
544 */
545efi_status_t efi_install_fdt(void *fdt)
546{
547 struct bootm_headers img = { 0 };
548 efi_status_t ret;
549
550 /*
551 * The EBBR spec requires that we have either an FDT or an ACPI table
552 * but not both.
553 */
554 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) && fdt)
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200555 log_warning("Can't have ACPI table and device tree - ignoring DT.\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900556
557 if (fdt == EFI_FDT_USE_INTERNAL) {
558 const char *fdt_opt;
559 uintptr_t fdt_addr;
560
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900561 /* Check if there is a hardware device tree */
562 fdt_opt = env_get("fdt_addr");
563 /* Use our own device tree as fallback */
564 if (!fdt_opt) {
565 fdt_opt = env_get("fdtcontroladdr");
566 if (!fdt_opt) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200567 log_err("need device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900568 return EFI_NOT_FOUND;
569 }
570 }
571 fdt_addr = hextoul(fdt_opt, NULL);
572 if (!fdt_addr) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200573 log_err("invalid $fdt_addr or $fdtcontroladdr\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900574 return EFI_LOAD_ERROR;
575 }
576 fdt = map_sysmem(fdt_addr, 0);
577 }
578
579 /* Install device tree */
580 if (fdt_check_header(fdt)) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200581 log_err("invalid device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900582 return EFI_LOAD_ERROR;
583 }
584
Mark Kettenis98c598c2024-02-16 00:25:34 +0100585 if (CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE)) {
586 /* Create memory reservations as indicated by the device tree */
587 efi_carve_out_dt_rsv(fdt);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900588 return EFI_SUCCESS;
Mark Kettenis98c598c2024-02-16 00:25:34 +0100589 }
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900590
591 /* Prepare device tree for payload */
592 ret = copy_fdt(&fdt);
593 if (ret) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200594 log_err("out of memory\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900595 return EFI_OUT_OF_RESOURCES;
596 }
597
Sughosh Ganu291bf9c2024-08-26 17:29:18 +0530598 if (image_setup_libfdt(&img, fdt, false)) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200599 log_err("failed to process device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900600 return EFI_LOAD_ERROR;
601 }
602
Mark Kettenis98c598c2024-02-16 00:25:34 +0100603 /* Create memory reservations as indicated by the device tree */
604 efi_carve_out_dt_rsv(fdt);
605
Heinrich Schuchardt069079c2024-09-17 10:49:29 +0200606 efi_try_purge_rng_seed(fdt);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900607
608 if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
609 ret = efi_tcg2_measure_dtb(fdt);
610 if (ret == EFI_SECURITY_VIOLATION) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200611 log_err("failed to measure DTB\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900612 return ret;
613 }
614 }
615
616 /* Install device tree as UEFI table */
617 ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
618 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200619 log_err("failed to install device tree\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900620 return ret;
621 }
622
623 return EFI_SUCCESS;
624}
625
626/**
Adriano Cordova395f7f22025-04-29 09:27:55 -0400627 * efi_install_initrd() - install initrd
628 *
629 * Install the initrd located at @initrd using the EFI_LOAD_FILE2
630 * protocol.
631 *
632 * @initrd: address of initrd or NULL if none is provided
633 * @initrd_sz: size of initrd
634 * Return: status code
635 */
636efi_status_t efi_install_initrd(void *initrd, size_t initd_sz)
637{
638 efi_status_t ret;
639 struct efi_device_path *dp_initrd;
640
641 if (!initrd)
642 return EFI_SUCCESS;
643
644 dp_initrd = efi_dp_from_mem(EFI_LOADER_DATA, (uintptr_t)initrd, initd_sz);
645 if (!dp_initrd)
646 return EFI_OUT_OF_RESOURCES;
647
648 ret = efi_initrd_register(dp_initrd);
649 if (ret != EFI_SUCCESS)
650 efi_free_pool(dp_initrd);
651
652 return ret;
653}
654
655/**
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900656 * do_bootefi_exec() - execute EFI binary
657 *
658 * The image indicated by @handle is started. When it returns the allocated
659 * memory for the @load_options is freed.
660 *
661 * @handle: handle of loaded image
662 * @load_options: load options
663 * Return: status code
664 *
665 * Load the EFI binary into a newly assigned memory unwinding the relocation
666 * information, install the loaded image protocol, and call the binary.
667 */
668efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options)
669{
670 efi_status_t ret;
671 efi_uintn_t exit_data_size = 0;
672 u16 *exit_data = NULL;
673 struct efi_event *evt;
674
675 /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */
676 switch_to_non_secure_mode();
677
678 /*
679 * The UEFI standard requires that the watchdog timer is set to five
680 * minutes when invoking an EFI boot option.
681 *
682 * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A
683 * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer
684 */
685 ret = efi_set_watchdog(300);
686 if (ret != EFI_SUCCESS) {
Heinrich Schuchardt353db822024-10-17 20:13:05 +0200687 log_err("failed to set watchdog timer\n");
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900688 goto out;
689 }
690
691 /* Call our payload! */
692 ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data));
693 if (ret != EFI_SUCCESS) {
694 log_err("## Application failed, r = %lu\n",
695 ret & ~EFI_ERROR_MASK);
696 if (exit_data) {
697 log_err("## %ls\n", exit_data);
698 efi_free_pool(exit_data);
699 }
700 }
701
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900702out:
703 free(load_options);
704
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900705 /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */
706 list_for_each_entry(evt, &efi_events, link) {
707 if (evt->group &&
708 !guidcmp(evt->group,
709 &efi_guid_event_group_return_to_efibootmgr)) {
710 efi_signal_event(evt);
711 EFI_CALL(systab.boottime->close_event(evt));
712 break;
713 }
714 }
715
716 /* Control is returned to U-Boot, disable EFI watchdog */
717 efi_set_watchdog(0);
718
719 return ret;
720}
Sughosh Ganu8231d032025-03-17 14:04:02 +0530721
722/**
723 * pmem_node_efi_memmap_setup() - Add pmem node and tweak EFI memmap
724 * @fdt: The devicetree to which pmem node is added
725 * @addr: start address of the pmem node
726 * @size: size of the memory of the pmem node
727 *
728 * The function adds the pmem node to the device-tree along with removing
729 * the corresponding region from the EFI memory map. Used primarily to
730 * pass the information of a RAM based ISO image to the OS.
731 *
732 * Return: 0 on success, -ve value on error
733 */
734static int pmem_node_efi_memmap_setup(void *fdt, u64 addr, u64 size)
735{
736 int ret;
737 u64 pages;
738 efi_status_t status;
739
740 ret = fdt_fixup_pmem_region(fdt, addr, size);
741 if (ret) {
742 log_err("Failed to setup pmem node for addr %#llx, size %#llx, err %d\n",
743 addr, size, ret);
744 return ret;
745 }
746
747 /* Remove the pmem region from the EFI memory map */
748 pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK));
749 status = efi_update_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY,
750 false, true);
751 if (status != EFI_SUCCESS)
752 return -1;
753
754 return 0;
755}
756
757int fdt_efi_pmem_setup(void *fdt)
758{
759 return blkmap_get_preserved_pmem_slices(pmem_node_efi_memmap_setup,
760 fdt);
761}