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