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 17const struct efi_system_table *st_systable; 18const struct efi_boot_services *st_boottime; 19static const struct efi_runtime_services *runtime; 20static efi_handle_t handle; 21static u16 reset_message[] = u"Selftest completed"; 22static 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 */ 32void 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 = st_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 = 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"); 57 return; 58 } 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"); 63 return; 64 } 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"); 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 */ 80static 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, st_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 */ 105static 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 */ 130static 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 */ 154static 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_SETTING_VIRTUAL_ADDRESS_MAP) 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 */ 175static 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 */ 191static 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 */ 212void 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 st_boottime, 244 * it may be setup at st_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 */ 252efi_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 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; 266 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"); 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 st_boottime service is correctly 284 * implemented we should call 285 * st_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 = st_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 st_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 efi_st_do_tests(testname, EFI_SETTING_VIRTUAL_ADDRESS_MAP, 331 EFI_ST_SETUP, &failures); 332 333 efi_st_exit_boot_services(); 334 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, 340 &failures); 341 342 /* Give feedback */ 343 efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures); 344 345 /* Reset system */ 346 efi_st_printf("Preparing for reset. Press any key...\n"); 347 efi_st_get_key(); 348 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); 352 } else { 353 efi_restore_gd(); 354 do_reset(NULL, 0, 0, NULL); 355 } 356 357 efi_st_printf("\n"); 358 efi_st_error("Reset failed\n"); 359 360 return EFI_UNSUPPORTED; 361} 362