blob: deafb2ce1c2d328395c097bfcb75aae8b1ff10bf [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
Simon Glass44d57f62025-01-23 15:07:21 -0700207 * @dp_dev: EFI device-path
208 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900209 *
210 * Execute an EFI binary image loaded at @image.
211 * @size may be zero if the binary is loaded with U-Boot load command.
212 *
213 * Return: status code
214 */
Simon Glassc14b38f2025-01-23 15:07:22 -0700215static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt,
216 struct efi_device_path *dp_dev,
217 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900218{
219 efi_status_t ret;
220
221 /* Initialize EFI drivers */
222 ret = efi_init_obj_list();
223 if (ret != EFI_SUCCESS) {
224 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
225 ret & ~EFI_ERROR_MASK);
226 return -1;
227 }
228
229 ret = efi_install_fdt(fdt);
230 if (ret != EFI_SUCCESS)
231 return ret;
232
Simon Glass44d57f62025-01-23 15:07:21 -0700233 return efi_run_image(image, size, dp_dev, dp_img);
234}
235
236/**
237 * efi_binary_run() - run loaded UEFI image
238 *
239 * @image: memory address of the UEFI image
240 * @size: size of the UEFI image
241 * @fdt: device-tree
242 *
243 * Execute an EFI binary image loaded at @image.
244 * @size may be zero if the binary is loaded with U-Boot load command.
245 *
246 * Return: status code
247 */
248efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
249{
Simon Glassc14b38f2025-01-23 15:07:22 -0700250 efi_handle_t mem_handle = NULL;
251 struct efi_device_path *file_path = NULL;
252 efi_status_t ret;
253
254 if (!bootefi_device_path || !bootefi_image_path) {
255 log_debug("Not loaded from disk\n");
256 /*
257 * Special case for efi payload not loaded from disk,
258 * such as 'bootefi hello' or for example payload
259 * loaded directly into memory via JTAG, etc:
260 */
261 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
262 (uintptr_t)image, size);
263 /*
264 * Make sure that device for device_path exist
265 * in load_image(). Otherwise, shell and grub will fail.
266 */
267 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
268 &efi_guid_device_path,
269 file_path, NULL);
270 if (ret != EFI_SUCCESS)
271 goto out;
272 } else {
273 log_debug("Loaded from disk\n");
274 }
275
276 ret = efi_binary_run_dp(image, size, fdt, bootefi_device_path,
277 bootefi_image_path);
278out:
279 if (mem_handle) {
280 efi_status_t r;
281
282 r = efi_uninstall_multiple_protocol_interfaces(mem_handle,
283 &efi_guid_device_path, file_path, NULL);
284 if (r != EFI_SUCCESS)
285 log_err("Uninstalling protocol interfaces failed\n");
286 }
287 efi_free_pool(file_path);
288
289 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900290}
Simon Glassfce57772025-01-23 15:07:23 -0700291
292/**
293 * calc_dev_name() - Calculate the device name to give to EFI
294 *
295 * If not supported, this shows an error.
296 *
297 * Return name, or NULL if not supported
298 */
299static const char *calc_dev_name(struct bootflow *bflow)
300{
301 const struct udevice *media_dev;
302
303 media_dev = dev_get_parent(bflow->dev);
304
305 if (!bflow->blk) {
Simon Glassff055b02025-01-23 15:07:24 -0700306 if (device_get_uclass_id(media_dev) == UCLASS_ETH)
307 return "Net";
308
Simon Glassfce57772025-01-23 15:07:23 -0700309 log_err("Cannot boot EFI app on media '%s'\n",
310 dev_get_uclass_name(media_dev));
311
312 return NULL;
313 }
314
315 if (device_get_uclass_id(media_dev) == UCLASS_MASS_STORAGE)
316 return "usb";
317
318 return blk_get_uclass_name(device_get_uclass_id(media_dev));
319}
320
321efi_status_t efi_bootflow_run(struct bootflow *bflow)
322{
323 struct efi_device_path *device, *image;
324 const struct udevice *media_dev;
325 struct blk_desc *desc = NULL;
326 const char *dev_name;
327 char devnum_str[9];
328 efi_status_t ret;
329 void *fdt;
330
331 media_dev = dev_get_parent(bflow->dev);
332 if (bflow->blk) {
333 desc = dev_get_uclass_plat(bflow->blk);
334
335 snprintf(devnum_str, sizeof(devnum_str), "%x:%x",
336 desc ? desc->devnum : dev_seq(media_dev), bflow->part);
337 } else {
338 *devnum_str = '\0';
339 }
340
341 dev_name = calc_dev_name(bflow);
342 log_debug("dev_name '%s' devnum_str '%s' fname '%s' media_dev '%s'\n",
343 dev_name, devnum_str, bflow->fname, media_dev->name);
344 if (!dev_name)
345 return EFI_UNSUPPORTED;
346 ret = calculate_paths(dev_name, devnum_str, bflow->fname, &device,
347 &image);
348 if (ret)
Simon Glassff055b02025-01-23 15:07:24 -0700349 return EFI_UNSUPPORTED;
Simon Glassfce57772025-01-23 15:07:23 -0700350
351 if (bflow->flags & BOOTFLOWF_USE_BUILTIN_FDT) {
352 log_debug("Booting with built-in fdt\n");
353 fdt = EFI_FDT_USE_INTERNAL;
354 } else {
355 log_debug("Booting with external fdt\n");
356 fdt = map_sysmem(bflow->fdt_addr, 0);
357 }
358 ret = efi_binary_run_dp(bflow->buf, bflow->size, fdt, device, image);
359
360 return ret;
361}