blob: 2cf972343a4539ce9850a41853836753568dba5a [file] [log] [blame]
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +09001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * For the code moved from cmd/bootefi.c
4 * Copyright (c) 2016 Alexander Graf
5 */
6
7#define LOG_CATEGORY LOGC_EFI
8
Simon Glassfce57772025-01-23 15:07:23 -07009#include <bootflow.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090010#include <charset.h>
Simon Glassfce57772025-01-23 15:07:23 -070011#include <dm.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090012#include <efi.h>
13#include <efi_loader.h>
14#include <env.h>
15#include <image.h>
16#include <log.h>
17#include <malloc.h>
Simon Glassfce57772025-01-23 15:07:23 -070018#include <mapmem.h>
Adriano Cordova54674692025-03-03 11:13:15 -030019#include <net.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090020
21static struct efi_device_path *bootefi_image_path;
22static struct efi_device_path *bootefi_device_path;
23static void *image_addr;
24static size_t image_size;
25
26/**
27 * efi_get_image_parameters() - return image parameters
28 *
29 * @img_addr: address of loaded image in memory
30 * @img_size: size of loaded image
31 */
32void efi_get_image_parameters(void **img_addr, size_t *img_size)
33{
34 *img_addr = image_addr;
35 *img_size = image_size;
36}
37
38/**
39 * efi_clear_bootdev() - clear boot device
40 */
41void efi_clear_bootdev(void)
42{
43 efi_free_pool(bootefi_device_path);
44 efi_free_pool(bootefi_image_path);
45 bootefi_device_path = NULL;
46 bootefi_image_path = NULL;
47 image_addr = NULL;
48 image_size = 0;
49}
50
51/**
Simon Glassa53fbb72025-01-09 08:02:38 -070052 * calculate_paths() - Calculate the device and image patch from strings
53 *
54 * @dev: device, e.g. "MMC"
55 * @devnr: number of the device, e.g. "1:2"
56 * @path: path to file loaded
57 * @device_pathp: returns EFI device path
58 * @image_pathp: returns EFI image path
59 * Return: EFI_SUCCESS on success, else error code
60 */
61static efi_status_t calculate_paths(const char *dev, const char *devnr,
62 const char *path,
63 struct efi_device_path **device_pathp,
64 struct efi_device_path **image_pathp)
65{
66 struct efi_device_path *image, *device;
67 efi_status_t ret;
68
69#if IS_ENABLED(CONFIG_NETDEVICES)
70 if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) {
Adriano Cordova54674692025-03-03 11:13:15 -030071 ret = efi_net_new_dp(dev, devnr, eth_get_dev());
Simon Glassa53fbb72025-01-09 08:02:38 -070072 if (ret != EFI_SUCCESS)
73 return ret;
74 }
75#endif
76
77 ret = efi_dp_from_name(dev, devnr, path, &device, &image);
78 if (ret != EFI_SUCCESS)
79 return ret;
80
81 *device_pathp = device;
82 if (image) {
83 /* FIXME: image should not contain device */
84 struct efi_device_path *image_tmp = image;
85
86 efi_dp_split_file_path(image, &device, &image);
87 efi_free_pool(image_tmp);
88 }
89 *image_pathp = image;
90 log_debug("- boot device %pD\n", device);
91 if (image)
92 log_debug("- image %pD\n", image);
93
94 return EFI_SUCCESS;
95}
96
97/**
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090098 * efi_set_bootdev() - set boot device
99 *
100 * This function is called when a file is loaded, e.g. via the 'load' command.
101 * We use the path to this file to inform the UEFI binary about the boot device.
102 *
Simon Glassa53fbb72025-01-09 08:02:38 -0700103 * For a valid image, it sets:
104 * - image_addr to the provided buffer
105 * - image_size to the provided buffer_size
106 * - bootefi_device_path to the EFI device-path
107 * - bootefi_image_path to the EFI image-path
108 *
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900109 * @dev: device, e.g. "MMC"
110 * @devnr: number of the device, e.g. "1:2"
111 * @path: path to file loaded
112 * @buffer: buffer with file loaded
113 * @buffer_size: size of file loaded
114 */
115void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
116 void *buffer, size_t buffer_size)
117{
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900118 efi_status_t ret;
119
120 log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
121 devnr, path, buffer, buffer_size);
122
123 /* Forget overwritten image */
124 if (buffer + buffer_size >= image_addr &&
125 image_addr + image_size >= buffer)
126 efi_clear_bootdev();
127
128 /* Remember only PE-COFF and FIT images */
129 if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
130 if (IS_ENABLED(CONFIG_FIT) &&
131 !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
132 /*
133 * FIT images of type EFI_OS are started via command
134 * bootm. We should not use their boot device with the
135 * bootefi command.
136 */
137 buffer = 0;
138 buffer_size = 0;
139 } else {
140 log_debug("- not remembering image\n");
141 return;
142 }
143 }
144
145 /* efi_set_bootdev() is typically called repeatedly, recover memory */
146 efi_clear_bootdev();
147
148 image_addr = buffer;
149 image_size = buffer_size;
150
Simon Glassa53fbb72025-01-09 08:02:38 -0700151 ret = calculate_paths(dev, devnr, path, &bootefi_device_path,
152 &bootefi_image_path);
153 if (ret) {
154 log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
155 efi_clear_bootdev();
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900156 }
157}
158
159/**
160 * efi_run_image() - run loaded UEFI image
161 *
162 * @source_buffer: memory address of the UEFI image
163 * @source_size: size of the UEFI image
Simon Glassa39a78b2025-01-23 15:07:20 -0700164 * @dp_dev: EFI device-path
165 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900166 * Return: status code
167 */
Simon Glassa39a78b2025-01-23 15:07:20 -0700168static efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size,
169 struct efi_device_path *dp_dev,
170 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900171{
Simon Glassc14b38f2025-01-23 15:07:22 -0700172 efi_handle_t handle;
173 struct efi_device_path *msg_path, *file_path;
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100174 efi_status_t ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900175 u16 *load_options;
176
Simon Glassc14b38f2025-01-23 15:07:22 -0700177 file_path = efi_dp_concat(dp_dev, dp_img, 0);
178 msg_path = dp_img;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900179
180 log_info("Booting %pD\n", msg_path);
181
182 ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
183 source_size, &handle));
184 if (ret != EFI_SUCCESS) {
185 log_err("Loading image failed\n");
186 goto out;
187 }
188
189 /* Transfer environment variable as load options */
190 ret = efi_env_set_load_options(handle, "bootargs", &load_options);
191 if (ret != EFI_SUCCESS)
192 goto out;
193
194 ret = do_bootefi_exec(handle, load_options);
195
196out:
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100197
198 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900199}
200
201/**
Simon Glass44d57f62025-01-23 15:07:21 -0700202 * efi_binary_run_dp() - run loaded UEFI image
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900203 *
204 * @image: memory address of the UEFI image
205 * @size: size of the UEFI image
206 * @fdt: device-tree
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300207 * @initrd: initrd
208 * @initrd_sz: initrd size
Simon Glass44d57f62025-01-23 15:07:21 -0700209 * @dp_dev: EFI device-path
210 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900211 *
212 * Execute an EFI binary image loaded at @image.
213 * @size may be zero if the binary is loaded with U-Boot load command.
214 *
215 * Return: status code
216 */
Simon Glassc14b38f2025-01-23 15:07:22 -0700217static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt,
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300218 void *initrd, size_t initd_sz,
Simon Glassc14b38f2025-01-23 15:07:22 -0700219 struct efi_device_path *dp_dev,
220 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900221{
222 efi_status_t ret;
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300223 struct efi_device_path *dp_initrd;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900224
225 /* Initialize EFI drivers */
226 ret = efi_init_obj_list();
227 if (ret != EFI_SUCCESS) {
228 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
229 ret & ~EFI_ERROR_MASK);
230 return -1;
231 }
232
233 ret = efi_install_fdt(fdt);
234 if (ret != EFI_SUCCESS)
235 return ret;
236
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300237 dp_initrd = efi_dp_from_mem(EFI_LOADER_DATA, (uintptr_t)initrd, initd_sz);
238 if (!dp_initrd)
239 return EFI_OUT_OF_RESOURCES;
240
241 ret = efi_initrd_register(dp_initrd);
242 if (ret != EFI_SUCCESS)
243 return ret;
244
Simon Glass44d57f62025-01-23 15:07:21 -0700245 return efi_run_image(image, size, dp_dev, dp_img);
246}
247
248/**
249 * efi_binary_run() - run loaded UEFI image
250 *
251 * @image: memory address of the UEFI image
252 * @size: size of the UEFI image
253 * @fdt: device-tree
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300254 * @initrd: initrd
255 * @initrd_sz: initrd size
Simon Glass44d57f62025-01-23 15:07:21 -0700256 *
257 * Execute an EFI binary image loaded at @image.
258 * @size may be zero if the binary is loaded with U-Boot load command.
259 *
260 * Return: status code
261 */
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300262efi_status_t efi_binary_run(void *image, size_t size, void *fdt, void *initrd, size_t initrd_sz)
Simon Glass44d57f62025-01-23 15:07:21 -0700263{
Simon Glassc14b38f2025-01-23 15:07:22 -0700264 efi_handle_t mem_handle = NULL;
265 struct efi_device_path *file_path = NULL;
266 efi_status_t ret;
267
268 if (!bootefi_device_path || !bootefi_image_path) {
269 log_debug("Not loaded from disk\n");
270 /*
271 * Special case for efi payload not loaded from disk,
272 * such as 'bootefi hello' or for example payload
273 * loaded directly into memory via JTAG, etc:
274 */
275 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
276 (uintptr_t)image, size);
277 /*
278 * Make sure that device for device_path exist
279 * in load_image(). Otherwise, shell and grub will fail.
280 */
281 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
282 &efi_guid_device_path,
283 file_path, NULL);
284 if (ret != EFI_SUCCESS)
285 goto out;
286 } else {
287 log_debug("Loaded from disk\n");
288 }
289
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300290 ret = efi_binary_run_dp(image, size, fdt, initrd, initrd_sz, bootefi_device_path,
Simon Glassc14b38f2025-01-23 15:07:22 -0700291 bootefi_image_path);
292out:
293 if (mem_handle) {
294 efi_status_t r;
295
296 r = efi_uninstall_multiple_protocol_interfaces(mem_handle,
297 &efi_guid_device_path, file_path, NULL);
298 if (r != EFI_SUCCESS)
299 log_err("Uninstalling protocol interfaces failed\n");
300 }
301 efi_free_pool(file_path);
302
303 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900304}
Simon Glassfce57772025-01-23 15:07:23 -0700305
306/**
307 * calc_dev_name() - Calculate the device name to give to EFI
308 *
309 * If not supported, this shows an error.
310 *
311 * Return name, or NULL if not supported
312 */
313static const char *calc_dev_name(struct bootflow *bflow)
314{
315 const struct udevice *media_dev;
316
317 media_dev = dev_get_parent(bflow->dev);
318
319 if (!bflow->blk) {
Simon Glassff055b02025-01-23 15:07:24 -0700320 if (device_get_uclass_id(media_dev) == UCLASS_ETH)
321 return "Net";
322
Simon Glassfce57772025-01-23 15:07:23 -0700323 log_err("Cannot boot EFI app on media '%s'\n",
324 dev_get_uclass_name(media_dev));
325
326 return NULL;
327 }
328
329 if (device_get_uclass_id(media_dev) == UCLASS_MASS_STORAGE)
330 return "usb";
331
332 return blk_get_uclass_name(device_get_uclass_id(media_dev));
333}
334
335efi_status_t efi_bootflow_run(struct bootflow *bflow)
336{
337 struct efi_device_path *device, *image;
338 const struct udevice *media_dev;
339 struct blk_desc *desc = NULL;
340 const char *dev_name;
341 char devnum_str[9];
342 efi_status_t ret;
343 void *fdt;
344
345 media_dev = dev_get_parent(bflow->dev);
346 if (bflow->blk) {
347 desc = dev_get_uclass_plat(bflow->blk);
348
349 snprintf(devnum_str, sizeof(devnum_str), "%x:%x",
350 desc ? desc->devnum : dev_seq(media_dev), bflow->part);
351 } else {
352 *devnum_str = '\0';
353 }
354
355 dev_name = calc_dev_name(bflow);
356 log_debug("dev_name '%s' devnum_str '%s' fname '%s' media_dev '%s'\n",
357 dev_name, devnum_str, bflow->fname, media_dev->name);
358 if (!dev_name)
359 return EFI_UNSUPPORTED;
360 ret = calculate_paths(dev_name, devnum_str, bflow->fname, &device,
361 &image);
362 if (ret)
Simon Glassff055b02025-01-23 15:07:24 -0700363 return EFI_UNSUPPORTED;
Simon Glassfce57772025-01-23 15:07:23 -0700364
365 if (bflow->flags & BOOTFLOWF_USE_BUILTIN_FDT) {
366 log_debug("Booting with built-in fdt\n");
367 fdt = EFI_FDT_USE_INTERNAL;
368 } else {
369 log_debug("Booting with external fdt\n");
370 fdt = map_sysmem(bflow->fdt_addr, 0);
371 }
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300372 ret = efi_binary_run_dp(bflow->buf, bflow->size, fdt, NULL, 0, device, image);
Simon Glassfce57772025-01-23 15:07:23 -0700373
374 return ret;
375}