b8eed048c23d1275d16c60ece2af01abf581028a
[platform/kernel/u-boot.git] / lib / efi_selftest / efi_selftest.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * EFI efi_selftest
4  *
5  * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
6  */
7
8 #include <command.h>
9 #include <efi_selftest.h>
10 #include <vsprintf.h>
11
12 /* Constants for test step bitmap */
13 #define EFI_ST_SETUP    1
14 #define EFI_ST_EXECUTE  2
15 #define EFI_ST_TEARDOWN 4
16
17 static const struct efi_system_table *systable;
18 static const struct efi_boot_services *boottime;
19 static const struct efi_runtime_services *runtime;
20 static efi_handle_t handle;
21 static u16 reset_message[] = L"Selftest completed";
22 static int *setup_status;
23
24 /*
25  * Exit the boot services.
26  *
27  * The size of the memory map is determined.
28  * Pool memory is allocated to copy the memory map.
29  * The memory map is copied and the map key is obtained.
30  * The map key is used to exit the boot services.
31  */
32 void efi_st_exit_boot_services(void)
33 {
34         efi_uintn_t map_size = 0;
35         efi_uintn_t map_key;
36         efi_uintn_t desc_size;
37         u32 desc_version;
38         efi_status_t ret;
39         struct efi_mem_desc *memory_map;
40
41         /* Do not detach devices in ExitBootServices. We need the console. */
42         efi_st_keep_devices = true;
43
44         ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size,
45                                        &desc_version);
46         if (ret != EFI_BUFFER_TOO_SMALL) {
47                 efi_st_error(
48                         "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
49                 return;
50         }
51         /* Allocate extra space for newly allocated memory */
52         map_size += sizeof(struct efi_mem_desc);
53         ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size,
54                                       (void **)&memory_map);
55         if (ret != EFI_SUCCESS) {
56                 efi_st_error("AllocatePool did not return EFI_SUCCESS\n");
57                 return;
58         }
59         ret = boottime->get_memory_map(&map_size, memory_map, &map_key,
60                                        &desc_size, &desc_version);
61         if (ret != EFI_SUCCESS) {
62                 efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n");
63                 return;
64         }
65         ret = boottime->exit_boot_services(handle, map_key);
66         if (ret != EFI_SUCCESS) {
67                 efi_st_error("ExitBootServices did not return EFI_SUCCESS\n");
68                 return;
69         }
70         efi_st_printc(EFI_WHITE, "\nBoot services terminated\n");
71 }
72
73 /*
74  * Set up a test.
75  *
76  * @test        the test to be executed
77  * @failures    counter that will be incremented if a failure occurs
78  * @return      EFI_ST_SUCCESS for success
79  */
80 static int setup(struct efi_unit_test *test, unsigned int *failures)
81 {
82         int ret;
83
84         if (!test->setup)
85                 return EFI_ST_SUCCESS;
86         efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name);
87         ret = test->setup(handle, systable);
88         if (ret != EFI_ST_SUCCESS) {
89                 efi_st_error("Setting up '%s' failed\n", test->name);
90                 ++*failures;
91         } else {
92                 efi_st_printc(EFI_LIGHTGREEN,
93                               "Setting up '%s' succeeded\n", test->name);
94         }
95         return ret;
96 }
97
98 /*
99  * Execute a test.
100  *
101  * @test        the test to be executed
102  * @failures    counter that will be incremented if a failure occurs
103  * @return      EFI_ST_SUCCESS for success
104  */
105 static int execute(struct efi_unit_test *test, unsigned int *failures)
106 {
107         int ret;
108
109         if (!test->execute)
110                 return EFI_ST_SUCCESS;
111         efi_st_printc(EFI_LIGHTBLUE, "\nExecuting '%s'\n", test->name);
112         ret = test->execute();
113         if (ret != EFI_ST_SUCCESS) {
114                 efi_st_error("Executing '%s' failed\n", test->name);
115                 ++*failures;
116         } else {
117                 efi_st_printc(EFI_LIGHTGREEN,
118                               "Executing '%s' succeeded\n", test->name);
119         }
120         return ret;
121 }
122
123 /*
124  * Tear down a test.
125  *
126  * @test        the test to be torn down
127  * @failures    counter that will be incremented if a failure occurs
128  * @return      EFI_ST_SUCCESS for success
129  */
130 static int teardown(struct efi_unit_test *test, unsigned int *failures)
131 {
132         int ret;
133
134         if (!test->teardown)
135                 return EFI_ST_SUCCESS;
136         efi_st_printc(EFI_LIGHTBLUE, "\nTearing down '%s'\n", test->name);
137         ret = test->teardown();
138         if (ret != EFI_ST_SUCCESS) {
139                 efi_st_error("Tearing down '%s' failed\n", test->name);
140                 ++*failures;
141         } else {
142                 efi_st_printc(EFI_LIGHTGREEN,
143                               "Tearing down '%s' succeeded\n", test->name);
144         }
145         return ret;
146 }
147
148 /*
149  * Check that a test requiring reset exists.
150  *
151  * @testname:   name of the test
152  * @return:     test, or NULL if not found
153  */
154 static bool need_reset(const u16 *testname)
155 {
156         struct efi_unit_test *test;
157
158         for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
159              test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
160                 if (testname && efi_st_strcmp_16_8(testname, test->name))
161                         continue;
162                 if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT ||
163                     test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT)
164                         return true;
165         }
166         return false;
167 }
168
169 /*
170  * Check that a test exists.
171  *
172  * @testname:   name of the test
173  * @return:     test, or NULL if not found
174  */
175 static struct efi_unit_test *find_test(const u16 *testname)
176 {
177         struct efi_unit_test *test;
178
179         for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
180              test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
181                 if (!efi_st_strcmp_16_8(testname, test->name))
182                         return test;
183         }
184         efi_st_printf("\nTest '%ps' not found\n", testname);
185         return NULL;
186 }
187
188 /*
189  * List all available tests.
190  */
191 static void list_all_tests(void)
192 {
193         struct efi_unit_test *test;
194
195         /* List all tests */
196         efi_st_printf("\nAvailable tests:\n");
197         for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
198              test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) {
199                 efi_st_printf("'%s'%s\n", test->name,
200                               test->on_request ? " - on request" : "");
201         }
202 }
203
204 /*
205  * Execute test steps of one phase.
206  *
207  * @testname    name of a single selected test or NULL
208  * @phase       test phase
209  * @steps       steps to execute (mask with bits from EFI_ST_...)
210  * failures     returns EFI_ST_SUCCESS if all test steps succeeded
211  */
212 void efi_st_do_tests(const u16 *testname, unsigned int phase,
213                      unsigned int steps, unsigned int *failures)
214 {
215         int i = 0;
216         struct efi_unit_test *test;
217
218         for (test = ll_entry_start(struct efi_unit_test, efi_unit_test);
219              test < ll_entry_end(struct efi_unit_test, efi_unit_test);
220              ++test, ++i) {
221                 if (testname ?
222                     efi_st_strcmp_16_8(testname, test->name) : test->on_request)
223                         continue;
224                 if (test->phase != phase)
225                         continue;
226                 if (steps & EFI_ST_SETUP)
227                         setup_status[i] = setup(test, failures);
228                 if (steps & EFI_ST_EXECUTE && setup_status[i] == EFI_ST_SUCCESS)
229                         execute(test, failures);
230                 if (steps & EFI_ST_TEARDOWN)
231                         teardown(test, failures);
232         }
233 }
234
235 /*
236  * Execute selftest of the EFI API
237  *
238  * This is the main entry point of the EFI selftest application.
239  *
240  * All tests use a driver model and are run in three phases:
241  * setup, execute, teardown.
242  *
243  * A test may be setup and executed at boottime,
244  * it may be setup at boottime and executed at runtime,
245  * or it may be setup and executed at runtime.
246  *
247  * After executing all tests the system is reset.
248  *
249  * @image_handle:       handle of the loaded EFI image
250  * @systab:             EFI system table
251  */
252 efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle,
253                                  struct efi_system_table *systab)
254 {
255         unsigned int failures = 0;
256         const u16 *testname = NULL;
257         struct efi_loaded_image *loaded_image;
258         efi_status_t ret;
259
260         systable = systab;
261         boottime = systable->boottime;
262         runtime = systable->runtime;
263         handle = image_handle;
264         con_out = systable->con_out;
265         con_in = systable->con_in;
266
267         ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image,
268                                         (void **)&loaded_image);
269         if (ret != EFI_SUCCESS) {
270                 efi_st_error("Cannot open loaded image protocol\n");
271                 return ret;
272         }
273
274         if (loaded_image->load_options)
275                 testname = (u16 *)loaded_image->load_options;
276
277         if (testname) {
278                 if (!efi_st_strcmp_16_8(testname, "list") ||
279                     !find_test(testname)) {
280                         list_all_tests();
281                         /*
282                          * TODO:
283                          * Once the Exit boottime service is correctly
284                          * implemented we should call
285                          *   boottime->exit(image_handle, EFI_SUCCESS, 0, NULL);
286                          * here, cf.
287                          * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html
288                          */
289                         return EFI_SUCCESS;
290                 }
291         }
292
293         efi_st_printc(EFI_WHITE, "\nTesting EFI API implementation\n");
294
295         if (testname)
296                 efi_st_printc(EFI_WHITE, "\nSelected test: '%ps'\n", testname);
297         else
298                 efi_st_printc(EFI_WHITE, "\nNumber of tests to execute: %u\n",
299                               ll_entry_count(struct efi_unit_test,
300                                              efi_unit_test));
301
302         /* Allocate buffer for setup results */
303         ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) *
304                                       ll_entry_count(struct efi_unit_test,
305                                                      efi_unit_test),
306                                       (void **)&setup_status);
307         if (ret != EFI_SUCCESS) {
308                 efi_st_error("Allocate pool failed\n");
309                 return ret;
310         }
311
312         /* Execute boottime tests */
313         efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
314                         EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
315                         &failures);
316
317         if (!need_reset(testname)) {
318                 if (failures)
319                         ret = EFI_PROTOCOL_ERROR;
320
321                 /* Give feedback */
322                 efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n",
323                               failures);
324                 return ret;
325         }
326
327         /* Execute mixed tests */
328         efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
329                         EFI_ST_SETUP, &failures);
330
331         efi_st_exit_boot_services();
332
333         efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT,
334                         EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures);
335
336         /* Execute runtime tests */
337         efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT,
338                         EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN,
339                         &failures);
340
341         /* Give feedback */
342         efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures);
343
344         /* Reset system */
345         efi_st_printf("Preparing for reset. Press any key...\n");
346         efi_st_get_key();
347
348         if (IS_ENABLED(CONFIG_EFI_HAVE_RUNTIME_RESET)) {
349                 runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY,
350                                       sizeof(reset_message), reset_message);
351         } else {
352                 efi_restore_gd();
353                 do_reset(NULL, 0, 0, NULL);
354         }
355
356         efi_st_printf("\n");
357         efi_st_error("Reset failed\n");
358
359         return EFI_UNSUPPORTED;
360 }