diff options
Diffstat (limited to 'lib/efi_selftest/efi_selftest_exitbootservices.c')
-rw-r--r-- | lib/efi_selftest/efi_selftest_exitbootservices.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/lib/efi_selftest/efi_selftest_exitbootservices.c b/lib/efi_selftest/efi_selftest_exitbootservices.c new file mode 100644 index 00000000000..b090ce74d23 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_exitbootservices.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_exitbootservices + * + * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> + * + * This unit test checks that the notification function of an + * EVT_SIGNAL_EXIT_BOOT_SERVICES event is called exactly once. + */ + +#include <efi_selftest.h> + +static efi_guid_t guid_before_exit_boot_services = + EFI_GUID(0x8be0e274, 0x3970, 0x4b44, 0x80, 0xc5, + 0x1a, 0xb9, 0x50, 0x2f, 0x3b, 0xfc); +#define CAPACITY 4 + +struct notification_record { + unsigned int count; + unsigned int type[CAPACITY]; +}; + +struct notification_context { + struct notification_record *record; + unsigned int type; +}; + +static struct efi_boot_services *boottime; +static struct efi_event *efi_st_event_notify; +static struct notification_record record; + +struct notification_context context_before = { + .record = &record, + .type = 1, +}; + +struct notification_context context = { + .record = &record, + .type = 2, +}; + +/* + * Notification function, increments the notification count. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI ebs_notify(struct efi_event *event, void *context) +{ + struct notification_context *ctx = context; + + if (ctx->record->count >= CAPACITY) + return; + + ctx->record->type[ctx->record->count] = ctx->type; + ctx->record->count++; +} + +/* + * Setup unit test. + * + * Create an EVT_SIGNAL_EXIT_BOOT_SERVICES event. + * + * @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; + + boottime = systable->boottime; + + ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, + TPL_CALLBACK, ebs_notify, + &context, + &efi_st_event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->create_event_ex(0, TPL_CALLBACK, ebs_notify, + &context_before, + &guid_before_exit_boot_services, + &efi_st_event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES + * event has been called. + * + * Call ExitBootServices again and check that the notification function is + * not called again. + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + if (record.count != 2) { + efi_st_error("Incorrect event count %u\n", record.count); + return EFI_ST_FAILURE; + } + if (record.type[0] != 1) { + efi_st_error("EFI_GROUP_BEFORE_EXIT_BOOT_SERVICE not notified\n"); + return EFI_ST_FAILURE; + } + if (record.type[1] != 2) { + efi_st_error("EVT_SIGNAL_EXIT_BOOT_SERVICES was not notified\n"); + return EFI_ST_FAILURE; + } + efi_st_exit_boot_services(); + if (record.count != 2) { + efi_st_error("Incorrect event count %u\n", record.count); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(exitbootservices) = { + .name = "ExitBootServices", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; |