1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * efi_selftest_exitbootservices 4 * 5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 * 7 * This unit test checks that the notification function of an 8 * EVT_SIGNAL_EXIT_BOOT_SERVICES event is called exactly once. 9 */ 10 11 #include <efi_selftest.h> 12 13 static struct efi_boot_services *boottime; 14 static struct efi_event *event_notify; 15 static unsigned int notification_count; 16 17 /* 18 * Notification function, increments the notification count. 19 * 20 * @event notified event 21 * @context pointer to the notification count 22 */ 23 static void EFIAPI notify(struct efi_event *event, void *context) 24 { 25 unsigned int *count = context; 26 27 ++*count; 28 } 29 30 /* 31 * Setup unit test. 32 * 33 * Create an EVT_SIGNAL_EXIT_BOOT_SERVICES event. 34 * 35 * @handle: handle of the loaded image 36 * @systable: system table 37 * @return: EFI_ST_SUCCESS for success 38 */ 39 static int setup(const efi_handle_t handle, 40 const struct efi_system_table *systable) 41 { 42 efi_status_t ret; 43 44 boottime = systable->boottime; 45 46 notification_count = 0; 47 ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, 48 TPL_CALLBACK, notify, 49 (void *)¬ification_count, 50 &event_notify); 51 if (ret != EFI_SUCCESS) { 52 efi_st_error("could not create event\n"); 53 return EFI_ST_FAILURE; 54 } 55 return EFI_ST_SUCCESS; 56 } 57 58 /* 59 * Tear down unit test. 60 * 61 * Close the event created in setup. 62 * 63 * @return: EFI_ST_SUCCESS for success 64 */ 65 static int teardown(void) 66 { 67 efi_status_t ret; 68 69 if (event_notify) { 70 ret = boottime->close_event(event_notify); 71 event_notify = NULL; 72 if (ret != EFI_SUCCESS) { 73 efi_st_error("could not close event\n"); 74 return EFI_ST_FAILURE; 75 } 76 } 77 return EFI_ST_SUCCESS; 78 } 79 80 /* 81 * Execute unit test. 82 * 83 * Check that the notification function of the EVT_SIGNAL_EXIT_BOOT_SERVICES 84 * event has been called. 85 * 86 * Call ExitBootServices again and check that the notification function is 87 * not called again. 88 * 89 * @return: EFI_ST_SUCCESS for success 90 */ 91 static int execute(void) 92 { 93 if (notification_count != 1) { 94 efi_st_error("ExitBootServices was not notified\n"); 95 return EFI_ST_FAILURE; 96 } 97 efi_st_exit_boot_services(); 98 if (notification_count != 1) { 99 efi_st_error("ExitBootServices was notified twice\n"); 100 return EFI_ST_FAILURE; 101 } 102 return EFI_ST_SUCCESS; 103 } 104 105 EFI_UNIT_TEST(exitbootservices) = { 106 .name = "ExitBootServices", 107 .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, 108 .setup = setup, 109 .execute = execute, 110 .teardown = teardown, 111 }; 112