diff options
Diffstat (limited to 'lib/efi_selftest')
-rw-r--r-- | lib/efi_selftest/Kconfig | 2 | ||||
-rw-r--r-- | lib/efi_selftest/Makefile | 5 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_controllers.c | 35 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_manageprotocols.c | 2 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_textoutput.c | 78 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_unaligned.c | 67 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_variables.c | 196 |
7 files changed, 381 insertions, 4 deletions
diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig index 3b5f3a1230..59f9f36801 100644 --- a/lib/efi_selftest/Kconfig +++ b/lib/efi_selftest/Kconfig @@ -1,6 +1,8 @@ config CMD_BOOTEFI_SELFTEST bool "Allow booting an EFI efi_selftest" depends on CMD_BOOTEFI + imply FAT + imply FAT_WRITE help This adds an EFI test application to U-Boot that can be executed with the 'bootefi selftest' command. It provides extended tests of diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 80c4302645..4fe404d88d 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -28,8 +28,13 @@ efi_selftest_textinput.o \ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ efi_selftest_util.o \ +efi_selftest_variables.o \ efi_selftest_watchdog.o +ifeq ($(CONFIG_CMD_BOOTEFI_SELFTEST),y) +obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o +endif + ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy) obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest_block_device.o endif diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c index e30c11b1e4..ceefa03444 100644 --- a/lib/efi_selftest/efi_selftest_controllers.c +++ b/lib/efi_selftest/efi_selftest_controllers.c @@ -6,7 +6,7 @@ * * This unit test checks the following protocol services: * ConnectController, DisconnectController, - * InstallProtocol, UninstallProtocol, + * InstallProtocol, ReinstallProtocol, UninstallProtocol, * OpenProtocol, CloseProtcol, OpenProtocolInformation */ @@ -14,6 +14,8 @@ #define NUMBER_OF_CHILD_CONTROLLERS 4 +static int interface1 = 1; +static int interface2 = 2; static struct efi_boot_services *boottime; const efi_guid_t guid_driver_binding_protocol = EFI_DRIVER_BINDING_PROTOCOL_GUID; @@ -271,7 +273,7 @@ static int setup(const efi_handle_t img_handle, /* Create controller handle */ ret = boottime->install_protocol_interface( &handle_controller, &guid_controller, - EFI_NATIVE_INTERFACE, NULL); + EFI_NATIVE_INTERFACE, &interface1); if (ret != EFI_SUCCESS) { efi_st_error("InstallProtocolInterface failed\n"); return EFI_ST_FAILURE; @@ -299,6 +301,7 @@ static int setup(const efi_handle_t img_handle, * Disconnect and destroy the remaining child controllers. * * Connect a controller to a driver. + * Reinstall the driver protocol on the controller. * Uninstall the driver protocol from the controller. */ static int execute(void) @@ -361,9 +364,35 @@ static int execute(void) efi_st_error("Number of children %u != %u\n", (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); } + /* Try to uninstall controller protocol using the wrong interface */ + ret = boottime->uninstall_protocol_interface(handle_controller, + &guid_controller, + &interface2); + if (ret == EFI_SUCCESS) { + efi_st_error( + "Interface not checked when uninstalling protocol\n"); + return EFI_ST_FAILURE; + } + /* Reinstall controller protocol */ + ret = boottime->reinstall_protocol_interface(handle_controller, + &guid_controller, + &interface1, + &interface2); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to reinstall protocols\n"); + return EFI_ST_FAILURE; + } + /* Check number of child controllers */ + ret = count_child_controllers(handle_controller, &guid_controller, + &count); + if (ret != EFI_SUCCESS || count != NUMBER_OF_CHILD_CONTROLLERS) { + efi_st_error("Number of children %u != %u\n", + (unsigned int)count, NUMBER_OF_CHILD_CONTROLLERS); + } /* Uninstall controller protocol */ ret = boottime->uninstall_protocol_interface(handle_controller, - &guid_controller, NULL); + &guid_controller, + &interface2); if (ret != EFI_SUCCESS) { efi_st_error("Failed to uninstall protocols\n"); return EFI_ST_FAILURE; diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c index 3e4755c25e..44b8da3ba5 100644 --- a/lib/efi_selftest/efi_selftest_manageprotocols.c +++ b/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -335,7 +335,7 @@ static int execute(void) return EFI_ST_FAILURE; } ret = boottime->uninstall_protocol_interface(handle1, &guid3, - &interface1); + &interface3); if (ret != EFI_SUCCESS) { efi_st_error("UninstallProtocolInterface failed\n"); return EFI_ST_FAILURE; diff --git a/lib/efi_selftest/efi_selftest_textoutput.c b/lib/efi_selftest/efi_selftest_textoutput.c index 3533647fd4..a87f65e197 100644 --- a/lib/efi_selftest/efi_selftest_textoutput.c +++ b/lib/efi_selftest/efi_selftest_textoutput.c @@ -23,6 +23,13 @@ static int execute(void) size_t background; size_t attrib; efi_status_t ret; + s16 col; + u16 cr[] = { 0x0d, 0x00 }; + u16 lf[] = { 0x0a, 0x00 }; + u16 brahmi[] = { /* 2 Brahmi letters */ + 0xD804, 0xDC05, + 0xD804, 0xDC22, + 0}; /* SetAttribute */ efi_st_printf("\nColor palette\n"); @@ -42,6 +49,77 @@ static int execute(void) efi_st_error("TestString failed for ANSI characters\n"); return EFI_ST_FAILURE; } + /* OutputString */ + ret = con_out->output_string(con_out, + L"Testing cursor column update\n"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for ANSI characters"); + return EFI_ST_FAILURE; + } + col = con_out->mode->cursor_column; + ret = con_out->output_string(con_out, lf); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for line feed\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column != col) { + efi_st_error("Cursor column changed by line feed\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, cr); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for carriage return\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column) { + efi_st_error("Cursor column not 0 at beginning of line\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"123"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for ANSI characters\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column != 3) { + efi_st_error("Cursor column not incremented properly\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"\b"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for backspace\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column != 2) { + efi_st_error("Cursor column not decremented properly\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"\b\b"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for backspace\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column) { + efi_st_error("Cursor column not decremented properly\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, L"\b\b"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("OutputString failed for backspace\n"); + return EFI_ST_FAILURE; + } + if (con_out->mode->cursor_column) { + efi_st_error("Cursor column decremented past zero\n"); + return EFI_ST_FAILURE; + } + ret = con_out->output_string(con_out, brahmi); + if (ret != EFI_ST_SUCCESS) { + efi_st_todo("Unicode output not fully supported\n"); + } else if (con_out->mode->cursor_column != 2) { + efi_st_printf("Unicode not handled properly\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("\n"); + return EFI_ST_SUCCESS; } diff --git a/lib/efi_selftest/efi_selftest_unaligned.c b/lib/efi_selftest/efi_selftest_unaligned.c new file mode 100644 index 0000000000..f799c6dd0f --- /dev/null +++ b/lib/efi_selftest/efi_selftest_unaligned.c @@ -0,0 +1,67 @@ +/* + * efi_selftest_unaligned + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Test unaligned memory access on ARMv7. + */ + +#include <efi_selftest.h> + +struct aligned_buffer { + char a[8] __aligned(8); +}; + +/* + * Return an u32 at a give address. + * If the address is not four byte aligned, an unaligned memory access + * occurs. + * + * @addr: address to read + * @return: value at the address + */ +static inline u32 deref(u32 *addr) +{ + int ret; + + asm( + "ldr %[out], [%[in]]\n\t" + : [out] "=r" (ret) + : [in] "r" (addr) + ); + return ret; +} + +/* + * Execute unit test. + * An unaligned memory access is executed. The result is checked. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct aligned_buffer buf = { + {0, 1, 2, 3, 4, 5, 6, 7}, + }; + void *v = &buf; + u32 r = 0; + + /* Read an unaligned address */ + r = deref(v + 1); + + /* UEFI only supports low endian systems */ + if (r != 0x04030201) { + efi_st_error("Unaligned access failed"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(unaligned) = { + .name = "unaligned memory access", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, +}; diff --git a/lib/efi_selftest/efi_selftest_variables.c b/lib/efi_selftest/efi_selftest_variables.c new file mode 100644 index 0000000000..146378fb9a --- /dev/null +++ b/lib/efi_selftest/efi_selftest_variables.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_variables + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks the following protocol services: + * ConnectController, DisconnectController, + * InstallProtocol, ReinstallProtocol, UninstallProtocol, + * OpenProtocol, CloseProtcol, OpenProtocolInformation + */ + +#include <efi_selftest.h> + +#define EFI_ST_MAX_DATA_SIZE 16 +#define EFI_ST_MAX_VARNAME_SIZE 40 + +static struct efi_boot_services *boottime; +static struct efi_runtime_services *runtime; +static efi_guid_t guid_vendor0 = + EFI_GUID(0x67029eb5, 0x0af2, 0xf6b1, + 0xda, 0x53, 0xfc, 0xb5, 0x66, 0xdd, 0x1c, 0xe6); +static efi_guid_t guid_vendor1 = + EFI_GUID(0xff629290, 0x1fc1, 0xd73f, + 0x8f, 0xb1, 0x32, 0xf9, 0x0c, 0xa0, 0x42, 0xea); + +/* + * Setup unit test. + * + * @handle handle of the loaded image + * @systable system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + runtime = systable->runtime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + */ +static int execute(void) +{ + efi_status_t ret; + efi_uintn_t len; + u32 attr; + u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c, + 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,}; + u8 data[EFI_ST_MAX_DATA_SIZE]; + u16 varname[EFI_ST_MAX_VARNAME_SIZE]; + int flag; + efi_guid_t guid; + u64 max_storage, rem_storage, max_size; + + ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS, + &max_storage, &rem_storage, + &max_size); + if (ret != EFI_SUCCESS) { + efi_st_todo("QueryVariableInfo failed\n"); + } else if (!max_storage || !rem_storage || !max_size) { + efi_st_error("QueryVariableInfo: wrong info\n"); + return EFI_ST_FAILURE; + } + /* Set variable 0 */ + ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 3, v + 4); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + data[3] = 0xff; + len = 3; + ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + if (efi_st_memcmp(data, v + 4, 3)) { + efi_st_error("GetVariable returned wrong value\n"); + return EFI_ST_FAILURE; + } + if (data[3] != 0xff) { + efi_st_error("GetVariable wrote past the end of the buffer\n"); + return EFI_ST_FAILURE; + } + /* Set variable 1 */ + ret = runtime->set_variable(L"efi_st_var1", &guid_vendor1, + EFI_VARIABLE_BOOTSERVICE_ACCESS, + 8, v); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + if (len != 8) { + efi_st_error("GetVariable returned wrong length %u\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + if (efi_st_memcmp(data, v, 8)) { + efi_st_error("GetVariable returned wrong value\n"); + return EFI_ST_FAILURE; + } + /* Append variable 1 */ + ret = runtime->set_variable(L"efi_st_var1", &guid_vendor1, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_APPEND_WRITE, + 7, v + 8); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + if (len != 15) + efi_st_todo("GetVariable returned wrong length %u\n", + (unsigned int)len); + if (efi_st_memcmp(data, v, len)) + efi_st_todo("GetVariable returned wrong value\n"); + /* Enumerate variables */ + boottime->set_mem(&guid, 16, 0); + *varname = 0; + flag = 0; + for (;;) { + len = EFI_ST_MAX_VARNAME_SIZE; + ret = runtime->get_next_variable_name(&len, varname, &guid); + if (ret == EFI_NOT_FOUND) + break; + if (ret != EFI_SUCCESS) { + efi_st_todo("GetNextVariableName failed\n"); + break; + } + if (!efi_st_memcmp(&guid, &guid_vendor0, sizeof(efi_guid_t)) && + !efi_st_strcmp_16_8(varname, "efi_st_var0")) + flag |= 2; + if (!efi_st_memcmp(&guid, &guid_vendor1, sizeof(efi_guid_t)) && + !efi_st_strcmp_16_8(varname, "efi_st_var1")) + flag |= 2; + } + if (flag != 3) + efi_st_todo( + "GetNextVariableName did not return all variables\n"); + /* Delete variable 1 */ + ret = runtime->set_variable(L"efi_st_var1", &guid_vendor1, + 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1, + &attr, &len, data); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Variable was not deleted\n"); + return EFI_ST_FAILURE; + } + /* Delete variable 0 */ + ret = runtime->set_variable(L"efi_st_var0", &guid_vendor0, + 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = EFI_ST_MAX_DATA_SIZE; + ret = runtime->get_variable(L"efi_st_var0", &guid_vendor0, + &attr, &len, data); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Variable was not deleted\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(variables) = { + .name = "variables", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; |