diff options
Diffstat (limited to 'lib/efi_selftest')
-rw-r--r-- | lib/efi_selftest/Makefile | 5 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest.c | 14 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_bitblt.c | 311 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_block_device.c | 24 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_devicepath.c | 2 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_devicepath_util.c | 286 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_disk_image.h | 58 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_event_groups.c | 140 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_fdt.c | 188 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_textinput.c | 182 |
10 files changed, 1165 insertions, 45 deletions
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index c4bdbdf6c0..0e4980c8a0 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,14 +14,19 @@ CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ +efi_selftest_bitblt.o \ efi_selftest_controllers.o \ efi_selftest_console.o \ efi_selftest_devicepath.o \ +efi_selftest_devicepath_util.o \ efi_selftest_events.o \ +efi_selftest_event_groups.o \ efi_selftest_exitbootservices.o \ +efi_selftest_fdt.o \ efi_selftest_gop.o \ efi_selftest_manageprotocols.o \ efi_selftest_snp.o \ +efi_selftest_textinput.o \ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ efi_selftest_util.o \ diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index fc5ef254a1..fd4fee726f 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -77,20 +77,20 @@ void efi_st_exit_boot_services(void) */ static int setup(struct efi_unit_test *test, unsigned int *failures) { - int ret; - - if (!test->setup) + if (!test->setup) { + test->setup_ok = EFI_ST_SUCCESS; return EFI_ST_SUCCESS; + } efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); - ret = test->setup(handle, systable); - if (ret != EFI_ST_SUCCESS) { + test->setup_ok = test->setup(handle, systable); + if (test->setup_ok != EFI_ST_SUCCESS) { efi_st_error("Setting up '%s' failed\n", test->name); ++*failures; } else { efi_st_printc(EFI_LIGHTGREEN, "Setting up '%s' succeeded\n", test->name); } - return ret; + return test->setup_ok; } /* @@ -200,7 +200,7 @@ void efi_st_do_tests(const u16 *testname, unsigned int phase, continue; if (steps & EFI_ST_SETUP) setup(test, failures); - if (steps & EFI_ST_EXECUTE) + if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS) execute(test, failures); if (steps & EFI_ST_TEARDOWN) teardown(test, failures); diff --git a/lib/efi_selftest/efi_selftest_bitblt.c b/lib/efi_selftest/efi_selftest_bitblt.c new file mode 100644 index 0000000000..0fb76cc727 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_bitblt.c @@ -0,0 +1,311 @@ +/* + * efi_selftest_bitblt + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Test the block image transfer in the graphical output protocol. + * An animated submarine is shown. + */ + +#include <efi_selftest.h> + +#define WIDTH 200 +#define HEIGHT 120 +#define DEPTH 60 + +static const struct efi_gop_pixel BLACK = { 0, 0, 0, 0}; +static const struct efi_gop_pixel RED = { 0, 0, 255, 0}; +static const struct efi_gop_pixel ORANGE = { 0, 128, 255, 0}; +static const struct efi_gop_pixel YELLOW = { 0, 255, 255, 0}; +static const struct efi_gop_pixel GREEN = { 0, 255, 0, 0}; +static const struct efi_gop_pixel DARK_BLUE = {128, 0, 0, 0}; +static const struct efi_gop_pixel LIGHT_BLUE = {255, 192, 192, 0}; + +static struct efi_boot_services *boottime; +static efi_guid_t efi_gop_guid = EFI_GOP_GUID; +static struct efi_gop *gop; +static struct efi_gop_pixel *bitmap; +static struct efi_event *event; +static efi_uintn_t xpos; + +static void ellipse(efi_uintn_t x, efi_uintn_t y, + efi_uintn_t x0, efi_uintn_t y0, + efi_uintn_t x1, efi_uintn_t y1, + const struct efi_gop_pixel col, struct efi_gop_pixel *pix) +{ + efi_uintn_t xm = x0 + x1; + efi_uintn_t ym = y0 + y1; + efi_uintn_t dx = x1 - x0 + 1; + efi_uintn_t dy = y1 - y0 + 1; + + if (dy * dy * (2 * x - xm) * (2 * x - xm) + + dx * dx * (2 * y - ym) * (2 * y - ym) <= dx * dx * dy * dy) + *pix = col; +} + +static void rectangle(efi_uintn_t x, efi_uintn_t y, + efi_uintn_t x0, efi_uintn_t y0, + efi_uintn_t x1, efi_uintn_t y1, + const struct efi_gop_pixel col, struct efi_gop_pixel *pix) +{ + if (x >= x0 && y >= y0 && x <= x1 && y <= y1) + *pix = col; +} + +/* + * Notification function, copies image to video. + * The position is incremented in each call. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + efi_uintn_t *pos = context; + efi_uintn_t dx, sx, width; + + if (!pos) + return; + + /* Increment position */ + *pos += 5; + if (*pos >= WIDTH + gop->mode->info->width) + *pos = 0; + + width = WIDTH; + dx = *pos - WIDTH; + sx = 0; + if (*pos >= gop->mode->info->width) { + width = WIDTH + gop->mode->info->width - *pos; + } else if (*pos < WIDTH) { + dx = 0; + sx = WIDTH - *pos; + width = *pos; + } + + /* Copy image to video */ + gop->blt(gop, bitmap, EFI_BLT_BUFFER_TO_VIDEO, sx, 0, dx, DEPTH, + width, HEIGHT, WIDTH * sizeof(struct efi_gop_pixel)); +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + struct efi_gop_pixel pix; + efi_uintn_t x, y; + + boottime = systable->boottime; + + /* Create event */ + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, (void *)&xpos, + &event); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + /* Get graphical output protocol */ + ret = boottime->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret != EFI_SUCCESS) { + gop = NULL; + efi_st_printf("Graphical output protocol is not available.\n"); + return EFI_ST_SUCCESS; + } + + /* Prepare image of submarine */ + ret = boottime->allocate_pool(EFI_LOADER_DATA, + sizeof(struct efi_gop_pixel) * + WIDTH * HEIGHT, (void **)&bitmap); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return EFI_ST_FAILURE; + } + for (y = 0; y < HEIGHT; ++y) { + for (x = 0; x < WIDTH; ++x) { + pix = DARK_BLUE; + + /* Propeller */ + ellipse(x, y, 35, 55, 43, 75, BLACK, &pix); + ellipse(x, y, 36, 56, 42, 74, LIGHT_BLUE, &pix); + + ellipse(x, y, 35, 75, 43, 95, BLACK, &pix); + ellipse(x, y, 36, 76, 42, 94, LIGHT_BLUE, &pix); + + /* Shaft */ + rectangle(x, y, 35, 73, 100, 77, BLACK, &pix); + + /* Periscope */ + ellipse(x, y, 120, 10, 160, 50, BLACK, &pix); + ellipse(x, y, 121, 11, 159, 59, YELLOW, &pix); + ellipse(x, y, 130, 20, 150, 40, BLACK, &pix); + ellipse(x, y, 131, 21, 149, 49, DARK_BLUE, &pix); + rectangle(x, y, 135, 10, 160, 50, DARK_BLUE, &pix); + ellipse(x, y, 132, 10, 138, 20, BLACK, &pix); + ellipse(x, y, 133, 11, 139, 19, RED, &pix); + + /* Rudder */ + ellipse(x, y, 45, 40, 75, 70, BLACK, &pix); + ellipse(x, y, 46, 41, 74, 69, ORANGE, &pix); + ellipse(x, y, 45, 80, 75, 109, BLACK, &pix); + ellipse(x, y, 46, 81, 74, 108, RED, &pix); + + /* Bridge */ + ellipse(x, y, 100, 30, 120, 50, BLACK, &pix); + ellipse(x, y, 101, 31, 119, 49, GREEN, &pix); + ellipse(x, y, 140, 30, 160, 50, BLACK, &pix); + ellipse(x, y, 141, 31, 159, 49, GREEN, &pix); + rectangle(x, y, 110, 30, 150, 50, BLACK, &pix); + rectangle(x, y, 110, 31, 150, 50, GREEN, &pix); + + /* Hull */ + ellipse(x, y, 50, 40, 199, 109, BLACK, &pix); + ellipse(x, y, 51, 41, 198, 108, LIGHT_BLUE, &pix); + + /* Port holes */ + ellipse(x, y, 79, 57, 109, 82, BLACK, &pix); + ellipse(x, y, 80, 58, 108, 81, LIGHT_BLUE, &pix); + ellipse(x, y, 83, 61, 105, 78, BLACK, &pix); + ellipse(x, y, 84, 62, 104, 77, YELLOW, &pix); + /* + * This port hole is created by copying + * ellipse(x, y, 119, 57, 149, 82, BLACK, &pix); + * ellipse(x, y, 120, 58, 148, 81, LIGHT_BLUE, &pix); + * ellipse(x, y, 123, 61, 145, 78, BLACK, &pix); + * ellipse(x, y, 124, 62, 144, 77, YELLOW, &pix); + */ + ellipse(x, y, 159, 57, 189, 82, BLACK, &pix); + ellipse(x, y, 160, 58, 188, 81, LIGHT_BLUE, &pix); + ellipse(x, y, 163, 61, 185, 78, BLACK, &pix); + ellipse(x, y, 164, 62, 184, 77, YELLOW, &pix); + + bitmap[WIDTH * y + x] = pix; + } + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + if (bitmap) { + ret = boottime->free_pool(bitmap); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + if (event) { + ret = boottime->close_event(event); + event = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("could not close event\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u32 max_mode; + efi_status_t ret; + struct efi_gop_mode_info *info; + + if (!gop) + return EFI_ST_SUCCESS; + + if (!gop->mode) { + efi_st_error("EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE missing\n"); + return EFI_ST_FAILURE; + } + info = gop->mode->info; + max_mode = gop->mode->max_mode; + if (!max_mode) { + efi_st_error("No graphical mode available\n"); + return EFI_ST_FAILURE; + } + + /* Fill background */ + ret = gop->blt(gop, bitmap, EFI_BLT_VIDEO_FILL, 0, 0, 0, 0, + info->width, info->height, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_VIDEO_FILL failed\n"); + return EFI_ST_FAILURE; + } + + /* Copy image to video */ + ret = gop->blt(gop, bitmap, EFI_BLT_BUFFER_TO_VIDEO, 0, 0, 0, DEPTH, + WIDTH, HEIGHT, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_BUFFER_TO_VIDEO failed\n"); + return EFI_ST_FAILURE; + } + + /* Copy left port hole */ + ret = gop->blt(gop, bitmap, EFI_BLT_VIDEO_TO_VIDEO, + 79, 57 + DEPTH, 119, 57 + DEPTH, + 31, 26, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_VIDEO_TO_VIDEO failed\n"); + return EFI_ST_FAILURE; + } + + /* Copy port holes back to buffer */ + ret = gop->blt(gop, bitmap, EFI_BLT_VIDEO_TO_BLT_BUFFER, + 94, 57 + DEPTH, 94, 57, + 90, 26, WIDTH * sizeof(struct efi_gop_pixel)); + if (ret != EFI_SUCCESS) { + efi_st_error("EFI_BLT_VIDEO_TO_BLT_BUFFER failed\n"); + return EFI_ST_FAILURE; + } + + /* Set 250ms timer */ + xpos = WIDTH; + ret = boottime->set_timer(event, EFI_TIMER_PERIODIC, 250000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + + con_out->set_cursor_position(con_out, 0, 0); + con_out->set_attribute(con_out, EFI_WHITE | EFI_BACKGROUND_BLUE); + efi_st_printf("The submarine should have three yellow port holes.\n"); + efi_st_printf("Press any key to continue"); + efi_st_get_key(); + con_out->set_attribute(con_out, EFI_LIGHTGRAY); + efi_st_printf("\n"); + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(bitblt) = { + .name = "block image transfer", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, + .on_request = true, +}; diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c index 9e4b93d9a6..a8979ed56b 100644 --- a/lib/efi_selftest/efi_selftest_block_device.c +++ b/lib/efi_selftest/efi_selftest_block_device.c @@ -29,6 +29,7 @@ static const efi_guid_t block_io_protocol_guid = BLOCK_IO_GUID; static const efi_guid_t guid_device_path = DEVICE_PATH_GUID; static const efi_guid_t guid_simple_file_system_protocol = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t guid_file_system_info = EFI_FILE_SYSTEM_INFO_GUID; static efi_guid_t guid_vendor = EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xb7, 0xb8); @@ -302,7 +303,11 @@ static int execute(void) struct efi_device_path *dp_partition; struct efi_simple_file_system_protocol *file_system; struct efi_file_handle *root, *file; - u64 buf_size; + struct { + struct efi_file_system_info info; + u16 label[12]; + } system_info; + efi_uintn_t buf_size; char buf[16] __aligned(ARCH_DMA_MINALIGN); ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); @@ -356,6 +361,23 @@ static int execute(void) efi_st_error("Failed to open volume\n"); return EFI_ST_FAILURE; } + buf_size = sizeof(system_info); + ret = root->getinfo(root, &guid_file_system_info, &buf_size, + &system_info); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get file system info\n"); + return EFI_ST_FAILURE; + } + if (system_info.info.block_size != 512) { + efi_st_error("Wrong block size %u, expected 512\n", + system_info.info.block_size); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(system_info.info.volume_label, "U-BOOT TEST")) { + efi_st_todo( + "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", + system_info.info.volume_label); + } ret = root->open(root, &file, (s16 *)L"hello.txt", EFI_FILE_MODE_READ, 0); if (ret != EFI_SUCCESS) { diff --git a/lib/efi_selftest/efi_selftest_devicepath.c b/lib/efi_selftest/efi_selftest_devicepath.c index 92940c7ab6..da68102eb2 100644 --- a/lib/efi_selftest/efi_selftest_devicepath.c +++ b/lib/efi_selftest/efi_selftest_devicepath.c @@ -52,7 +52,7 @@ struct efi_device_path_to_text_protocol *device_path_to_text; * Setup unit test. * * Create three handles. Install a new protocol on two of them and - * provice device paths. + * provide device paths. * * handle1 * guid interface diff --git a/lib/efi_selftest/efi_selftest_devicepath_util.c b/lib/efi_selftest/efi_selftest_devicepath_util.c new file mode 100644 index 0000000000..2b5384f21b --- /dev/null +++ b/lib/efi_selftest/efi_selftest_devicepath_util.c @@ -0,0 +1,286 @@ +/* + * efi_selftest_devicepath_util + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test checks the device path utilities protocol. + */ + +#include <efi_selftest.h> + +static struct efi_boot_services *boottime; + +static efi_guid_t guid_device_path_utilities_protocol = + EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID; + +struct efi_device_path_utilities_protocol *dpu; + +/* + * Setup unit test. + * + * Locate the device path utilities protocol. + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + int ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&guid_device_path_utilities_protocol, + NULL, (void **)&dpu); + if (ret != EFI_SUCCESS) { + dpu = NULL; + efi_st_error( + "Device path to text protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Create a device path consisting of a single media device node followed by an + * end node. + * + * @length: length of the media device node + * @dp: device path + * @return: status code + */ +static int create_single_node_device_path(unsigned int length, + struct efi_device_path **dp) +{ + struct efi_device_path *node; + efi_uintn_t len; + int ret; + + node = dpu->create_device_node(DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, length); + if (!node) { + efi_st_error("CreateDeviceNode failed\n"); + return EFI_ST_FAILURE; + } + *dp = dpu->append_device_node(NULL, node); + if (!*dp) { + efi_st_error("AppendDeviceNode failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(node); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(*dp); + if (len != length + 4) { + efi_st_error("Wrong device path length %u, expected %u\n", + (unsigned int)len, length); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * In the test device paths are created, copied, and concatenated. The device + * path length is used as a measure of success. + */ +static int execute(void) +{ + struct efi_device_path *dp1; + struct efi_device_path *dp2; + struct efi_device_path *dp3; + + efi_uintn_t len; + int ret; + + /* IsDevicePathMultiInstance(NULL) */ + if (dpu->is_device_path_multi_instance(NULL)) { + efi_st_error("IsDevicePathMultiInstance(NULL) returned true\n"); + return EFI_ST_FAILURE; + } + /* GetDevicePathSize(NULL) */ + len = dpu->get_device_path_size(NULL); + if (len) { + efi_st_error("Wrong device path length %u, expected 0\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + /* DuplicateDevicePath(NULL) */ + dp1 = dpu->duplicate_device_path(NULL); + if (dp1) { + efi_st_error("DuplicateDevicePath(NULL) failed\n"); + return EFI_ST_FAILURE; + } + /* AppendDevicePath(NULL, NULL) */ + dp1 = dpu->append_device_path(NULL, NULL); + if (!dp1) { + efi_st_error("AppendDevicePath(NULL, NULL) failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + if (len != 4) { + efi_st_error("Wrong device path length %u, expected 4\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp1); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* CreateDeviceNode */ + ret = create_single_node_device_path(21, &dp1); + if (ret != EFI_ST_SUCCESS) + return ret; + ret = create_single_node_device_path(17, &dp2); + if (ret != EFI_ST_SUCCESS) + return ret; + /* AppendDevicePath */ + dp3 = dpu->append_device_path(dp1, dp2); + if (!dp3) { + efi_st_error("AppendDevicePath failed\n"); + return EFI_ST_FAILURE; + } + if (dp3 == dp1 || dp3 == dp2) { + efi_st_error("AppendDevicePath reused buffer\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp3); + /* 21 + 17 + 4 */ + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 42\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* AppendDeviceNode */ + dp2 = dpu->append_device_node(dp1, dp3); + if (!dp2) { + efi_st_error("AppendDevicePath failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp2); + /* 21 + 21 + 4 */ + if (len != 46) { + printf("%s(%d) %s\n", __FILE__, __LINE__, __func__); + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp1); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* IsDevicePathMultiInstance */ + if (dpu->is_device_path_multi_instance(dp2)) { + printf("%s(%d) %s\n", __FILE__, __LINE__, __func__); + efi_st_error("IsDevicePathMultiInstance returned true\n"); + return EFI_ST_FAILURE; + } + /* AppendDevicePathInstance */ + dp1 = dpu->append_device_path_instance(dp2, dp3); + if (!dp1) { + efi_st_error("AppendDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + /* 46 + 42 */ + if (len != 88) { + efi_st_error("Wrong device path length %u, expected 88\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + /* IsDevicePathMultiInstance */ + if (!dpu->is_device_path_multi_instance(dp1)) { + efi_st_error("IsDevicePathMultiInstance returned false\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp3); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + /* GetNextDevicePathInstance */ + dp3 = dp1; + dp2 = dpu->get_next_device_path_instance(&dp1, &len); + if (!dp2) { + efi_st_error("GetNextDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + if (!dp1) { + efi_st_error("GetNextDevicePathInstance no 2nd instance\n"); + return EFI_ST_FAILURE; + } + if (len != 46) { + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + len = dpu->get_device_path_size(dp1); + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 42\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + dp2 = dpu->get_next_device_path_instance(&dp1, &len); + if (!dp2) { + efi_st_error("GetNextDevicePathInstance failed\n"); + return EFI_ST_FAILURE; + } + if (len != 42) { + efi_st_error("Wrong device path length %u, expected 46\n", + (unsigned int)len); + return EFI_ST_FAILURE; + } + if (dp1) { + efi_st_error("GetNextDevicePathInstance did not signal end\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* Clean up */ + ret = boottime->free_pool(dp2); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(dp3); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(dputil) = { + .name = "device path utilities protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/lib/efi_selftest/efi_selftest_disk_image.h b/lib/efi_selftest/efi_selftest_disk_image.h index 4775dace70..9c741ce136 100644 --- a/lib/efi_selftest/efi_selftest_disk_image.h +++ b/lib/efi_selftest/efi_selftest_disk_image.h @@ -3,21 +3,21 @@ * * Generated with tools/file2include * - * SPDX-License-Identifier: GPL-2.0+ + * SPDX-License-Identifier: GPL-2.0+ */ #define EFI_ST_DISK_IMG { 0x00010000, { \ - {0x000001b8, "\x94\x37\x69\xfc\x00\x00\x00\x00"}, /* .7i..... */ \ - {0x000001c0, "\x02\x00\x83\x02\x02\x00\x01\x00"}, /* ........ */ \ + {0x000001b8, "\x21\x5d\x53\xd1\x00\x00\x00\x00"}, /* !]S..... */ \ + {0x000001c0, "\x02\x00\x01\x02\x02\x00\x01\x00"}, /* ........ */ \ {0x000001c8, "\x00\x00\x7f\x00\x00\x00\x00\x00"}, /* ........ */ \ {0x000001f8, "\x00\x00\x00\x00\x00\x00\x55\xaa"}, /* ......U. */ \ {0x00000200, "\xeb\x3c\x90\x6d\x6b\x66\x73\x2e"}, /* .<.mkfs. */ \ {0x00000208, "\x66\x61\x74\x00\x02\x04\x01\x00"}, /* fat..... */ \ {0x00000210, "\x02\x00\x02\x7f\x00\xf8\x01\x00"}, /* ........ */ \ {0x00000218, "\x20\x00\x40\x00\x00\x00\x00\x00"}, /* .@..... */ \ - {0x00000220, "\x00\x00\x00\x00\x80\x00\x29\x86"}, /* ......). */ \ - {0x00000228, "\xe8\x82\x80\x4e\x4f\x20\x4e\x41"}, /* ...NO NA */ \ - {0x00000230, "\x4d\x45\x20\x20\x20\x20\x46\x41"}, /* ME FA */ \ + {0x00000220, "\x00\x00\x00\x00\x80\x00\x29\xc4"}, /* ......). */ \ + {0x00000228, "\xc4\x88\x11\x55\x2d\x42\x4f\x4f"}, /* ...U-BOO */ \ + {0x00000230, "\x54\x20\x54\x45\x53\x54\x46\x41"}, /* T TESTFA */ \ {0x00000238, "\x54\x31\x32\x20\x20\x20\x0e\x1f"}, /* T12 .. */ \ {0x00000240, "\xbe\x5b\x7c\xac\x22\xc0\x74\x0b"}, /* .[|.".t. */ \ {0x00000248, "\x56\xb4\x0e\xbb\x07\x00\xcd\x10"}, /* V....... */ \ @@ -36,34 +36,20 @@ {0x000002b0, "\x72\x79\x20\x61\x67\x61\x69\x6e"}, /* ry again */ \ {0x000002b8, "\x20\x2e\x2e\x2e\x20\x0d\x0a\x00"}, /* ... ... */ \ {0x000003f8, "\x00\x00\x00\x00\x00\x00\x55\xaa"}, /* ......U. */ \ - {0x00000400, "\xf8\xff\xff\x00\x00\x00\x00\xf0"}, /* ........ */ \ - {0x00000408, "\xff\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \ - {0x00000600, "\xf8\xff\xff\x00\x00\x00\x00\xf0"}, /* ........ */ \ - {0x00000608, "\xff\x00\x00\x00\x00\x00\x00\x00"}, /* ........ */ \ - {0x00000800, "\xe5\x70\x00\x00\x00\xff\xff\xff"}, /* .p...... */ \ - {0x00000808, "\xff\xff\xff\x0f\x00\x0e\xff\xff"}, /* ........ */ \ - {0x00000810, "\xff\xff\xff\xff\xff\xff\xff\xff"}, /* ........ */ \ - {0x00000818, "\xff\xff\x00\x00\xff\xff\xff\xff"}, /* ........ */ \ - {0x00000820, "\xe5\x2e\x00\x68\x00\x65\x00\x6c"}, /* ...h.e.l */ \ - {0x00000828, "\x00\x6c\x00\x0f\x00\x0e\x6f\x00"}, /* .l....o. */ \ - {0x00000830, "\x2e\x00\x74\x00\x78\x00\x74\x00"}, /* ..t.x.t. */ \ - {0x00000838, "\x2e\x00\x00\x00\x73\x00\x77\x00"}, /* ....s.w. */ \ - {0x00000840, "\xe5\x45\x4c\x4c\x4f\x54\x7e\x31"}, /* .ELLOT~1 */ \ - {0x00000848, "\x53\x57\x50\x20\x00\x64\xd0\x8a"}, /* SWP .d.. */ \ - {0x00000850, "\x92\x4b\x92\x4b\x00\x00\xd0\x8a"}, /* .K.K.... */ \ - {0x00000858, "\x92\x4b\x00\x00\x00\x00\x00\x00"}, /* .K...... */ \ - {0x00000860, "\x41\x68\x00\x65\x00\x6c\x00\x6c"}, /* Ah.e.l.l */ \ - {0x00000868, "\x00\x6f\x00\x0f\x00\xf1\x2e\x00"}, /* .o...... */ \ - {0x00000870, "\x74\x00\x78\x00\x74\x00\x00\x00"}, /* t.x.t... */ \ - {0x00000878, "\xff\xff\x00\x00\xff\xff\xff\xff"}, /* ........ */ \ - {0x00000880, "\x48\x45\x4c\x4c\x4f\x20\x20\x20"}, /* HELLO */ \ - {0x00000888, "\x54\x58\x54\x20\x00\x64\xd4\x8a"}, /* TXT .d.. */ \ - {0x00000890, "\x92\x4b\x92\x4b\x00\x00\xd4\x8a"}, /* .K.K.... */ \ - {0x00000898, "\x92\x4b\x05\x00\x0d\x00\x00\x00"}, /* .K...... */ \ - {0x000008a0, "\xe5\x45\x4c\x4c\x4f\x54\x7e\x31"}, /* .ELLOT~1 */ \ - {0x000008a8, "\x53\x57\x58\x20\x00\x64\xd0\x8a"}, /* SWX .d.. */ \ - {0x000008b0, "\x92\x4b\x92\x4b\x00\x00\xd0\x8a"}, /* .K.K.... */ \ - {0x000008b8, "\x92\x4b\x00\x00\x00\x00\x00\x00"}, /* .K...... */ \ - {0x00006000, "\x48\x65\x6c\x6c\x6f\x20\x77\x6f"}, /* Hello wo */ \ - {0x00006008, "\x72\x6c\x64\x21\x0a\x00\x00\x00"}, /* rld!.... */ \ + {0x00000400, "\xf8\xff\xff\x00\xf0\xff\x00\x00"}, /* ........ */ \ + {0x00000600, "\xf8\xff\xff\x00\xf0\xff\x00\x00"}, /* ........ */ \ + {0x00000800, "\x55\x2d\x42\x4f\x4f\x54\x20\x54"}, /* U-BOOT T */ \ + {0x00000808, "\x45\x53\x54\x08\x00\x00\xaa\x56"}, /* EST....V */ \ + {0x00000810, "\x84\x4c\x84\x4c\x00\x00\xaa\x56"}, /* .L.L...V */ \ + {0x00000818, "\x84\x4c\x00\x00\x00\x00\x00\x00"}, /* .L...... */ \ + {0x00000820, "\x41\x68\x00\x65\x00\x6c\x00\x6c"}, /* Ah.e.l.l */ \ + {0x00000828, "\x00\x6f\x00\x0f\x00\xf1\x2e\x00"}, /* .o...... */ \ + {0x00000830, "\x74\x00\x78\x00\x74\x00\x00\x00"}, /* t.x.t... */ \ + {0x00000838, "\xff\xff\x00\x00\xff\xff\xff\xff"}, /* ........ */ \ + {0x00000840, "\x48\x45\x4c\x4c\x4f\x20\x20\x20"}, /* HELLO */ \ + {0x00000848, "\x54\x58\x54\x20\x00\x64\xd7\x46"}, /* TXT .d.F */ \ + {0x00000850, "\x84\x4c\x84\x4c\x00\x00\xd7\x46"}, /* .L.L...F */ \ + {0x00000858, "\x84\x4c\x03\x00\x0d\x00\x00\x00"}, /* .L...... */ \ + {0x00005000, "\x48\x65\x6c\x6c\x6f\x20\x77\x6f"}, /* Hello wo */ \ + {0x00005008, "\x72\x6c\x64\x21\x0a\x00\x00\x00"}, /* rld!.... */ \ {0, NULL} } } diff --git a/lib/efi_selftest/efi_selftest_event_groups.c b/lib/efi_selftest/efi_selftest_event_groups.c new file mode 100644 index 0000000000..79e4ea1ce2 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_event_groups.c @@ -0,0 +1,140 @@ +/* + * efi_selftest_event_groups + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This test checks the notification of group events and the + * following services: + * CreateEventEx, CloseEvent, SignalEvent, CheckEvent. + */ + +#include <efi_selftest.h> + +#define GROUP_SIZE 16 + +static struct efi_boot_services *boottime; +static efi_guid_t event_group = + EFI_GUID(0x2335905b, 0xc3b9, 0x4221, 0xa3, 0x71, + 0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91); + +/* + * Notification function, increments the notfication count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Create multiple events in an event group. Signal each event once and check + * that all events are notified once in each round. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + unsigned int counter[GROUP_SIZE] = {0}; + struct efi_event *events[GROUP_SIZE]; + size_t i, j; + efi_status_t ret; + + for (i = 0; i < GROUP_SIZE; ++i) { + ret = boottime->create_event_ex(0, TPL_NOTIFY, + notify, (void *)&counter[i], + &event_group, &events[i]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + } + + for (i = 0; i < GROUP_SIZE; ++i) { + ret = boottime->signal_event(events[i]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to signal event\n"); + return EFI_ST_FAILURE; + } + for (j = 0; j < GROUP_SIZE; ++j) { + if (counter[j] != i) { + efi_st_printf("i %u, j %u, count %u\n", + (unsigned int)i, (unsigned int)j, + (unsigned int)counter[j]); + efi_st_error( + "Notification function was called\n"); + return EFI_ST_FAILURE; + } + /* Clear signaled state */ + ret = boottime->check_event(events[j]); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled\n"); + return EFI_ST_FAILURE; + } + if (counter[j] != i) { + efi_st_printf("i %u, j %u, count %u\n", + (unsigned int)i, (unsigned int)j, + (unsigned int)counter[j]); + efi_st_error( + "Notification function was called\n"); + return EFI_ST_FAILURE; + } + /* Call notification function */ + ret = boottime->check_event(events[j]); + if (ret != EFI_NOT_READY) { + efi_st_error( + "Signaled state not cleared\n"); + return EFI_ST_FAILURE; + } + if (counter[j] != i + 1) { + efi_st_printf("i %u, j %u, count %u\n", + (unsigned int)i, (unsigned int)j, + (unsigned int)counter[j]); + efi_st_error( + "Nofification function not called\n"); + return EFI_ST_FAILURE; + } + } + } + + for (i = 0; i < GROUP_SIZE; ++i) { + ret = boottime->close_event(events[i]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event\n"); + return EFI_ST_FAILURE; + } + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(eventgoups) = { + .name = "event groups", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c new file mode 100644 index 0000000000..e5a8d6a6ae --- /dev/null +++ b/lib/efi_selftest/efi_selftest_fdt.c @@ -0,0 +1,188 @@ +/* + * efi_selftest_pos + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. + * + * The following services are tested: + * OutputString, TestString, SetAttribute. + */ + +#include <efi_selftest.h> +#include <linux/libfdt.h> + +static struct efi_boot_services *boottime; +static const char *fdt; + +/* This should be sufficent for */ +#define BUFFERSIZE 0x100000 + +static efi_guid_t fdt_guid = EFI_FDT_GUID; + +/* + * Convert FDT value to host endianness. + * + * @val FDT value + * @return converted value + */ +static uint32_t f2h(fdt32_t val) +{ + char *buf = (char *)&val; + char i; + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + /* Swap the bytes */ + i = buf[0]; buf[0] = buf[3]; buf[3] = i; + i = buf[1]; buf[1] = buf[2]; buf[2] = i; +#endif + return *(uint32_t *)buf; +} + +/* + * Return the value of a property of the FDT root node. + * + * @name name of the property + * @return value of the property + */ +static char *get_property(const u16 *property) +{ + struct fdt_header *header = (struct fdt_header *)fdt; + const fdt32_t *pos; + const char *strings; + + if (!header) + return NULL; + + if (f2h(header->magic) != FDT_MAGIC) { + printf("Wrong magic\n"); + return NULL; + } + + pos = (fdt32_t *)(fdt + f2h(header->off_dt_struct)); + strings = fdt + f2h(header->off_dt_strings); + + for (;;) { + switch (f2h(pos[0])) { + case FDT_BEGIN_NODE: { + char *c = (char *)&pos[1]; + size_t i; + + for (i = 0; c[i]; ++i) + ; + pos = &pos[2 + (i >> 2)]; + break; + } + case FDT_PROP: { + struct fdt_property *prop = (struct fdt_property *)pos; + const char *label = &strings[f2h(prop->nameoff)]; + efi_status_t ret; + + /* Check if this is the property to be returned */ + if (!efi_st_strcmp_16_8(property, label)) { + char *str; + efi_uintn_t len = f2h(prop->len); + + if (!len) + return NULL; + /* + * The string might not be 0 terminated. + * It is safer to make a copy. + */ + ret = boottime->allocate_pool( + EFI_LOADER_DATA, len + 1, + (void **)&str); + if (ret != EFI_SUCCESS) { + efi_st_printf("AllocatePool failed\n"); + return NULL; + } + boottime->copy_mem(str, &pos[3], len); + str[len] = 0; + + return str; + } + + pos = &pos[3 + ((f2h(prop->len) + 3) >> 2)]; + break; + } + case FDT_NOP: + pos = &pos[1]; + break; + default: + return NULL; + } + } +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_uintn_t i; + + boottime = systable->boottime; + + /* Find configuration tables */ + for (i = 0; i < systable->nr_tables; ++i) { + if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid, + sizeof(efi_guid_t))) + fdt = systable->tables[i].table; + } + if (!fdt) { + efi_st_error("Missing device tree\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + char *str; + efi_status_t ret; + + str = get_property(L"compatible"); + if (str) { + efi_st_printf("compatible: %s\n", str); + ret = boottime->free_pool(str); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } else { + efi_st_printf("Missing property 'compatible'\n"); + return EFI_ST_FAILURE; + } + str = get_property(L"serial-number"); + if (str) { + efi_st_printf("serial-number: %s\n", str); + ret = boottime->free_pool(str); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(fdt) = { + .name = "device tree", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c new file mode 100644 index 0000000000..c890ff88b7 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_textinput.c @@ -0,0 +1,182 @@ +/* + * efi_selftest_textinput + * + * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL. + * The unicode character and the scan code are printed for text + * input. To run the test: + * + * setenv efi_selftest text input + * bootefi selftest + */ + +#include <efi_selftest.h> + +struct translate { + u16 code; + u16 *text; +}; + +static struct efi_boot_services *boottime; + +static struct translate control_characters[] = { + {0, L"Null"}, + {8, L"BS"}, + {9, L"TAB"}, + {10, L"LF"}, + {13, L"CR"}, + {0, NULL}, +}; + +static u16 ch[] = L"' '"; +static u16 unknown[] = L"unknown"; + +static struct translate scan_codes[] = { + {0x00, L"Null"}, + {0x01, L"Up"}, + {0x02, L"Down"}, + {0x03, L"Right"}, + {0x04, L"Left"}, + {0x05, L"Home"}, + {0x06, L"End"}, + {0x07, L"Insert"}, + {0x08, L"Delete"}, + {0x09, L"Page Up"}, + {0x0a, L"Page Down"}, + {0x0b, L"FN 1"}, + {0x0c, L"FN 2"}, + {0x0d, L"FN 3"}, + {0x0e, L"FN 4"}, + {0x0f, L"FN 5"}, + {0x10, L"FN 6"}, + {0x11, L"FN 7"}, + {0x12, L"FN 8"}, + {0x13, L"FN 9"}, + {0x14, L"FN 10"}, + {0x15, L"FN 11"}, + {0x16, L"FN 12"}, + {0x17, L"Escape"}, + {0x68, L"FN 13"}, + {0x69, L"FN 14"}, + {0x6a, L"FN 15"}, + {0x6b, L"FN 16"}, + {0x6c, L"FN 17"}, + {0x6d, L"FN 18"}, + {0x6e, L"FN 19"}, + {0x6f, L"FN 20"}, + {0x70, L"FN 21"}, + {0x71, L"FN 22"}, + {0x72, L"FN 23"}, + {0x73, L"FN 24"}, + {0x7f, L"Mute"}, + {0x80, L"Volume Up"}, + {0x81, L"Volume Down"}, + {0x100, L"Brightness Up"}, + {0x101, L"Brightness Down"}, + {0x102, L"Suspend"}, + {0x103, L"Hibernate"}, + {0x104, L"Toggle Display"}, + {0x105, L"Recovery"}, + {0x106, L"Reject"}, + {0x0, NULL}, +}; + +/* + * Translate a unicode character to a string. + * + * @code unicode character + * @return string + */ +static u16 *translate_char(u16 code) +{ + struct translate *tr; + + if (code >= ' ') { + ch[1] = code; + return ch; + } + for (tr = control_characters; tr->text; ++tr) { + if (tr->code == code) + return tr->text; + } + return unknown; +} + +/* + * Translate a scan code to a human readable string. + * + * @code unicode character + * @return string + */ +static u16 *translate_code(u16 code) +{ + struct translate *tr; + + for (tr = scan_codes; tr->text; ++tr) { + if (tr->code == code) + return tr->text; + } + return unknown; +} + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct efi_input_key input_key = {0}; + efi_status_t ret; + + efi_st_printf("Waiting for your input\n"); + efi_st_printf("To terminate type 'x'\n"); + + for (;;) { + /* Wait for next key */ + do { + ret = con_in->read_key_stroke(con_in, &input_key); + } while (ret == EFI_NOT_READY); + + /* Allow 5 minutes until time out */ + boottime->set_watchdog_timer(300, 0, 0, NULL); + + efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n", + (unsigned int)input_key.unicode_char, + translate_char(input_key.unicode_char), + (unsigned int)input_key.scan_code, + translate_code(input_key.scan_code)); + + switch (input_key.unicode_char) { + case 'x': + case 'X': + return EFI_ST_SUCCESS; + } + } +} + +EFI_UNIT_TEST(textinput) = { + .name = "text input", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .on_request = true, +}; |