From 24f6be7ada05f24f18aec6651dd393e82136342a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 4 May 2019 22:44:13 +0200 Subject: [PATCH] efi_selftest: unit test for RegisterProtocolNotify() Provide a unit test for the RegisterProtocolNotify() boot service. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/Makefile | 1 + .../efi_selftest_register_notify.c | 231 ++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_register_notify.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 4945691e67..c69ad7a9c0 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -27,6 +27,7 @@ efi_selftest_gop.o \ efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ efi_selftest_memory.o \ +efi_selftest_register_notify.o \ efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ diff --git a/lib/efi_selftest/efi_selftest_register_notify.c b/lib/efi_selftest/efi_selftest_register_notify.c new file mode 100644 index 0000000000..ee0ef395de --- /dev/null +++ b/lib/efi_selftest/efi_selftest_register_notify.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_register_notify + * + * Copyright (c) 2019 Heinrich Schuchardt + * + * This unit test checks the following protocol services: + * InstallProtocolInterface, UninstallProtocolInterface, + * RegisterProtocolNotify, CreateEvent, CloseEvent. + */ + +#include + +/* + * The test currently does not actually call the interface function. + * So this is just a dummy structure. + */ +struct interface { + void (EFIAPI * inc)(void); +}; + +struct context { + void *registration_key; + efi_uintn_t notify_count; + efi_uintn_t handle_count; + efi_handle_t *handles; +}; + +static struct efi_boot_services *boottime; +static efi_guid_t guid1 = + EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a, + 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf); +static efi_guid_t guid2 = + EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77, + 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f); +static struct context context; +static struct efi_event *event; + +/* + * Notification function, increments the notification 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) +{ + struct context *cp = context; + efi_status_t ret; + + cp->notify_count++; + + ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL, + cp->registration_key, + &cp->handle_count, + &cp->handles); + if (ret != EFI_SUCCESS) + cp->handle_count = 0; +} + +/* + * 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) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->create_event(EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, &context, + &event); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->register_protocol_notify(&guid1, event, + &context.registration_key); + if (ret != EFI_SUCCESS) { + efi_st_error("could not register event\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + + 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. + * + */ +static int execute(void) +{ + efi_status_t ret; + efi_handle_t handle1 = NULL, handle2 = NULL; + struct interface interface1, interface2; + + ret = boottime->install_protocol_interface(&handle1, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("could not install interface\n"); + return EFI_ST_FAILURE; + } + if (!context.notify_count) { + efi_st_error("install was not notified\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count > 1) { + efi_st_error("install was notified too often\n"); + return EFI_ST_FAILURE; + } + if (context.handle_count != 1) { + efi_st_error("LocateHandle failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(context.handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + context.notify_count = 0; + ret = boottime->install_protocol_interface(&handle1, &guid2, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("could not install interface\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count) { + efi_st_error("wrong protocol was notified\n"); + return EFI_ST_FAILURE; + } + context.notify_count = 0; + ret = boottime->reinstall_protocol_interface(handle1, &guid1, + &interface1, &interface2); + if (ret != EFI_SUCCESS) { + efi_st_error("could not reinstall interface\n"); + return EFI_ST_FAILURE; + } + if (!context.notify_count) { + efi_st_error("reinstall was not notified\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count > 1) { + efi_st_error("reinstall was notified too often\n"); + return EFI_ST_FAILURE; + } + if (context.handle_count != 1) { + efi_st_error("LocateHandle failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(context.handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + context.notify_count = 0; + ret = boottime->install_protocol_interface(&handle2, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("could not install interface\n"); + return EFI_ST_FAILURE; + } + if (!context.notify_count) { + efi_st_error("install was not notified\n"); + return EFI_ST_FAILURE; + } + if (context.notify_count > 1) { + efi_st_error("install was notified too often\n"); + return EFI_ST_FAILURE; + } + if (context.handle_count != 2) { + efi_st_error("LocateHandle failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(context.handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->uninstall_multiple_protocol_interfaces + (handle1, &guid1, &interface2, + &guid2, &interface1, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->uninstall_multiple_protocol_interfaces + (handle2, &guid1, &interface1, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(regprotnot) = { + .name = "register protocol notify", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; -- 2.39.5