// SPDX-License-Identifier: GPL-2.0+ /* * efi_selftest_exitbootservices * * Copyright (c) 2017 Heinrich Schuchardt * * This unit test checks that the notification function of an * EVT_SIGNAL_EXIT_BOOT_SERVICES event is called exactly once. */ #include 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, };