1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
9 #include <efi_selftest.h>
12 /* Constants for test step bitmap */
13 #define EFI_ST_SETUP 1
14 #define EFI_ST_EXECUTE 2
15 #define EFI_ST_TEARDOWN 4
17 const struct efi_system_table
*st_systable
;
18 const struct efi_boot_services
*st_boottime
;
19 static const struct efi_runtime_services
*runtime
;
20 static efi_handle_t handle
;
21 static u16 reset_message
[] = u
"Selftest completed";
22 static int *setup_status
;
25 * Exit the boot services.
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.
32 void efi_st_exit_boot_services(void)
34 efi_uintn_t map_size
= 0;
36 efi_uintn_t desc_size
;
39 struct efi_mem_desc
*memory_map
;
41 /* Do not detach devices in ExitBootServices. We need the console. */
42 efi_st_keep_devices
= true;
44 ret
= st_boottime
->get_memory_map(&map_size
, NULL
, &map_key
, &desc_size
,
46 if (ret
!= EFI_BUFFER_TOO_SMALL
) {
48 "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n");
51 /* Allocate extra space for newly allocated memory */
52 map_size
+= sizeof(struct efi_mem_desc
);
53 ret
= st_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");
59 ret
= st_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");
65 ret
= st_boottime
->exit_boot_services(handle
, map_key
);
66 if (ret
!= EFI_SUCCESS
) {
67 efi_st_error("ExitBootServices did not return EFI_SUCCESS\n");
70 efi_st_printc(EFI_WHITE
, "\nBoot services terminated\n");
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
80 static int setup(struct efi_unit_test
*test
, unsigned int *failures
)
85 return EFI_ST_SUCCESS
;
86 efi_st_printc(EFI_LIGHTBLUE
, "\nSetting up '%s'\n", test
->name
);
87 ret
= test
->setup(handle
, st_systable
);
88 if (ret
!= EFI_ST_SUCCESS
) {
89 efi_st_error("Setting up '%s' failed\n", test
->name
);
92 efi_st_printc(EFI_LIGHTGREEN
,
93 "Setting up '%s' succeeded\n", test
->name
);
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
105 static int execute(struct efi_unit_test
*test
, unsigned int *failures
)
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
);
117 efi_st_printc(EFI_LIGHTGREEN
,
118 "Executing '%s' succeeded\n", test
->name
);
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
130 static int teardown(struct efi_unit_test
*test
, unsigned int *failures
)
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
);
142 efi_st_printc(EFI_LIGHTGREEN
,
143 "Tearing down '%s' succeeded\n", test
->name
);
149 * Check that a test requiring reset exists.
151 * @testname: name of the test
152 * Return: test, or NULL if not found
154 static bool need_reset(const u16
*testname
)
156 struct efi_unit_test
*test
;
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
))
162 if (test
->phase
== EFI_SETUP_BEFORE_BOOTTIME_EXIT
||
163 test
->phase
== EFI_SETTING_VIRTUAL_ADDRESS_MAP
)
170 * Check that a test exists.
172 * @testname: name of the test
173 * Return: test, or NULL if not found
175 static struct efi_unit_test
*find_test(const u16
*testname
)
177 struct efi_unit_test
*test
;
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
))
184 efi_st_printf("\nTest '%ps' not found\n", testname
);
189 * List all available tests.
191 static void list_all_tests(void)
193 struct efi_unit_test
*test
;
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" : "");
205 * Execute test steps of one phase.
207 * @testname name of a single selected test or NULL
209 * @steps steps to execute (mask with bits from EFI_ST_...)
210 * failures returns EFI_ST_SUCCESS if all test steps succeeded
212 void efi_st_do_tests(const u16
*testname
, unsigned int phase
,
213 unsigned int steps
, unsigned int *failures
)
216 struct efi_unit_test
*test
;
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
);
222 efi_st_strcmp_16_8(testname
, test
->name
) : test
->on_request
)
224 if (test
->phase
!= phase
)
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
);
236 * Execute selftest of the EFI API
238 * This is the main entry point of the EFI selftest application.
240 * All tests use a driver model and are run in three phases:
241 * setup, execute, teardown.
243 * A test may be setup and executed at st_boottime,
244 * it may be setup at st_boottime and executed at runtime,
245 * or it may be setup and executed at runtime.
247 * After executing all tests the system is reset.
249 * @image_handle: handle of the loaded EFI image
250 * @systab: EFI system table
252 efi_status_t EFIAPI
efi_selftest(efi_handle_t image_handle
,
253 struct efi_system_table
*systab
)
255 unsigned int failures
= 0;
256 const u16
*testname
= NULL
;
257 struct efi_loaded_image
*loaded_image
;
260 st_systable
= systab
;
261 st_boottime
= st_systable
->boottime
;
262 runtime
= st_systable
->runtime
;
263 handle
= image_handle
;
264 con_out
= st_systable
->con_out
;
265 con_in
= st_systable
->con_in
;
267 ret
= st_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");
274 if (loaded_image
->load_options
)
275 testname
= (u16
*)loaded_image
->load_options
;
278 if (!efi_st_strcmp_16_8(testname
, "list") ||
279 !find_test(testname
)) {
283 * Once the Exit st_boottime service is correctly
284 * implemented we should call
285 * st_boottime->exit(image_handle, EFI_SUCCESS, 0, NULL);
287 * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html
293 efi_st_printc(EFI_WHITE
, "\nTesting EFI API implementation\n");
296 efi_st_printc(EFI_WHITE
, "\nSelected test: '%ps'\n", testname
);
298 efi_st_printc(EFI_WHITE
, "\nNumber of tests to execute: %u\n",
299 ll_entry_count(struct efi_unit_test
,
302 /* Allocate buffer for setup results */
303 ret
= st_boottime
->allocate_pool(EFI_RUNTIME_SERVICES_DATA
, sizeof(int) *
304 ll_entry_count(struct efi_unit_test
,
306 (void **)&setup_status
);
307 if (ret
!= EFI_SUCCESS
) {
308 efi_st_error("Allocate pool failed\n");
312 /* Execute st_boottime tests */
313 efi_st_do_tests(testname
, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT
,
314 EFI_ST_SETUP
| EFI_ST_EXECUTE
| EFI_ST_TEARDOWN
,
317 if (!need_reset(testname
)) {
319 ret
= EFI_PROTOCOL_ERROR
;
322 efi_st_printc(EFI_WHITE
, "\nSummary: %u failures\n\n",
327 /* Execute mixed tests */
328 efi_st_do_tests(testname
, EFI_SETUP_BEFORE_BOOTTIME_EXIT
,
329 EFI_ST_SETUP
, &failures
);
330 efi_st_do_tests(testname
, EFI_SETTING_VIRTUAL_ADDRESS_MAP
,
331 EFI_ST_SETUP
, &failures
);
333 efi_st_exit_boot_services();
335 efi_st_do_tests(testname
, EFI_SETUP_BEFORE_BOOTTIME_EXIT
,
336 EFI_ST_EXECUTE
| EFI_ST_TEARDOWN
, &failures
);
337 /* Execute test setting the virtual address map */
338 efi_st_do_tests(testname
, EFI_SETTING_VIRTUAL_ADDRESS_MAP
,
339 EFI_ST_EXECUTE
| EFI_ST_TEARDOWN
,
343 efi_st_printc(EFI_WHITE
, "\nSummary: %u failures\n\n", failures
);
346 efi_st_printf("Preparing for reset. Press any key...\n");
349 if (IS_ENABLED(CONFIG_EFI_HAVE_RUNTIME_RESET
)) {
350 runtime
->reset_system(EFI_RESET_WARM
, EFI_NOT_READY
,
351 sizeof(reset_message
), reset_message
);
354 do_reset(NULL
, 0, 0, NULL
);
358 efi_st_error("Reset failed\n");
360 return EFI_UNSUPPORTED
;