]> git.ipfire.org Git - thirdparty/u-boot.git/blob - lib/efi_loader/efi_bootbin.c
efi_loader: correct handling of EFI binary return code
[thirdparty/u-boot.git] / lib / efi_loader / efi_bootbin.c
1 // 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
17 static struct efi_device_path *bootefi_image_path;
18 static struct efi_device_path *bootefi_device_path;
19 static void *image_addr;
20 static 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 */
28 void 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 */
37 void 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 */
59 void 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
96 ret = efi_dp_from_name(dev, devnr, path, &device, &image);
97 if (ret == EFI_SUCCESS) {
98 bootefi_device_path = device;
99 if (image) {
100 /* FIXME: image should not contain device */
101 struct efi_device_path *image_tmp = image;
102
103 efi_dp_split_file_path(image, &device, &image);
104 efi_free_pool(image_tmp);
105 }
106 bootefi_image_path = image;
107 log_debug("- boot device %pD\n", device);
108 if (image)
109 log_debug("- image %pD\n", image);
110 } else {
111 log_debug("- efi_dp_from_name() failed, err=%lx\n", ret);
112 efi_clear_bootdev();
113 }
114 }
115
116 /**
117 * efi_run_image() - run loaded UEFI image
118 *
119 * @source_buffer: memory address of the UEFI image
120 * @source_size: size of the UEFI image
121 * Return: status code
122 */
123 efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size)
124 {
125 efi_handle_t mem_handle = NULL, handle;
126 struct efi_device_path *file_path = NULL;
127 struct efi_device_path *msg_path;
128 efi_status_t ret;
129 u16 *load_options;
130
131 if (!bootefi_device_path || !bootefi_image_path) {
132 log_debug("Not loaded from disk\n");
133 /*
134 * Special case for efi payload not loaded from disk,
135 * such as 'bootefi hello' or for example payload
136 * loaded directly into memory via JTAG, etc:
137 */
138 file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
139 (uintptr_t)source_buffer,
140 source_size);
141 /*
142 * Make sure that device for device_path exist
143 * in load_image(). Otherwise, shell and grub will fail.
144 */
145 ret = efi_install_multiple_protocol_interfaces(&mem_handle,
146 &efi_guid_device_path,
147 file_path, NULL);
148 if (ret != EFI_SUCCESS)
149 goto out;
150 msg_path = file_path;
151 } else {
152 file_path = efi_dp_concat(bootefi_device_path,
153 bootefi_image_path, false);
154 msg_path = bootefi_image_path;
155 log_debug("Loaded from disk\n");
156 }
157
158 log_info("Booting %pD\n", msg_path);
159
160 ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer,
161 source_size, &handle));
162 if (ret != EFI_SUCCESS) {
163 log_err("Loading image failed\n");
164 goto out;
165 }
166
167 /* Transfer environment variable as load options */
168 ret = efi_env_set_load_options(handle, "bootargs", &load_options);
169 if (ret != EFI_SUCCESS)
170 goto out;
171
172 ret = do_bootefi_exec(handle, load_options);
173
174 out:
175 if (mem_handle) {
176 efi_status_t r;
177
178 r = efi_uninstall_multiple_protocol_interfaces(
179 mem_handle, &efi_guid_device_path, file_path, NULL);
180 if (r != EFI_SUCCESS)
181 log_err("Uninstalling protocol interfaces failed\n");
182 }
183 efi_free_pool(file_path);
184
185 return ret;
186 }
187
188 /**
189 * efi_binary_run() - run loaded UEFI image
190 *
191 * @image: memory address of the UEFI image
192 * @size: size of the UEFI image
193 * @fdt: device-tree
194 *
195 * Execute an EFI binary image loaded at @image.
196 * @size may be zero if the binary is loaded with U-Boot load command.
197 *
198 * Return: status code
199 */
200 efi_status_t efi_binary_run(void *image, size_t size, void *fdt)
201 {
202 efi_status_t ret;
203
204 /* Initialize EFI drivers */
205 ret = efi_init_obj_list();
206 if (ret != EFI_SUCCESS) {
207 log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n",
208 ret & ~EFI_ERROR_MASK);
209 return -1;
210 }
211
212 ret = efi_install_fdt(fdt);
213 if (ret != EFI_SUCCESS)
214 return ret;
215
216 return efi_run_image(image, size);
217 }