blob: b677bbc312447e9f39004cdf28ef3c8021110bc0 [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/**
48 * efi_set_bootdev() - set boot device
49 *
50 * This function is called when a file is loaded, e.g. via the 'load' command.
51 * We use the path to this file to inform the UEFI binary about the boot device.
52 *
53 * @dev: device, e.g. "MMC"
54 * @devnr: number of the device, e.g. "1:2"
55 * @path: path to file loaded
56 * @buffer: buffer with file loaded
57 * @buffer_size: size of file loaded
58 */
59void efi_set_bootdev(const char *dev, const char *devnr, const char *path,
60 void *buffer, size_t buffer_size)
61{
62 struct efi_device_path *device, *image;
63 efi_status_t ret;
64
65 log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev,
66 devnr, path, buffer, buffer_size);
67
68 /* Forget overwritten image */
69 if (buffer + buffer_size >= image_addr &&
70 image_addr + image_size >= buffer)
71 efi_clear_bootdev();
72
73 /* Remember only PE-COFF and FIT images */
74 if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) {
75 if (IS_ENABLED(CONFIG_FIT) &&
76 !fit_check_format(buffer, IMAGE_SIZE_INVAL)) {
77 /*
78 * FIT images of type EFI_OS are started via command
79 * bootm. We should not use their boot device with the
80 * bootefi command.
81 */
82 buffer = 0;
83 buffer_size = 0;
84 } else {
85 log_debug("- not remembering image\n");
86 return;
87 }
88 }
89
90 /* efi_set_bootdev() is typically called repeatedly, recover memory */
91 efi_clear_bootdev();
92
93 image_addr = buffer;
94 image_size = buffer_size;
95
Adriano Cordova93cba0f2024-12-04 00:05:23 -030096#if IS_ENABLED(CONFIG_NETDEVICES)
97 if (!strcmp(dev, "Net") || !strcmp(dev, "Http")) {
98 ret = efi_net_set_dp(dev, devnr);
99 if (ret != EFI_SUCCESS)
100 goto error;
101 }
102#endif
103
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900104 ret = efi_dp_from_name(dev, devnr, path, &device, &image);
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300105 if (ret != EFI_SUCCESS)
106 goto error;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900107
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300108 bootefi_device_path = device;
109 if (image) {
110 /* FIXME: image should not contain device */
111 struct efi_device_path *image_tmp = image;
112
113 efi_dp_split_file_path(image, &device, &image);
114 efi_free_pool(image_tmp);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900115 }
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300116 bootefi_image_path = image;
117 log_debug("- boot device %pD\n", device);
118 if (image)
119 log_debug("- image %pD\n", image);
120 return;
121error:
122 log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
123 efi_clear_bootdev();
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900124}
125
126/**
127 * efi_run_image() - run loaded UEFI image
128 *
129 * @source_buffer: memory address of the UEFI image
130 * @source_size: size of the UEFI image
131 * Return: status code
132 */
133efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
134{
135 efi_handle_t mem_handle = NULL, handle;
136 struct efi_device_path *file_path = NULL;
137 struct efi_device_path *msg_path;
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100138 efi_status_t ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900139 u16 *load_options;
140
141 if (!bootefi_device_path || !bootefi_image_path) {
142 log_debug("Not loaded from disk\n");
143 /*
144 * Special case for efi payload not loaded from disk,
145 * such as 'bootefi hello' or for example payload
146 * loaded directly into memory via JTAG, etc:
147 */
148 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
149 (uintptr_t)source_buffer,
150 source_size);
151 /*
152 * Make sure that device for device_path exist
153 * in load_image(). Otherwise, shell and grub will fail.
154 */
155 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
156 &efi_guid_device_path,
157 file_path, NULL);
158 if (ret != EFI_SUCCESS)
159 goto out;
160 msg_path = file_path;
161 } else {
162 file_path = efi_dp_concat(bootefi_device_path,
Heinrich Schuchardtf8de0092024-05-24 14:54:26 +0200163 bootefi_image_path, 0);
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900164 msg_path = bootefi_image_path;
165 log_debug("Loaded from disk\n");
166 }
167
168 log_info("Booting %pD\n", msg_path);
169
170 ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
171 source_size, &handle));
172 if (ret != EFI_SUCCESS) {
173 log_err("Loading image failed\n");
174 goto out;
175 }
176
177 /* Transfer environment variable as load options */
178 ret = efi_env_set_load_options(handle, "bootargs", &load_options);
179 if (ret != EFI_SUCCESS)
180 goto out;
181
182 ret = do_bootefi_exec(handle, load_options);
183
184out:
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100185 if (mem_handle) {
186 efi_status_t r;
187
188 r = efi_uninstall_multiple_protocol_interfaces(
189 mem_handle, &efi_guid_device_path, file_path, NULL);
190 if (r != EFI_SUCCESS)
191 log_err("Uninstalling protocol interfaces failed\n");
192 }
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900193 efi_free_pool(file_path);
Heinrich Schuchardtb41a33f2024-03-16 10:36:42 +0100194
195 return ret;
AKASHI Takahiro9b08b9a2024-01-17 13:39:41 +0900196}
197
198/**
199 * efi_binary_run() - run loaded UEFI image
200 *
201 * @image: memory address of the UEFI image
202 * @size: size of the UEFI image
203 * @fdt: device-tree
204 *
205 * Execute an EFI binary image loaded at @image.
206 * @size may be zero if the binary is loaded with U-Boot load command.
207 *
208 * Return: status code
209 */
210efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
211{
212 efi_status_t ret;
213
214 /* Initialize EFI drivers */
215 ret = efi_init_obj_list();
216 if (ret != EFI_SUCCESS) {
217 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
218 ret & ~EFI_ERROR_MASK);
219 return -1;
220 }
221
222 ret = efi_install_fdt(fdt);
223 if (ret != EFI_SUCCESS)
224 return ret;
225
226 return efi_run_image(image, size);
227}