summaryrefslogtreecommitdiff
path: root/lib/efi_selftest
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_selftest')
-rw-r--r--lib/efi_selftest/Kconfig2
-rw-r--r--lib/efi_selftest/Makefile5
-rw-r--r--lib/efi_selftest/efi_selftest_controllers.c35
-rw-r--r--lib/efi_selftest/efi_selftest_manageprotocols.c2
-rw-r--r--lib/efi_selftest/efi_selftest_textoutput.c78
-rw-r--r--lib/efi_selftest/efi_selftest_unaligned.c67
-rw-r--r--lib/efi_selftest/efi_selftest_variables.c196
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,
+};