1623b3a57SHeinrich Schuchardt /* 2623b3a57SHeinrich Schuchardt * EFI efi_selftest 3623b3a57SHeinrich Schuchardt * 4623b3a57SHeinrich Schuchardt * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 5623b3a57SHeinrich Schuchardt * 6623b3a57SHeinrich Schuchardt * SPDX-License-Identifier: GPL-2.0+ 7623b3a57SHeinrich Schuchardt */ 8623b3a57SHeinrich Schuchardt 9623b3a57SHeinrich Schuchardt #include <efi_selftest.h> 10623b3a57SHeinrich Schuchardt #include <vsprintf.h> 11623b3a57SHeinrich Schuchardt 121f66a12eSHeinrich Schuchardt /* 131f66a12eSHeinrich Schuchardt * Constants for test step bitmap 141f66a12eSHeinrich Schuchardt */ 151f66a12eSHeinrich Schuchardt #define EFI_ST_SETUP 1 161f66a12eSHeinrich Schuchardt #define EFI_ST_EXECUTE 2 171f66a12eSHeinrich Schuchardt #define EFI_ST_TEARDOWN 4 181f66a12eSHeinrich Schuchardt 19623b3a57SHeinrich Schuchardt static const struct efi_system_table *systable; 20623b3a57SHeinrich Schuchardt static const struct efi_boot_services *boottime; 21623b3a57SHeinrich Schuchardt static const struct efi_runtime_services *runtime; 22623b3a57SHeinrich Schuchardt static efi_handle_t handle; 23623b3a57SHeinrich Schuchardt static u16 reset_message[] = L"Selftest completed"; 24623b3a57SHeinrich Schuchardt 25623b3a57SHeinrich Schuchardt /* 26623b3a57SHeinrich Schuchardt * Exit the boot services. 27623b3a57SHeinrich Schuchardt * 28623b3a57SHeinrich Schuchardt * The size of the memory map is determined. 29623b3a57SHeinrich Schuchardt * Pool memory is allocated to copy the memory map. 30623b3a57SHeinrich Schuchardt * The memory amp is copied and the map key is obtained. 31623b3a57SHeinrich Schuchardt * The map key is used to exit the boot services. 32623b3a57SHeinrich Schuchardt */ 33623b3a57SHeinrich Schuchardt void efi_st_exit_boot_services(void) 34623b3a57SHeinrich Schuchardt { 35623b3a57SHeinrich Schuchardt unsigned long map_size = 0; 36623b3a57SHeinrich Schuchardt unsigned long map_key; 37623b3a57SHeinrich Schuchardt unsigned long desc_size; 38623b3a57SHeinrich Schuchardt u32 desc_version; 39623b3a57SHeinrich Schuchardt efi_status_t ret; 40623b3a57SHeinrich Schuchardt struct efi_mem_desc *memory_map; 41623b3a57SHeinrich Schuchardt 42623b3a57SHeinrich Schuchardt ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, 43623b3a57SHeinrich Schuchardt &desc_version); 44623b3a57SHeinrich Schuchardt if (ret != EFI_BUFFER_TOO_SMALL) { 45037ee6f9SHeinrich Schuchardt efi_st_error( 46037ee6f9SHeinrich Schuchardt "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); 47623b3a57SHeinrich Schuchardt return; 48623b3a57SHeinrich Schuchardt } 49623b3a57SHeinrich Schuchardt /* Allocate extra space for newly allocated memory */ 50623b3a57SHeinrich Schuchardt map_size += sizeof(struct efi_mem_desc); 51623b3a57SHeinrich Schuchardt ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, 52623b3a57SHeinrich Schuchardt (void **)&memory_map); 53623b3a57SHeinrich Schuchardt if (ret != EFI_SUCCESS) { 54037ee6f9SHeinrich Schuchardt efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); 55623b3a57SHeinrich Schuchardt return; 56623b3a57SHeinrich Schuchardt } 57623b3a57SHeinrich Schuchardt ret = boottime->get_memory_map(&map_size, memory_map, &map_key, 58623b3a57SHeinrich Schuchardt &desc_size, &desc_version); 59623b3a57SHeinrich Schuchardt if (ret != EFI_SUCCESS) { 60037ee6f9SHeinrich Schuchardt efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); 61623b3a57SHeinrich Schuchardt return; 62623b3a57SHeinrich Schuchardt } 63623b3a57SHeinrich Schuchardt ret = boottime->exit_boot_services(handle, map_key); 64623b3a57SHeinrich Schuchardt if (ret != EFI_SUCCESS) { 65037ee6f9SHeinrich Schuchardt efi_st_error("ExitBootServices did not return EFI_SUCCESS\n"); 66623b3a57SHeinrich Schuchardt return; 67623b3a57SHeinrich Schuchardt } 68623b3a57SHeinrich Schuchardt efi_st_printf("\nBoot services terminated\n"); 69623b3a57SHeinrich Schuchardt } 70623b3a57SHeinrich Schuchardt 71623b3a57SHeinrich Schuchardt /* 72623b3a57SHeinrich Schuchardt * Set up a test. 73623b3a57SHeinrich Schuchardt * 74623b3a57SHeinrich Schuchardt * @test the test to be executed 75623b3a57SHeinrich Schuchardt * @failures counter that will be incremented if a failure occurs 76e67e7249SHeinrich Schuchardt * @return EFI_ST_SUCCESS for success 77623b3a57SHeinrich Schuchardt */ 78623b3a57SHeinrich Schuchardt static int setup(struct efi_unit_test *test, unsigned int *failures) 79623b3a57SHeinrich Schuchardt { 80623b3a57SHeinrich Schuchardt int ret; 81623b3a57SHeinrich Schuchardt 82623b3a57SHeinrich Schuchardt if (!test->setup) 83e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 84623b3a57SHeinrich Schuchardt efi_st_printf("\nSetting up '%s'\n", test->name); 85623b3a57SHeinrich Schuchardt ret = test->setup(handle, systable); 86e67e7249SHeinrich Schuchardt if (ret != EFI_ST_SUCCESS) { 87037ee6f9SHeinrich Schuchardt efi_st_error("Setting up '%s' failed\n", test->name); 88623b3a57SHeinrich Schuchardt ++*failures; 89623b3a57SHeinrich Schuchardt } else { 90623b3a57SHeinrich Schuchardt efi_st_printf("Setting up '%s' succeeded\n", test->name); 91623b3a57SHeinrich Schuchardt } 92623b3a57SHeinrich Schuchardt return ret; 93623b3a57SHeinrich Schuchardt } 94623b3a57SHeinrich Schuchardt 95623b3a57SHeinrich Schuchardt /* 96623b3a57SHeinrich Schuchardt * Execute a test. 97623b3a57SHeinrich Schuchardt * 98623b3a57SHeinrich Schuchardt * @test the test to be executed 99623b3a57SHeinrich Schuchardt * @failures counter that will be incremented if a failure occurs 100e67e7249SHeinrich Schuchardt * @return EFI_ST_SUCCESS for success 101623b3a57SHeinrich Schuchardt */ 102623b3a57SHeinrich Schuchardt static int execute(struct efi_unit_test *test, unsigned int *failures) 103623b3a57SHeinrich Schuchardt { 104623b3a57SHeinrich Schuchardt int ret; 105623b3a57SHeinrich Schuchardt 106623b3a57SHeinrich Schuchardt if (!test->execute) 107e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 108623b3a57SHeinrich Schuchardt efi_st_printf("\nExecuting '%s'\n", test->name); 109623b3a57SHeinrich Schuchardt ret = test->execute(); 110e67e7249SHeinrich Schuchardt if (ret != EFI_ST_SUCCESS) { 111037ee6f9SHeinrich Schuchardt efi_st_error("Executing '%s' failed\n", test->name); 112623b3a57SHeinrich Schuchardt ++*failures; 113623b3a57SHeinrich Schuchardt } else { 114623b3a57SHeinrich Schuchardt efi_st_printf("Executing '%s' succeeded\n", test->name); 115623b3a57SHeinrich Schuchardt } 116623b3a57SHeinrich Schuchardt return ret; 117623b3a57SHeinrich Schuchardt } 118623b3a57SHeinrich Schuchardt 119623b3a57SHeinrich Schuchardt /* 120623b3a57SHeinrich Schuchardt * Tear down a test. 121623b3a57SHeinrich Schuchardt * 122623b3a57SHeinrich Schuchardt * @test the test to be torn down 123623b3a57SHeinrich Schuchardt * @failures counter that will be incremented if a failure occurs 124e67e7249SHeinrich Schuchardt * @return EFI_ST_SUCCESS for success 125623b3a57SHeinrich Schuchardt */ 126623b3a57SHeinrich Schuchardt static int teardown(struct efi_unit_test *test, unsigned int *failures) 127623b3a57SHeinrich Schuchardt { 128623b3a57SHeinrich Schuchardt int ret; 129623b3a57SHeinrich Schuchardt 130623b3a57SHeinrich Schuchardt if (!test->teardown) 131e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 132623b3a57SHeinrich Schuchardt efi_st_printf("\nTearing down '%s'\n", test->name); 133623b3a57SHeinrich Schuchardt ret = test->teardown(); 134e67e7249SHeinrich Schuchardt if (ret != EFI_ST_SUCCESS) { 135037ee6f9SHeinrich Schuchardt efi_st_error("Tearing down '%s' failed\n", test->name); 136623b3a57SHeinrich Schuchardt ++*failures; 137623b3a57SHeinrich Schuchardt } else { 138623b3a57SHeinrich Schuchardt efi_st_printf("Tearing down '%s' succeeded\n", test->name); 139623b3a57SHeinrich Schuchardt } 140623b3a57SHeinrich Schuchardt return ret; 141623b3a57SHeinrich Schuchardt } 142623b3a57SHeinrich Schuchardt 143623b3a57SHeinrich Schuchardt /* 144*d78e40d6SHeinrich Schuchardt * Check that a test exists. 1451f66a12eSHeinrich Schuchardt * 146*d78e40d6SHeinrich Schuchardt * @testname: name of the test 147*d78e40d6SHeinrich Schuchardt * @return: test 1481f66a12eSHeinrich Schuchardt */ 149*d78e40d6SHeinrich Schuchardt static struct efi_unit_test *find_test(const u16 *testname) 1501f66a12eSHeinrich Schuchardt { 1511f66a12eSHeinrich Schuchardt struct efi_unit_test *test; 1521f66a12eSHeinrich Schuchardt 1531f66a12eSHeinrich Schuchardt for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 1541f66a12eSHeinrich Schuchardt test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 155*d78e40d6SHeinrich Schuchardt if (!efi_st_strcmp_16_8(testname, test->name)) 156*d78e40d6SHeinrich Schuchardt return test; 157*d78e40d6SHeinrich Schuchardt } 158*d78e40d6SHeinrich Schuchardt efi_st_printf("\nTest '%ps' not found\n", testname); 159*d78e40d6SHeinrich Schuchardt return NULL; 160*d78e40d6SHeinrich Schuchardt } 161*d78e40d6SHeinrich Schuchardt 162*d78e40d6SHeinrich Schuchardt /* 163*d78e40d6SHeinrich Schuchardt * List all available tests. 164*d78e40d6SHeinrich Schuchardt */ 165*d78e40d6SHeinrich Schuchardt static void list_all_tests(void) 166*d78e40d6SHeinrich Schuchardt { 167*d78e40d6SHeinrich Schuchardt struct efi_unit_test *test; 168*d78e40d6SHeinrich Schuchardt 169*d78e40d6SHeinrich Schuchardt /* List all tests */ 170*d78e40d6SHeinrich Schuchardt efi_st_printf("\nAvailable tests:\n"); 171*d78e40d6SHeinrich Schuchardt for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 172*d78e40d6SHeinrich Schuchardt test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 173*d78e40d6SHeinrich Schuchardt efi_st_printf("'%s'%s\n", test->name, 174*d78e40d6SHeinrich Schuchardt test->on_request ? " - on request" : ""); 175*d78e40d6SHeinrich Schuchardt } 176*d78e40d6SHeinrich Schuchardt } 177*d78e40d6SHeinrich Schuchardt 178*d78e40d6SHeinrich Schuchardt /* 179*d78e40d6SHeinrich Schuchardt * Execute test steps of one phase. 180*d78e40d6SHeinrich Schuchardt * 181*d78e40d6SHeinrich Schuchardt * @testname name of a single selected test or NULL 182*d78e40d6SHeinrich Schuchardt * @phase test phase 183*d78e40d6SHeinrich Schuchardt * @steps steps to execute 184*d78e40d6SHeinrich Schuchardt * failures returns EFI_ST_SUCCESS if all test steps succeeded 185*d78e40d6SHeinrich Schuchardt */ 186*d78e40d6SHeinrich Schuchardt void efi_st_do_tests(const u16 *testname, unsigned int phase, 187*d78e40d6SHeinrich Schuchardt unsigned int steps, unsigned int *failures) 188*d78e40d6SHeinrich Schuchardt { 189*d78e40d6SHeinrich Schuchardt struct efi_unit_test *test; 190*d78e40d6SHeinrich Schuchardt 191*d78e40d6SHeinrich Schuchardt for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); 192*d78e40d6SHeinrich Schuchardt test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { 193*d78e40d6SHeinrich Schuchardt if (testname ? 194*d78e40d6SHeinrich Schuchardt efi_st_strcmp_16_8(testname, test->name) : test->on_request) 195*d78e40d6SHeinrich Schuchardt continue; 1961f66a12eSHeinrich Schuchardt if (test->phase != phase) 1971f66a12eSHeinrich Schuchardt continue; 1981f66a12eSHeinrich Schuchardt if (steps & EFI_ST_SETUP) 1991f66a12eSHeinrich Schuchardt setup(test, failures); 2001f66a12eSHeinrich Schuchardt if (steps & EFI_ST_EXECUTE) 2011f66a12eSHeinrich Schuchardt execute(test, failures); 2021f66a12eSHeinrich Schuchardt if (steps & EFI_ST_TEARDOWN) 2031f66a12eSHeinrich Schuchardt teardown(test, failures); 2041f66a12eSHeinrich Schuchardt } 2051f66a12eSHeinrich Schuchardt } 2061f66a12eSHeinrich Schuchardt 2071f66a12eSHeinrich Schuchardt /* 208623b3a57SHeinrich Schuchardt * Execute selftest of the EFI API 209623b3a57SHeinrich Schuchardt * 210623b3a57SHeinrich Schuchardt * This is the main entry point of the EFI selftest application. 211623b3a57SHeinrich Schuchardt * 212623b3a57SHeinrich Schuchardt * All tests use a driver model and are run in three phases: 213623b3a57SHeinrich Schuchardt * setup, execute, teardown. 214623b3a57SHeinrich Schuchardt * 215623b3a57SHeinrich Schuchardt * A test may be setup and executed at boottime, 216623b3a57SHeinrich Schuchardt * it may be setup at boottime and executed at runtime, 217623b3a57SHeinrich Schuchardt * or it may be setup and executed at runtime. 218623b3a57SHeinrich Schuchardt * 219623b3a57SHeinrich Schuchardt * After executing all tests the system is reset. 220623b3a57SHeinrich Schuchardt * 221623b3a57SHeinrich Schuchardt * @image_handle: handle of the loaded EFI image 222623b3a57SHeinrich Schuchardt * @systab: EFI system table 223623b3a57SHeinrich Schuchardt */ 224623b3a57SHeinrich Schuchardt efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, 225623b3a57SHeinrich Schuchardt struct efi_system_table *systab) 226623b3a57SHeinrich Schuchardt { 227623b3a57SHeinrich Schuchardt unsigned int failures = 0; 228*d78e40d6SHeinrich Schuchardt const u16 *testname = NULL; 229*d78e40d6SHeinrich Schuchardt struct efi_loaded_image *loaded_image; 230*d78e40d6SHeinrich Schuchardt efi_status_t ret; 231623b3a57SHeinrich Schuchardt 232623b3a57SHeinrich Schuchardt systable = systab; 233623b3a57SHeinrich Schuchardt boottime = systable->boottime; 234623b3a57SHeinrich Schuchardt runtime = systable->runtime; 235623b3a57SHeinrich Schuchardt handle = image_handle; 236623b3a57SHeinrich Schuchardt con_out = systable->con_out; 237623b3a57SHeinrich Schuchardt con_in = systable->con_in; 238623b3a57SHeinrich Schuchardt 239*d78e40d6SHeinrich Schuchardt ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, 240*d78e40d6SHeinrich Schuchardt (void **)&loaded_image); 241*d78e40d6SHeinrich Schuchardt if (ret != EFI_SUCCESS) { 242*d78e40d6SHeinrich Schuchardt efi_st_error("Cannot open loaded image protocol"); 243*d78e40d6SHeinrich Schuchardt return ret; 244*d78e40d6SHeinrich Schuchardt } 245*d78e40d6SHeinrich Schuchardt 246*d78e40d6SHeinrich Schuchardt if (loaded_image->load_options) 247*d78e40d6SHeinrich Schuchardt testname = (u16 *)loaded_image->load_options; 248*d78e40d6SHeinrich Schuchardt 249*d78e40d6SHeinrich Schuchardt if (testname) { 250*d78e40d6SHeinrich Schuchardt if (!efi_st_strcmp_16_8(testname, "list") || 251*d78e40d6SHeinrich Schuchardt !find_test(testname)) { 252*d78e40d6SHeinrich Schuchardt list_all_tests(); 253*d78e40d6SHeinrich Schuchardt /* 254*d78e40d6SHeinrich Schuchardt * TODO: 255*d78e40d6SHeinrich Schuchardt * Once the Exit boottime service is correctly 256*d78e40d6SHeinrich Schuchardt * implemented we should call 257*d78e40d6SHeinrich Schuchardt * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); 258*d78e40d6SHeinrich Schuchardt * here, cf. 259*d78e40d6SHeinrich Schuchardt * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html 260*d78e40d6SHeinrich Schuchardt */ 261*d78e40d6SHeinrich Schuchardt return EFI_SUCCESS; 262*d78e40d6SHeinrich Schuchardt } 263*d78e40d6SHeinrich Schuchardt } 264*d78e40d6SHeinrich Schuchardt 265623b3a57SHeinrich Schuchardt efi_st_printf("\nTesting EFI API implementation\n"); 266623b3a57SHeinrich Schuchardt 267*d78e40d6SHeinrich Schuchardt if (testname) 268*d78e40d6SHeinrich Schuchardt efi_st_printf("\nSelected test: '%ps'\n", testname); 269*d78e40d6SHeinrich Schuchardt else 270623b3a57SHeinrich Schuchardt efi_st_printf("\nNumber of tests to execute: %u\n", 271*d78e40d6SHeinrich Schuchardt ll_entry_count(struct efi_unit_test, 272*d78e40d6SHeinrich Schuchardt efi_unit_test)); 273623b3a57SHeinrich Schuchardt 274623b3a57SHeinrich Schuchardt /* Execute boottime tests */ 275*d78e40d6SHeinrich Schuchardt efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 2761f66a12eSHeinrich Schuchardt EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, 2771f66a12eSHeinrich Schuchardt &failures); 278623b3a57SHeinrich Schuchardt 279623b3a57SHeinrich Schuchardt /* Execute mixed tests */ 280*d78e40d6SHeinrich Schuchardt efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, 2811f66a12eSHeinrich Schuchardt EFI_ST_SETUP, &failures); 282623b3a57SHeinrich Schuchardt 283623b3a57SHeinrich Schuchardt efi_st_exit_boot_services(); 284623b3a57SHeinrich Schuchardt 285*d78e40d6SHeinrich Schuchardt efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, 2861f66a12eSHeinrich Schuchardt EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); 287623b3a57SHeinrich Schuchardt 288623b3a57SHeinrich Schuchardt /* Execute runtime tests */ 289*d78e40d6SHeinrich Schuchardt efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT, 2901f66a12eSHeinrich Schuchardt EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, 2911f66a12eSHeinrich Schuchardt &failures); 292623b3a57SHeinrich Schuchardt 293623b3a57SHeinrich Schuchardt /* Give feedback */ 294623b3a57SHeinrich Schuchardt efi_st_printf("\nSummary: %u failures\n\n", failures); 295623b3a57SHeinrich Schuchardt 296623b3a57SHeinrich Schuchardt /* Reset system */ 297623b3a57SHeinrich Schuchardt efi_st_printf("Preparing for reset. Press any key.\n"); 298623b3a57SHeinrich Schuchardt efi_st_get_key(); 299623b3a57SHeinrich Schuchardt runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, 300623b3a57SHeinrich Schuchardt sizeof(reset_message), reset_message); 301037ee6f9SHeinrich Schuchardt efi_st_printf("\n"); 302037ee6f9SHeinrich Schuchardt efi_st_error("Reset failed.\n"); 303623b3a57SHeinrich Schuchardt 304623b3a57SHeinrich Schuchardt return EFI_UNSUPPORTED; 305623b3a57SHeinrich Schuchardt } 306