From d78e40d651972ef061c960e4b7da7843383c2ec9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:13 +0200 Subject: efi_selftest: allow to select a single test for execution Environment variable efi_selftest is passed as load options to the selftest application. It is used to select a single test to be executed. The load options are an UTF8 string. Yet I decided to keep the name propertiy of the tests as char[] to reduce code size. Special value 'list' displays a list of all available tests. Tests get an on_request property. If this property is set the tests are only executed if explicitly requested. The invocation of efi_selftest is changed to reflect that bootefi selftest with efi_selftest = 'list' will call the Exit bootservice. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 88 ++++++++++++++++++++++++++++++--- lib/efi_selftest/efi_selftest_console.c | 10 ++++ lib/efi_selftest/efi_selftest_util.c | 9 ++++ 3 files changed, 99 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 73f074d9e1..b6bc4dd5c0 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -140,20 +140,59 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures) return ret; } +/* + * Check that a test exists. + * + * @testname: name of the test + * @return: test + */ +static struct efi_unit_test *find_test(const u16 *testname) +{ + struct efi_unit_test *test; + + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (!efi_st_strcmp_16_8(testname, test->name)) + return test; + } + efi_st_printf("\nTest '%ps' not found\n", testname); + return NULL; +} + +/* + * List all available tests. + */ +static void list_all_tests(void) +{ + struct efi_unit_test *test; + + /* List all tests */ + efi_st_printf("\nAvailable tests:\n"); + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + efi_st_printf("'%s'%s\n", test->name, + test->on_request ? " - on request" : ""); + } +} + /* * Execute test steps of one phase. * + * @testname name of a single selected test or NULL * @phase test phase * @steps steps to execute * failures returns EFI_ST_SUCCESS if all test steps succeeded */ -void efi_st_do_tests(unsigned int phase, unsigned int steps, - unsigned int *failures) +void efi_st_do_tests(const u16 *testname, unsigned int phase, + unsigned int steps, unsigned int *failures) { struct efi_unit_test *test; for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (testname ? + efi_st_strcmp_16_8(testname, test->name) : test->on_request) + continue; if (test->phase != phase) continue; if (steps & EFI_ST_SETUP) @@ -186,6 +225,9 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, struct efi_system_table *systab) { unsigned int failures = 0; + const u16 *testname = NULL; + struct efi_loaded_image *loaded_image; + efi_status_t ret; systable = systab; boottime = systable->boottime; @@ -194,27 +236,57 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, con_out = systable->con_out; con_in = systable->con_in; + ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, + (void **)&loaded_image); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot open loaded image protocol"); + return ret; + } + + if (loaded_image->load_options) + testname = (u16 *)loaded_image->load_options; + + if (testname) { + if (!efi_st_strcmp_16_8(testname, "list") || + !find_test(testname)) { + list_all_tests(); + /* + * TODO: + * Once the Exit boottime service is correctly + * implemented we should call + * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); + * here, cf. + * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html + */ + return EFI_SUCCESS; + } + } + efi_st_printf("\nTesting EFI API implementation\n"); - efi_st_printf("\nNumber of tests to execute: %u\n", - ll_entry_count(struct efi_unit_test, efi_unit_test)); + if (testname) + efi_st_printf("\nSelected test: '%ps'\n", testname); + else + efi_st_printf("\nNumber of tests to execute: %u\n", + ll_entry_count(struct efi_unit_test, + efi_unit_test)); /* Execute boottime tests */ - efi_st_do_tests(EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); /* Execute mixed tests */ - efi_st_do_tests(EFI_SETUP_BEFORE_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP, &failures); efi_st_exit_boot_services(); - efi_st_do_tests(EFI_SETUP_BEFORE_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); /* Execute runtime tests */ - efi_st_do_tests(EFI_SETUP_AFTER_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index 840e2290c6..6a7fd20da5 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -142,6 +142,7 @@ void efi_st_printf(const char *fmt, ...) const char *c; u16 *pos = buf; const char *s; + const u16 *u; va_start(args, fmt); @@ -179,9 +180,18 @@ void efi_st_printf(const char *fmt, ...) case 'p': ++c; switch (*c) { + /* MAC address */ case 'm': mac(va_arg(args, void*), &pos); break; + + /* u16 string */ + case 's': + u = va_arg(args, u16*); + /* Ensure string fits into buffer */ + for (; *u && pos < buf + 120; ++u) + *pos++ = *u; + break; default: --c; pointer(va_arg(args, void*), &pos); diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c index 5f81f251c4..1b17bf4d4b 100644 --- a/lib/efi_selftest/efi_selftest_util.c +++ b/lib/efi_selftest/efi_selftest_util.c @@ -23,3 +23,12 @@ int efi_st_memcmp(const void *buf1, const void *buf2, size_t length) } return 0; } + +int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2) +{ + for (; *buf1 || *buf2; ++buf1, ++buf2) { + if (*buf1 != *buf2) + return *buf1 - *buf2; + } + return 0; +} -- cgit