blob: b394f0d60cecc822c40f3a2d50c4147a88195cf9 [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>
Simon Glass37972f42025-05-24 11:28:21 -060013#include <efi_device_path.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090014#include <efi_loader.h>
15#include <env.h>
16#include <image.h>
17#include <log.h>
18#include <malloc.h>
Simon Glassfce57772025-01-23 15:07:23 -070019#include <mapmem.h>
Adriano Cordova54674692025-03-03 11:13:15 -030020#include <net.h>
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090021
22static struct efi_device_path *bootefi_image_path;
23static struct efi_device_path *bootefi_device_path;
24static void *image_addr;
25static size_t image_size;
26
27/**
28 * efi_get_image_parameters() - return image parameters
29 *
30 * @img_addr: address of loaded image in memory
31 * @img_size: size of loaded image
32 */
33void efi_get_image_parameters(void **img_addr, size_t *img_size)
34{
35 *img_addr = image_addr;
36 *img_size = image_size;
37}
38
39/**
40 * efi_clear_bootdev() - clear boot device
41 */
42void efi_clear_bootdev(void)
43{
44 efi_free_pool(bootefi_device_path);
45 efi_free_pool(bootefi_image_path);
46 bootefi_device_path = NULL;
47 bootefi_image_path = NULL;
48 image_addr = NULL;
49 image_size = 0;
50}
51
52/**
Simon Glassa53fbb72025-01-09 08:02:38 -070053 * calculate_paths() - Calculate the device and image patch from strings
54 *
55 * @dev: device, e.g. "MMC"
56 * @devnr: number of the device, e.g. "1:2"
57 * @path: path to file loaded
58 * @device_pathp: returns EFI device path
59 * @image_pathp: returns EFI image path
60 * Return: EFI_SUCCESS on success, else error code
61 */
62static efi_status_t calculate_paths(const char *dev, const char *devnr,
63 const char *path,
64 struct efi_device_path **device_pathp,
65 struct efi_device_path **image_pathp)
66{
67 struct efi_device_path *image, *device;
68 efi_status_t ret;
69
70#if IS_ENABLED(CONFIG_NETDEVICES)
71 if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) {
Adriano Cordova54674692025-03-03 11:13:15 -030072 ret = efi_net_new_dp(dev, devnr, eth_get_dev());
Simon Glassa53fbb72025-01-09 08:02:38 -070073 if (ret != EFI_SUCCESS)
74 return ret;
75 }
76#endif
77
78 ret = efi_dp_from_name(dev, devnr, path, &device, &image);
79 if (ret != EFI_SUCCESS)
80 return ret;
81
82 *device_pathp = device;
83 if (image) {
84 /* FIXME: image should not contain device */
85 struct efi_device_path *image_tmp = image;
86
87 efi_dp_split_file_path(image, &device, &image);
88 efi_free_pool(image_tmp);
89 }
90 *image_pathp = image;
91 log_debug("- boot device %pD\n", device);
92 if (image)
93 log_debug("- image %pD\n", image);
94
95 return EFI_SUCCESS;
96}
97
98/**
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090099 * efi_set_bootdev() - set boot device
100 *
101 * This function is called when a file is loaded, e.g. via the 'load' command.
102 * We use the path to this file to inform the UEFI binary about the boot device.
103 *
Simon Glassa53fbb72025-01-09 08:02:38 -0700104 * For a valid image, it sets:
105 * - image_addr to the provided buffer
106 * - image_size to the provided buffer_size
107 * - bootefi_device_path to the EFI device-path
108 * - bootefi_image_path to the EFI image-path
109 *
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900110 * @dev: device, e.g. "MMC"
111 * @devnr: number of the device, e.g. "1:2"
112 * @path: path to file loaded
113 * @buffer: buffer with file loaded
114 * @buffer_size: size of file loaded
115 */
116void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
117 void *buffer, size_t buffer_size)
118{
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900119 efi_status_t ret;
120
121 log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
122 devnr, path, buffer, buffer_size);
123
124 /* Forget overwritten image */
125 if (buffer + buffer_size >= image_addr &&
126 image_addr + image_size >= buffer)
127 efi_clear_bootdev();
128
129 /* Remember only PE-COFF and FIT images */
130 if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
131 if (IS_ENABLED(CONFIG_FIT) &&
132 !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
133 /*
134 * FIT images of type EFI_OS are started via command
135 * bootm. We should not use their boot device with the
136 * bootefi command.
137 */
138 buffer = 0;
139 buffer_size = 0;
140 } else {
141 log_debug("- not remembering image\n");
142 return;
143 }
144 }
145
146 /* efi_set_bootdev() is typically called repeatedly, recover memory */
147 efi_clear_bootdev();
148
149 image_addr = buffer;
150 image_size = buffer_size;
151
Simon Glassa53fbb72025-01-09 08:02:38 -0700152 ret = calculate_paths(dev, devnr, path, &bootefi_device_path,
153 &bootefi_image_path);
154 if (ret) {
155 log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
156 efi_clear_bootdev();
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900157 }
158}
159
160/**
161 * efi_run_image() - run loaded UEFI image
162 *
163 * @source_buffer: memory address of the UEFI image
164 * @source_size: size of the UEFI image
Simon Glassa39a78b2025-01-23 15:07:20 -0700165 * @dp_dev: EFI device-path
166 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900167 * Return: status code
168 */
Simon Glassa39a78b2025-01-23 15:07:20 -0700169static efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size,
170 struct efi_device_path *dp_dev,
171 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900172{
Simon Glassc14b38f2025-01-23 15:07:22 -0700173 efi_handle_t handle;
174 struct efi_device_path *msg_path, *file_path;
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100175 efi_status_t ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900176 u16 *load_options;
177
Simon Glassc14b38f2025-01-23 15:07:22 -0700178 file_path = efi_dp_concat(dp_dev, dp_img, 0);
179 msg_path = dp_img;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900180
181 log_info("Booting %pD\n", msg_path);
182
183 ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
184 source_size, &handle));
185 if (ret != EFI_SUCCESS) {
186 log_err("Loading image failed\n");
187 goto out;
188 }
189
190 /* Transfer environment variable as load options */
191 ret = efi_env_set_load_options(handle, "bootargs", &load_options);
192 if (ret != EFI_SUCCESS)
193 goto out;
194
195 ret = do_bootefi_exec(handle, load_options);
196
197out:
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100198
199 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900200}
201
202/**
Simon Glass44d57f62025-01-23 15:07:21 -0700203 * efi_binary_run_dp() - run loaded UEFI image
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900204 *
205 * @image: memory address of the UEFI image
206 * @size: size of the UEFI image
207 * @fdt: device-tree
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300208 * @initrd: initrd
209 * @initrd_sz: initrd size
Simon Glass44d57f62025-01-23 15:07:21 -0700210 * @dp_dev: EFI device-path
211 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900212 *
213 * Execute an EFI binary image loaded at @image.
214 * @size may be zero if the binary is loaded with U-Boot load command.
215 *
216 * Return: status code
217 */
Simon Glassc14b38f2025-01-23 15:07:22 -0700218static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt,
Adriano Cordova565e5302025-04-29 09:27:56 -0400219 void *initrd, size_t initrd_sz,
Simon Glassc14b38f2025-01-23 15:07:22 -0700220 struct efi_device_path *dp_dev,
221 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900222{
223 efi_status_t ret;
224
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 Cordova565e5302025-04-29 09:27:56 -0400237 ret = efi_install_initrd(initrd, initrd_sz);
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300238 if (ret != EFI_SUCCESS)
239 return ret;
240
Simon Glass44d57f62025-01-23 15:07:21 -0700241 return efi_run_image(image, size, dp_dev, dp_img);
242}
243
244/**
245 * efi_binary_run() - run loaded UEFI image
246 *
247 * @image: memory address of the UEFI image
248 * @size: size of the UEFI image
249 * @fdt: device-tree
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300250 * @initrd: initrd
251 * @initrd_sz: initrd size
Simon Glass44d57f62025-01-23 15:07:21 -0700252 *
253 * Execute an EFI binary image loaded at @image.
254 * @size may be zero if the binary is loaded with U-Boot load command.
255 *
256 * Return: status code
257 */
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300258efi_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 -0700259{
Simon Glassc14b38f2025-01-23 15:07:22 -0700260 efi_handle_t mem_handle = NULL;
261 struct efi_device_path *file_path = NULL;
262 efi_status_t ret;
263
264 if (!bootefi_device_path || !bootefi_image_path) {
265 log_debug("Not loaded from disk\n");
266 /*
267 * Special case for efi payload not loaded from disk,
268 * such as 'bootefi hello' or for example payload
269 * loaded directly into memory via JTAG, etc:
270 */
271 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
272 (uintptr_t)image, size);
273 /*
274 * Make sure that device for device_path exist
275 * in load_image(). Otherwise, shell and grub will fail.
276 */
277 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
278 &efi_guid_device_path,
279 file_path, NULL);
280 if (ret != EFI_SUCCESS)
281 goto out;
Christian Kohlschütter723776c2025-03-23 20:03:03 +0100282
283 bootefi_device_path = file_path;
284 bootefi_image_path = NULL;
Simon Glassc14b38f2025-01-23 15:07:22 -0700285 } else {
286 log_debug("Loaded from disk\n");
287 }
288
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300289 ret = efi_binary_run_dp(image, size, fdt, initrd, initrd_sz, bootefi_device_path,
Simon Glassc14b38f2025-01-23 15:07:22 -0700290 bootefi_image_path);
291out:
292 if (mem_handle) {
293 efi_status_t r;
294
295 r = efi_uninstall_multiple_protocol_interfaces(mem_handle,
296 &efi_guid_device_path, file_path, NULL);
297 if (r != EFI_SUCCESS)
298 log_err("Uninstalling protocol interfaces failed\n");
299 }
300 efi_free_pool(file_path);
301
302 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900303}
Simon Glassfce57772025-01-23 15:07:23 -0700304
305/**
306 * calc_dev_name() - Calculate the device name to give to EFI
307 *
308 * If not supported, this shows an error.
309 *
310 * Return name, or NULL if not supported
311 */
312static const char *calc_dev_name(struct bootflow *bflow)
313{
314 const struct udevice *media_dev;
315
316 media_dev = dev_get_parent(bflow->dev);
317
318 if (!bflow->blk) {
Simon Glassff055b02025-01-23 15:07:24 -0700319 if (device_get_uclass_id(media_dev) == UCLASS_ETH)
320 return "Net";
321
Simon Glassfce57772025-01-23 15:07:23 -0700322 log_err("Cannot boot EFI app on media '%s'\n",
323 dev_get_uclass_name(media_dev));
324
325 return NULL;
326 }
327
328 if (device_get_uclass_id(media_dev) == UCLASS_MASS_STORAGE)
329 return "usb";
330
331 return blk_get_uclass_name(device_get_uclass_id(media_dev));
332}
333
334efi_status_t efi_bootflow_run(struct bootflow *bflow)
335{
336 struct efi_device_path *device, *image;
337 const struct udevice *media_dev;
338 struct blk_desc *desc = NULL;
339 const char *dev_name;
340 char devnum_str[9];
341 efi_status_t ret;
342 void *fdt;
343
344 media_dev = dev_get_parent(bflow->dev);
345 if (bflow->blk) {
346 desc = dev_get_uclass_plat(bflow->blk);
347
348 snprintf(devnum_str, sizeof(devnum_str), "%x:%x",
349 desc ? desc->devnum : dev_seq(media_dev), bflow->part);
350 } else {
351 *devnum_str = '\0';
352 }
353
354 dev_name = calc_dev_name(bflow);
355 log_debug("dev_name '%s' devnum_str '%s' fname '%s' media_dev '%s'\n",
356 dev_name, devnum_str, bflow->fname, media_dev->name);
357 if (!dev_name)
358 return EFI_UNSUPPORTED;
359 ret = calculate_paths(dev_name, devnum_str, bflow->fname, &device,
360 &image);
361 if (ret)
Simon Glassff055b02025-01-23 15:07:24 -0700362 return EFI_UNSUPPORTED;
Simon Glassfce57772025-01-23 15:07:23 -0700363
364 if (bflow->flags & BOOTFLOWF_USE_BUILTIN_FDT) {
365 log_debug("Booting with built-in fdt\n");
366 fdt = EFI_FDT_USE_INTERNAL;
367 } else {
368 log_debug("Booting with external fdt\n");
369 fdt = map_sysmem(bflow->fdt_addr, 0);
370 }
Adriano Cordovacea09ba2025-03-19 11:45:00 -0300371 ret = efi_binary_run_dp(bflow->buf, bflow->size, fdt, NULL, 0, device, image);
Simon Glassfce57772025-01-23 15:07:23 -0700372
373 return ret;
374}