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 <efi_selftest.h> 9 #include <vsprintf.h> 10 11 /* 12 * Constants for test step bitmap 13 */ 14 #define EFI_ST_SETUP 1 15 #define EFI_ST_EXECUTE 2 16 #define EFI_ST_TEARDOWN 4 17 18 static const struct efi_system_table *systable; 19 static const struct efi_boot_services *boottime; 20 static const struct efi_runtime_services *runtime; 21 static efi_handle_t handle; 22 static u16 reset_message[] = L"Selftest completed"; 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 amp 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 ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, 42 &desc_version); 43 if (ret != EFI_BUFFER_TOO_SMALL) { 44 efi_st_error( 45 "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); 46 return; 47 } 48 /* Allocate extra space for newly allocated memory */ 49 map_size += sizeof(struct efi_mem_desc); 50 ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, 51 (void **)&memory_map); 52 if (ret != EFI_SUCCESS) { 53 efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); 54 return; 55 } 56 ret = boottime->get_memory_map(&map_size, memory_map, &map_key, 57 &desc_size, &desc_version); 58 if (ret != EFI_SUCCESS) { 59 efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); 60 return; 61 } 62 ret = boottime->exit_boot_services(handle, map_key); 63 if (ret != EFI_SUCCESS) { 64 efi_st_error("ExitBootServices did not return EFI_SUCCESS\n"); 65 return; 66 } 67 efi_st_printc(EFI_WHITE, "\nBoot services terminated\n"); 68 } 69 70 /* 71 * Set up a test. 72 * 73 * @test the test to be executed 74 * @failures counter that will be incremented if a failure occurs 75 * @return EFI_ST_SUCCESS for success 76 */ 77 static int setup(struct efi_unit_test *test, unsigned int *failures) 78 { 79 if (!test->setup) { 80 test->setup_ok = EFI_ST_SUCCESS; 81 return EFI_ST_SUCCESS; 82 } 83 efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); 84 test->setup_ok = test->setup(handle, systable); 85 if (test->setup_ok != EFI_ST_SUCCESS) { 86 efi_st_error("Setting up '%s' failed\n", test->name); 87 ++*failures; 88 } else { 89 efi_st_printc(EFI_LIGHTGREEN, 90 "Setting up '%s' succeeded\n", test->name); 91 } 92 return test->setup_ok; 93 } 94 95 /* 96 * Execute a test. 97 * 98 * @test the test to be executed 99 * @failures counter that will be incremented if a failure occurs 100 * @return EFI_ST_SUCCESS for success 101 */ 102 static int execute(struct efi_unit_test *test, unsigned int *failures) 103 { 104 int ret; 105 106 if (!test->execute) 107 return EFI_ST_SUCCESS; 108 efi_st_printc(EFI_LIGHTBLUE, "\nExecuting '%s'\n", test->name); 109 ret = test->execute(); 110 if (ret != EFI_ST_SUCCESS) { 111 efi_st_error("Executing '%s' failed\n", test->name); 112 ++*failures; 113 } else { 114 efi_st_printc(EFI_LIGHTGREEN, 115 "Executing '%s' succeeded\n", test->name); 116 } 117 return ret; 118 } 119 120 /* 121 * Tear down a test. 122 * 123 * @test the test to be torn down 124 * @failures counter that will be incremented if a failure occurs 125 * @return EFI_ST_SUCCESS for success 126 */ 127 static int teardown(struct efi_unit_test *test, unsigned int *failures) 128 { 129 int ret; 130 131 if (!test->teardown) 132 return EFI_ST_SUCCESS; 133 efi_st_printc(EFI_LIGHTBLUE, "\nTearing down '%s'\n", test->name); 134 ret = test->teardown(); 135 if (ret != EFI_ST_SUCCESS) { 136 efi_st_error("Tearing down '%s' failed\n", test->name); 137 ++*failures; 138 } else { 139 efi_st_printc(EFI_LIGHTGREEN, 140 "Tearing down '%s' succeeded\n", test->name); 141 } 142 return ret; 143 } 144 145 /* 146 * Check that a test exists. 147 * 148 * @testname: name of the test 149 * @return: test 150 */ 151 static struct efi_unit_test *find_test(const u16 *testname) 152 { 153 struct efi_unit_test *test; 154 155 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 156 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 157 if (!efi_st_strcmp_16_8(testname, test->name)) 158 return test; 159 } 160 efi_st_printf("\nTest '%ps' not found\n", testname); 161 return NULL; 162 } 163 164 /* 165 * List all available tests. 166 */ 167 static void list_all_tests(void) 168 { 169 struct efi_unit_test *test; 170 171 /* List all tests */ 172 efi_st_printf("\nAvailable tests:\n"); 173 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 174 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 175 efi_st_printf("'%s'%s\n", test->name, 176 test->on_request ? " - on request" : ""); 177 } 178 } 179 180 /* 181 * Execute test steps of one phase. 182 * 183 * @testname name of a single selected test or NULL 184 * @phase test phase 185 * @steps steps to execute 186 * failures returns EFI_ST_SUCCESS if all test steps succeeded 187 */ 188 void efi_st_do_tests(const u16 *testname, unsigned int phase, 189 unsigned int steps, unsigned int *failures) 190 { 191 struct efi_unit_test *test; 192 193 for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 194 test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 195 if (testname ? 196 efi_st_strcmp_16_8(testname, test->name) : test->on_request) 197 continue; 198 if (test->phase != phase) 199 continue; 200 if (steps & EFI_ST_SETUP) 201 setup(test, failures); 202 if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS) 203 execute(test, failures); 204 if (steps & EFI_ST_TEARDOWN) 205 teardown(test, failures); 206 } 207 } 208 209 /* 210 * Execute selftest of the EFI API 211 * 212 * This is the main entry point of the EFI selftest application. 213 * 214 * All tests use a driver model and are run in three phases: 215 * setup, execute, teardown. 216 * 217 * A test may be setup and executed at boottime, 218 * it may be setup at boottime and executed at runtime, 219 * or it may be setup and executed at runtime. 220 * 221 * After executing all tests the system is reset. 222 * 223 * @image_handle: handle of the loaded EFI image 224 * @systab: EFI system table 225 */ 226 efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, 227 struct efi_system_table *systab) 228 { 229 unsigned int failures = 0; 230 const u16 *testname = NULL; 231 struct efi_loaded_image *loaded_image; 232 efi_status_t ret; 233 234 systable = systab; 235 boottime = systable->boottime; 236 runtime = systable->runtime; 237 handle = image_handle; 238 con_out = systable->con_out; 239 con_in = systable->con_in; 240 241 ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, 242 (void **)&loaded_image); 243 if (ret != EFI_SUCCESS) { 244 efi_st_error("Cannot open loaded image protocol\n"); 245 return ret; 246 } 247 248 if (loaded_image->load_options) 249 testname = (u16 *)loaded_image->load_options; 250 251 if (testname) { 252 if (!efi_st_strcmp_16_8(testname, "list") || 253 !find_test(testname)) { 254 list_all_tests(); 255 /* 256 * TODO: 257 * Once the Exit boottime service is correctly 258 * implemented we should call 259 * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); 260 * here, cf. 261 * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html 262 */ 263 return EFI_SUCCESS; 264 } 265 } 266 267 efi_st_printc(EFI_WHITE, "\nTesting EFI API implementation\n"); 268 269 if (testname) 270 efi_st_printc(EFI_WHITE, "\nSelected test: '%ps'\n", testname); 271 else 272 efi_st_printc(EFI_WHITE, "\nNumber of tests to execute: %u\n", 273 ll_entry_count(struct efi_unit_test, 274 efi_unit_test)); 275 276 /* Execute boottime tests */ 277 efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 278 EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, 279 &failures); 280 281 /* Execute mixed tests */ 282 efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, 283 EFI_ST_SETUP, &failures); 284 285 efi_st_exit_boot_services(); 286 287 efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, 288 EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); 289 290 /* Execute runtime tests */ 291 efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT, 292 EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, 293 &failures); 294 295 /* Give feedback */ 296 efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures); 297 298 /* Reset system */ 299 efi_st_printf("Preparing for reset. Press any key.\n"); 300 efi_st_get_key(); 301 runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, 302 sizeof(reset_message), reset_message); 303 efi_st_printf("\n"); 304 efi_st_error("Reset failed.\n"); 305 306 return EFI_UNSUPPORTED; 307 } 308