u-boot/lib/efi_selftest/efi_selftest_register_notify.c
Heinrich Schuchardt f09cea36ca efi_loader: correct notification of protocol installation
When a protocol is installed the handle should be queued for the
registration key of each registered event. LocateHandle() should return the
first handle from the queue for the registration key and delete it from the
queue.

Implement the queueing.

Correct the selftest.

With the patch the UEFI SCT tests for LocateHandle() are passed without
failure.

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
2019-05-31 23:27:11 +02:00

236 lines
5.7 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* efi_selftest_register_notify
*
* Copyright (c) 2019 Heinrich Schuchardt <xypron.glpk@gmx.de>
*
* This unit test checks the following protocol services:
* InstallProtocolInterface, UninstallProtocolInterface,
* RegisterProtocolNotify, CreateEvent, CloseEvent.
*/
#include <efi_selftest.h>
/*
* 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;
efi_uintn_t handle_count;
efi_handle_t *handles;
cp->notify_count++;
for (;;) {
ret = boottime->locate_handle_buffer(BY_REGISTER_NOTIFY, NULL,
cp->registration_key,
&handle_count, &handles);
if (ret != EFI_SUCCESS)
break;
cp->handle_count += handle_count;
cp->handles = handles;
}
}
/*
* 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 != 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;
}
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 != 3) {
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,
};