blob: 789da8bcda0bfcb946185ed1bb0c0d40e4043ac0 [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
9#include <charset.h>
10#include <efi.h>
11#include <efi_loader.h>
12#include <env.h>
13#include <image.h>
14#include <log.h>
15#include <malloc.h>
16
17static struct efi_device_path *bootefi_image_path;
18static struct efi_device_path *bootefi_device_path;
19static void *image_addr;
20static size_t image_size;
21
22/**
23 * efi_get_image_parameters() - return image parameters
24 *
25 * @img_addr: address of loaded image in memory
26 * @img_size: size of loaded image
27 */
28void efi_get_image_parameters(void **img_addr, size_t *img_size)
29{
30 *img_addr = image_addr;
31 *img_size = image_size;
32}
33
34/**
35 * efi_clear_bootdev() - clear boot device
36 */
37void efi_clear_bootdev(void)
38{
39 efi_free_pool(bootefi_device_path);
40 efi_free_pool(bootefi_image_path);
41 bootefi_device_path = NULL;
42 bootefi_image_path = NULL;
43 image_addr = NULL;
44 image_size = 0;
45}
46
47/**
Simon Glassa53fbb72025-01-09 08:02:38 -070048 * calculate_paths() - Calculate the device and image patch from strings
49 *
50 * @dev: device, e.g. "MMC"
51 * @devnr: number of the device, e.g. "1:2"
52 * @path: path to file loaded
53 * @device_pathp: returns EFI device path
54 * @image_pathp: returns EFI image path
55 * Return: EFI_SUCCESS on success, else error code
56 */
57static efi_status_t calculate_paths(const char *dev, const char *devnr,
58 const char *path,
59 struct efi_device_path **device_pathp,
60 struct efi_device_path **image_pathp)
61{
62 struct efi_device_path *image, *device;
63 efi_status_t ret;
64
65#if IS_ENABLED(CONFIG_NETDEVICES)
66 if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) {
67 ret = efi_net_set_dp(dev, devnr);
68 if (ret != EFI_SUCCESS)
69 return ret;
70 }
71#endif
72
73 ret = efi_dp_from_name(dev, devnr, path, &device, &image);
74 if (ret != EFI_SUCCESS)
75 return ret;
76
77 *device_pathp = device;
78 if (image) {
79 /* FIXME: image should not contain device */
80 struct efi_device_path *image_tmp = image;
81
82 efi_dp_split_file_path(image, &device, &image);
83 efi_free_pool(image_tmp);
84 }
85 *image_pathp = image;
86 log_debug("- boot device %pD\n", device);
87 if (image)
88 log_debug("- image %pD\n", image);
89
90 return EFI_SUCCESS;
91}
92
93/**
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +090094 * efi_set_bootdev() - set boot device
95 *
96 * This function is called when a file is loaded, e.g. via the 'load' command.
97 * We use the path to this file to inform the UEFI binary about the boot device.
98 *
Simon Glassa53fbb72025-01-09 08:02:38 -070099 * For a valid image, it sets:
100 * - image_addr to the provided buffer
101 * - image_size to the provided buffer_size
102 * - bootefi_device_path to the EFI device-path
103 * - bootefi_image_path to the EFI image-path
104 *
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900105 * @dev: device, e.g. "MMC"
106 * @devnr: number of the device, e.g. "1:2"
107 * @path: path to file loaded
108 * @buffer: buffer with file loaded
109 * @buffer_size: size of file loaded
110 */
111void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
112 void *buffer, size_t buffer_size)
113{
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900114 efi_status_t ret;
115
116 log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
117 devnr, path, buffer, buffer_size);
118
119 /* Forget overwritten image */
120 if (buffer + buffer_size >= image_addr &&
121 image_addr + image_size >= buffer)
122 efi_clear_bootdev();
123
124 /* Remember only PE-COFF and FIT images */
125 if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
126 if (IS_ENABLED(CONFIG_FIT) &&
127 !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
128 /*
129 * FIT images of type EFI_OS are started via command
130 * bootm. We should not use their boot device with the
131 * bootefi command.
132 */
133 buffer = 0;
134 buffer_size = 0;
135 } else {
136 log_debug("- not remembering image\n");
137 return;
138 }
139 }
140
141 /* efi_set_bootdev() is typically called repeatedly, recover memory */
142 efi_clear_bootdev();
143
144 image_addr = buffer;
145 image_size = buffer_size;
146
Simon Glassa53fbb72025-01-09 08:02:38 -0700147 ret = calculate_paths(dev, devnr, path, &bootefi_device_path,
148 &bootefi_image_path);
149 if (ret) {
150 log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
151 efi_clear_bootdev();
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900152 }
153}
154
155/**
156 * efi_run_image() - run loaded UEFI image
157 *
158 * @source_buffer: memory address of the UEFI image
159 * @source_size: size of the UEFI image
Simon Glassa39a78b2025-01-23 15:07:20 -0700160 * @dp_dev: EFI device-path
161 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900162 * Return: status code
163 */
Simon Glassa39a78b2025-01-23 15:07:20 -0700164static efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size,
165 struct efi_device_path *dp_dev,
166 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900167{
168 efi_handle_t mem_handle = NULL, handle;
169 struct efi_device_path *file_path = NULL;
170 struct efi_device_path *msg_path;
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100171 efi_status_t ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900172 u16 *load_options;
173
Simon Glassa39a78b2025-01-23 15:07:20 -0700174 if (!dp_img || !dp_img) {
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900175 log_debug("Not loaded from disk\n");
176 /*
177 * Special case for efi payload not loaded from disk,
178 * such as 'bootefi hello' or for example payload
179 * loaded directly into memory via JTAG, etc:
180 */
181 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
182 (uintptr_t)source_buffer,
183 source_size);
184 /*
185 * Make sure that device for device_path exist
186 * in load_image(). Otherwise, shell and grub will fail.
187 */
188 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
189 &efi_guid_device_path,
190 file_path, NULL);
191 if (ret != EFI_SUCCESS)
192 goto out;
193 msg_path = file_path;
194 } else {
Simon Glassa39a78b2025-01-23 15:07:20 -0700195 file_path = efi_dp_concat(dp_img, dp_img, 0);
196 msg_path = dp_img;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900197 log_debug("Loaded from disk\n");
198 }
199
200 log_info("Booting %pD\n", msg_path);
201
202 ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
203 source_size, &handle));
204 if (ret != EFI_SUCCESS) {
205 log_err("Loading image failed\n");
206 goto out;
207 }
208
209 /* Transfer environment variable as load options */
210 ret = efi_env_set_load_options(handle, "bootargs", &load_options);
211 if (ret != EFI_SUCCESS)
212 goto out;
213
214 ret = do_bootefi_exec(handle, load_options);
215
216out:
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100217 if (mem_handle) {
218 efi_status_t r;
219
220 r = efi_uninstall_multiple_protocol_interfaces(
221 mem_handle, &efi_guid_device_path, file_path, NULL);
222 if (r != EFI_SUCCESS)
223 log_err("Uninstalling protocol interfaces failed\n");
224 }
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900225 efi_free_pool(file_path);
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100226
227 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900228}
229
230/**
Simon Glass44d57f62025-01-23 15:07:21 -0700231 * efi_binary_run_dp() - run loaded UEFI image
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900232 *
233 * @image: memory address of the UEFI image
234 * @size: size of the UEFI image
235 * @fdt: device-tree
Simon Glass44d57f62025-01-23 15:07:21 -0700236 * @dp_dev: EFI device-path
237 * @dp_img: EFI image-path
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900238 *
239 * Execute an EFI binary image loaded at @image.
240 * @size may be zero if the binary is loaded with U-Boot load command.
241 *
242 * Return: status code
243 */
Simon Glass44d57f62025-01-23 15:07:21 -0700244efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt,
245 struct efi_device_path *dp_dev,
246 struct efi_device_path *dp_img)
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900247{
248 efi_status_t ret;
249
250 /* Initialize EFI drivers */
251 ret = efi_init_obj_list();
252 if (ret != EFI_SUCCESS) {
253 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
254 ret & ~EFI_ERROR_MASK);
255 return -1;
256 }
257
258 ret = efi_install_fdt(fdt);
259 if (ret != EFI_SUCCESS)
260 return ret;
261
Simon Glass44d57f62025-01-23 15:07:21 -0700262 return efi_run_image(image, size, dp_dev, dp_img);
263}
264
265/**
266 * efi_binary_run() - run loaded UEFI image
267 *
268 * @image: memory address of the UEFI image
269 * @size: size of the UEFI image
270 * @fdt: device-tree
271 *
272 * Execute an EFI binary image loaded at @image.
273 * @size may be zero if the binary is loaded with U-Boot load command.
274 *
275 * Return: status code
276 */
277efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
278{
279 return efi_binary_run_dp(image, size, fdt, bootefi_device_path,
280 bootefi_image_path);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900281}