efi_loader: validate load option
[oweals/u-boot.git] / lib / efi_selftest / efi_selftest_startimage_exit.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * efi_selftest_start_image
4  *
5  * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  *
7  * This test checks the StartImage boot service.
8  * The efi_selftest_miniapp_exit.efi application is loaded into memory
9  * and started.
10  */
11
12 #include <efi_selftest.h>
13 /* Include containing the miniapp.efi application */
14 #include "efi_miniapp_file_image_exit.h"
15
16 /* Block size of compressed disk image */
17 #define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8
18
19 /* Binary logarithm of the block size */
20 #define LB_BLOCK_SIZE 9
21
22 static efi_handle_t image_handle;
23 static struct efi_boot_services *boottime;
24
25 /* One 8 byte block of the compressed disk image */
26 struct line {
27         size_t addr;
28         char *line;
29 };
30
31 /* Compressed file image */
32 struct compressed_file_image {
33         size_t length;
34         struct line lines[];
35 };
36
37 static struct compressed_file_image img = EFI_ST_DISK_IMG;
38
39 /* Decompressed file image */
40 static u8 *image;
41
42 /*
43  * Decompress the disk image.
44  *
45  * @image       decompressed disk image
46  * @return      status code
47  */
48 static efi_status_t decompress(u8 **image)
49 {
50         u8 *buf;
51         size_t i;
52         size_t addr;
53         size_t len;
54         efi_status_t ret;
55
56         ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length,
57                                       (void **)&buf);
58         if (ret != EFI_SUCCESS) {
59                 efi_st_error("Out of memory\n");
60                 return ret;
61         }
62         boottime->set_mem(buf, img.length, 0);
63
64         for (i = 0; ; ++i) {
65                 if (!img.lines[i].line)
66                         break;
67                 addr = img.lines[i].addr;
68                 len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE;
69                 if (addr + len > img.length)
70                         len = img.length - addr;
71                 boottime->copy_mem(buf + addr, img.lines[i].line, len);
72         }
73         *image = buf;
74         return ret;
75 }
76
77 /*
78  * Setup unit test.
79  *
80  * @handle:     handle of the loaded image
81  * @systable:   system table
82  * @return:     EFI_ST_SUCCESS for success
83  */
84 static int setup(const efi_handle_t handle,
85                  const struct efi_system_table *systable)
86 {
87         image_handle = handle;
88         boottime = systable->boottime;
89
90         /* Load the application image into memory */
91         decompress(&image);
92
93         return EFI_ST_SUCCESS;
94 }
95
96 /*
97  * Tear down unit test.
98  *
99  * @return:     EFI_ST_SUCCESS for success
100  */
101 static int teardown(void)
102 {
103         efi_status_t r = EFI_ST_SUCCESS;
104
105         if (image) {
106                 r = boottime->free_pool(image);
107                 if (r != EFI_SUCCESS) {
108                         efi_st_error("Failed to free image\n");
109                         return EFI_ST_FAILURE;
110                 }
111         }
112         return r;
113 }
114
115 /*
116  * Execute unit test.
117  *
118  * Load and start the application image.
119  *
120  * @return:     EFI_ST_SUCCESS for success
121  */
122 static int execute(void)
123 {
124         efi_status_t ret;
125         efi_handle_t handle;
126         efi_uintn_t exit_data_size = 0;
127         u16 *exit_data = NULL;
128         u16 expected_text[] = EFI_ST_SUCCESS_STR;
129
130         ret = boottime->load_image(false, image_handle, NULL, image,
131                                    img.length, &handle);
132         if (ret != EFI_SUCCESS) {
133                 efi_st_error("Failed to load image\n");
134                 return EFI_ST_FAILURE;
135         }
136         ret = boottime->start_image(handle, &exit_data_size, &exit_data);
137         if (ret != EFI_UNSUPPORTED) {
138                 efi_st_error("Wrong return value from application\n");
139                 return EFI_ST_FAILURE;
140         }
141         if (!exit_data || exit_data_size != sizeof(expected_text) ||
142             memcmp(exit_data, expected_text, sizeof(expected_text))) {
143                 efi_st_error("Incorrect exit data\n");
144                 return EFI_ST_FAILURE;
145         }
146         ret = boottime->free_pool(exit_data);
147         if (ret != EFI_SUCCESS) {
148                 efi_st_error("Failed to free exit data\n");
149                 return EFI_ST_FAILURE;
150         }
151
152         return EFI_ST_SUCCESS;
153 }
154
155 EFI_UNIT_TEST(startimage_exit) = {
156         .name = "start image exit",
157         .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
158         .setup = setup,
159         .execute = execute,
160         .teardown = teardown,
161 };