blob: 4e77a7cbac2fd14838a38a20d7e577e248dec859 [file] [log] [blame]
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * efi_selftest_load_file
4 *
5 * Copyright (c) 2020 Heinrich Schuchardt <xypron.glpk@gmx.de>
6 *
7 * This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol
8 * by the LoadImage() service.
9 */
10
11#include <efi_selftest.h>
12/* Include containing the miniapp.efi application */
13#include "efi_miniapp_file_image_exit.h"
14
15/* Block size of compressed disk image */
16#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
17
18/* Binary logarithm of the block size */
19#define LB_BLOCK_SIZE 9
20
21#define GUID_VENDOR \
22 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
23 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1)
24
25#define GUID_VENDOR2 \
26 EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \
27 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2)
28
29#define FILE_NAME_SIZE 16
30
31static const efi_guid_t efi_st_guid_load_file_protocol =
32 EFI_LOAD_FILE_PROTOCOL_GUID;
33static const efi_guid_t efi_st_guid_load_file2_protocol =
34 EFI_LOAD_FILE2_PROTOCOL_GUID;
35static const efi_guid_t efi_st_guid_device_path =
36 EFI_DEVICE_PATH_PROTOCOL_GUID;
37
38static efi_handle_t image_handle;
39static struct efi_boot_services *boottime;
40static efi_handle_t handle_lf;
41static efi_handle_t handle_lf2;
42
43/* One 8 byte block of the compressed disk image */
44struct line {
45 size_t addr;
46 char *line;
47};
48
49/* Compressed file image */
50struct compressed_file_image {
51 size_t length;
52 struct line lines[];
53};
54
55static struct compressed_file_image img = EFI_ST_DISK_IMG;
56
57static int load_file_call_count;
58static int load_file2_call_count;
59
60/* Decompressed file image */
61static u8 *image;
62
63static struct {
64 struct efi_device_path_vendor v;
65 struct efi_device_path d;
66} dp_lf_prot = {
67 {
68 {
69 DEVICE_PATH_TYPE_HARDWARE_DEVICE,
70 DEVICE_PATH_SUB_TYPE_VENDOR,
71 sizeof(struct efi_device_path_vendor),
72 },
73 GUID_VENDOR,
74 },
75 {
76 DEVICE_PATH_TYPE_END,
77 DEVICE_PATH_SUB_TYPE_END,
78 sizeof(struct efi_device_path),
79 },
80};
81
82static struct {
83 struct efi_device_path_vendor v;
84 struct efi_device_path_file_path f;
85 u16 file_name[FILE_NAME_SIZE];
86 struct efi_device_path e;
87} dp_lf_file = {
88 {
89 {
90 DEVICE_PATH_TYPE_HARDWARE_DEVICE,
91 DEVICE_PATH_SUB_TYPE_VENDOR,
92 sizeof(struct efi_device_path_vendor),
93 },
94 GUID_VENDOR,
95 },
96 {
97 {
98 DEVICE_PATH_TYPE_MEDIA_DEVICE,
99 DEVICE_PATH_SUB_TYPE_FILE_PATH,
100 sizeof(struct efi_device_path_file_path) +
101 FILE_NAME_SIZE * sizeof(u16),
102 }
103 },
Simon Glass90975372022-01-23 12:55:12 -0700104 u"\\lf.efi",
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100105 {
106 DEVICE_PATH_TYPE_END,
107 DEVICE_PATH_SUB_TYPE_END,
108 sizeof(struct efi_device_path),
109 },
110};
111
112struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp;
113
114static struct {
115 struct efi_device_path_vendor v;
116 struct efi_device_path d;
117} dp_lf2_prot = {
118 {
119 {
120 DEVICE_PATH_TYPE_HARDWARE_DEVICE,
121 DEVICE_PATH_SUB_TYPE_VENDOR,
122 sizeof(struct efi_device_path_vendor),
123 },
124 GUID_VENDOR2,
125 },
126 {
127 DEVICE_PATH_TYPE_END,
128 DEVICE_PATH_SUB_TYPE_END,
129 sizeof(struct efi_device_path),
130 },
131};
132
133static struct {
134 struct efi_device_path_vendor v;
135 struct efi_device_path_file_path f;
136 u16 file_name[FILE_NAME_SIZE];
137 struct efi_device_path e;
138} dp_lf2_file = {
139 {
140 {
141 DEVICE_PATH_TYPE_HARDWARE_DEVICE,
142 DEVICE_PATH_SUB_TYPE_VENDOR,
143 sizeof(struct efi_device_path_vendor),
144 },
145 GUID_VENDOR2,
146 },
147 {
148 {
149 DEVICE_PATH_TYPE_MEDIA_DEVICE,
150 DEVICE_PATH_SUB_TYPE_FILE_PATH,
151 sizeof(struct efi_device_path_file_path) +
152 FILE_NAME_SIZE * sizeof(u16),
153 }
154 },
Simon Glass90975372022-01-23 12:55:12 -0700155 u"\\lf2.efi",
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100156 {
157 DEVICE_PATH_TYPE_END,
158 DEVICE_PATH_SUB_TYPE_END,
159 sizeof(struct efi_device_path),
160 },
161};
162
163struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp;
164
165/*
166 * Decompress the disk image.
167 *
168 * @image decompressed disk image
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100169 * Return: status code
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100170 */
171static efi_status_t decompress(u8 **image)
172{
173 u8 *buf;
174 size_t i;
175 size_t addr;
176 size_t len;
177 efi_status_t ret;
178
179 ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
180 (void **)&buf);
181 if (ret != EFI_SUCCESS) {
182 efi_st_error("Out of memory\n");
183 return ret;
184 }
185 boottime->set_mem(buf, img.length, 0);
186
187 for (i = 0; ; ++i) {
188 if (!img.lines[i].line)
189 break;
190 addr = img.lines[i].addr;
191 len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
192 if (addr + len > img.length)
193 len = img.length - addr;
194 boottime->copy_mem(buf + addr, img.lines[i].line, len);
195 }
196 *image = buf;
197 return ret;
198}
199
200/*
201 * load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL
202 *
203 * @this: instance of EFI_LOAD_FILE_PROTOCOL
204 * @file_path: remaining device path
205 * @boot_policy: true if called by boot manager
206 * @buffer_size: (required) buffer size
207 * @buffer: buffer to which the file is to be loaded
208 */
Bin Menga7f3b7b2023-04-05 20:15:16 +0800209static efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this,
210 struct efi_device_path *file_path,
211 bool boot_policy,
212 efi_uintn_t *buffer_size,
213 void *buffer)
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100214{
215 ++load_file_call_count;
216 if (memcmp(file_path, dp_lf_file_remainder,
217 sizeof(struct efi_device_path_file_path) +
218 FILE_NAME_SIZE * sizeof(u16) +
219 sizeof(struct efi_device_path))) {
220 efi_st_error("Wrong remaining device path\n");
221 return EFI_NOT_FOUND;
222 }
223 if (this->load_file != load_file) {
224 efi_st_error("wrong this\n");
225 return EFI_INVALID_PARAMETER;
226 }
227 if (*buffer_size < img.length) {
228 *buffer_size = img.length;
229 return EFI_BUFFER_TOO_SMALL;
230 }
231 memcpy(buffer, image, img.length);
232 *buffer_size = img.length;
233 return EFI_SUCCESS;
234}
235
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100236/*
237 * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL
238 *
239 * @this: instance of EFI_LOAD_FILE2_PROTOCOL
240 * @file_path: remaining device path
241 * @boot_policy: true if called by boot manager
242 * @buffer_size: (required) buffer size
243 * @buffer: buffer to which the file is to be loaded
244 */
Bin Menga7f3b7b2023-04-05 20:15:16 +0800245static efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this,
246 struct efi_device_path *file_path,
247 bool boot_policy,
248 efi_uintn_t *buffer_size,
249 void *buffer)
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100250{
251 ++load_file2_call_count;
252 if (memcmp(file_path, dp_lf2_file_remainder,
253 sizeof(struct efi_device_path_file_path) +
254 FILE_NAME_SIZE * sizeof(u16) +
255 sizeof(struct efi_device_path))) {
256 efi_st_error("Wrong remaining device path\n");
257 return EFI_NOT_FOUND;
258 }
259 if (this->load_file != load_file2) {
260 efi_st_error("wrong this\n");
261 return EFI_INVALID_PARAMETER;
262 }
263 if (boot_policy) {
264 efi_st_error("LOAD_FILE2 called with boot_policy = true");
265 return EFI_INVALID_PARAMETER;
266 }
267 if (*buffer_size < img.length) {
268 *buffer_size = img.length;
269 return EFI_BUFFER_TOO_SMALL;
270 }
271 memcpy(buffer, image, img.length);
272 *buffer_size = img.length;
273 return EFI_SUCCESS;
274}
275
276static struct efi_load_file_protocol lf_prot = {load_file};
277static struct efi_load_file_protocol lf2_prot = {load_file2};
278
279/*
280 * Setup unit test.
281 *
282 * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL.
283 *
284 * @handle: handle of the loaded image
285 * @systable: system table
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100286 * Return: EFI_ST_SUCCESS for success
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100287 */
288static int efi_st_load_file_setup(const efi_handle_t handle,
289 const struct efi_system_table *systable)
290{
291 efi_status_t ret;
292
293 image_handle = handle;
294 boottime = systable->boottime;
295
296 /* Load the application image into memory */
297 decompress(&image);
298
299 ret = boottime->install_multiple_protocol_interfaces(
300 &handle_lf,
301 &efi_st_guid_device_path,
302 &dp_lf_prot,
303 &efi_st_guid_load_file_protocol,
304 &lf_prot,
305 NULL);
306 if (ret != EFI_SUCCESS) {
307 efi_st_error("InstallMultipleProtocolInterfaces failed\n");
308 return EFI_ST_FAILURE;
309 }
310 ret = boottime->install_multiple_protocol_interfaces(
311 &handle_lf2,
312 &efi_st_guid_device_path,
313 &dp_lf2_prot,
314 &efi_st_guid_load_file2_protocol,
315 &lf2_prot,
316 NULL);
317 if (ret != EFI_SUCCESS) {
318 efi_st_error("InstallMultipleProtocolInterfaces failed\n");
319 return EFI_ST_FAILURE;
320 }
321
322 return EFI_ST_SUCCESS;
323}
324
325/*
326 * Tear down unit test.
327 *
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100328 * Return: EFI_ST_SUCCESS for success
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100329 */
330static int efi_st_load_file_teardown(void)
331{
332 efi_status_t ret = EFI_ST_SUCCESS;
333
334 if (handle_lf) {
335 ret = boottime->uninstall_multiple_protocol_interfaces(
336 handle_lf,
337 &efi_st_guid_device_path,
338 &dp_lf_prot,
339 &efi_st_guid_load_file_protocol,
340 &lf_prot,
341 NULL);
342 if (ret != EFI_SUCCESS) {
343 efi_st_error(
344 "UninstallMultipleProtocolInterfaces failed\n");
345 return EFI_ST_FAILURE;
346 }
347 }
348 if (handle_lf2) {
349 ret = boottime->uninstall_multiple_protocol_interfaces(
350 handle_lf2,
351 &efi_st_guid_device_path,
352 &dp_lf2_prot,
353 &efi_st_guid_load_file2_protocol,
354 &lf2_prot,
355 NULL);
356 if (ret != EFI_SUCCESS) {
357 efi_st_error(
358 "UninstallMultipleProtocolInterfaces failed\n");
359 return EFI_ST_FAILURE;
360 }
361 }
362
363 if (image) {
364 ret = boottime->free_pool(image);
365 if (ret != EFI_SUCCESS) {
366 efi_st_error("Failed to free image\n");
367 return EFI_ST_FAILURE;
368 }
369 }
370 return ret;
371}
372
373/*
374 * Execute unit test.
375 *
376 * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the
377 * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image.
378 *
Heinrich Schuchardtfbe90212022-01-20 19:48:20 +0100379 * Return: EFI_ST_SUCCESS for success
Heinrich Schuchardtee3d1e02020-12-08 15:55:01 +0100380 */
381static int efi_st_load_file_execute(void)
382{
383 efi_status_t ret;
384 efi_handle_t handle;
385 efi_uintn_t exit_data_size = 0;
386 u16 *exit_data = NULL;
387 u16 expected_text[] = EFI_ST_SUCCESS_STR;
388
389 load_file_call_count = 0;
390 load_file2_call_count = 0;
391 handle = NULL;
392 ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL,
393 0, &handle);
394 if (ret != EFI_SUCCESS) {
395 efi_st_error("Failed to load image\n");
396 return EFI_ST_FAILURE;
397 }
398 if (load_file2_call_count || !load_file_call_count) {
399 efi_st_error("Wrong image loaded\n");
400 return EFI_ST_FAILURE;
401 }
402 ret = boottime->unload_image(handle);
403 if (ret != EFI_SUCCESS) {
404 efi_st_error("Failed to unload image\n");
405 return EFI_ST_FAILURE;
406 }
407
408 load_file_call_count = 0;
409 load_file2_call_count = 0;
410 handle = NULL;
411 ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL,
412 0, &handle);
413 if (ret != EFI_SUCCESS) {
414 efi_st_error("Failed to load image\n");
415 return EFI_ST_FAILURE;
416 }
417 if (load_file2_call_count || !load_file_call_count) {
418 efi_st_error("Wrong image loaded\n");
419 return EFI_ST_FAILURE;
420 }
421 ret = boottime->unload_image(handle);
422 if (ret != EFI_SUCCESS) {
423 efi_st_error("Failed to unload image\n");
424 return EFI_ST_FAILURE;
425 }
426
427 ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL,
428 0, &handle);
429 if (ret != EFI_NOT_FOUND) {
430 efi_st_error(
431 "Boot manager should not use LOAD_FILE2_PROTOCOL\n");
432 return EFI_ST_FAILURE;
433 }
434
435 load_file_call_count = 0;
436 load_file2_call_count = 0;
437 handle = NULL;
438 ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL,
439 0, &handle);
440 if (ret != EFI_SUCCESS) {
441 efi_st_error("Failed to load image\n");
442 return EFI_ST_FAILURE;
443 }
444 if (!load_file2_call_count || load_file_call_count) {
445 efi_st_error("Wrong image loaded\n");
446 return EFI_ST_FAILURE;
447 }
448
449 ret = boottime->start_image(handle, &exit_data_size, &exit_data);
450 if (ret != EFI_UNSUPPORTED) {
451 efi_st_error("Wrong return value from application\n");
452 return EFI_ST_FAILURE;
453 }
454 if (!exit_data || exit_data_size != sizeof(expected_text) ||
455 memcmp(exit_data, expected_text, sizeof(expected_text))) {
456 efi_st_error("Incorrect exit data\n");
457 return EFI_ST_FAILURE;
458 }
459 ret = boottime->free_pool(exit_data);
460 if (ret != EFI_SUCCESS) {
461 efi_st_error("Failed to free exit data\n");
462 return EFI_ST_FAILURE;
463 }
464
465 return EFI_ST_SUCCESS;
466}
467
468EFI_UNIT_TEST(load_file_protocol) = {
469 .name = "load file protocol",
470 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
471 .setup = efi_st_load_file_setup,
472 .execute = efi_st_load_file_execute,
473 .teardown = efi_st_load_file_teardown,
474};