1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * efi_selftest_events 4 * 5 * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 6 * 7 * This unit test uses timer events to check the implementation 8 * of the following boottime services: 9 * CreateEvent, CloseEvent, WaitForEvent, CheckEvent, SetTimer. 10 */ 11 12 #include <efi_selftest.h> 13 14 static struct efi_event *event_notify; 15 static struct efi_event *event_wait; 16 static unsigned int timer_ticks; 17 static struct efi_boot_services *boottime; 18 19 /* 20 * Notification function, increments the notification count if parameter 21 * context is provided. 22 * 23 * @event notified event 24 * @context pointer to the notification count 25 */ 26 static void EFIAPI notify(struct efi_event *event, void *context) 27 { 28 unsigned int *count = context; 29 30 if (count) 31 ++*count; 32 } 33 34 /* 35 * Setup unit test. 36 * 37 * Create two timer events. 38 * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. 39 * 40 * @handle: handle of the loaded image 41 * @systable: system table 42 * @return: EFI_ST_SUCCESS for success 43 */ 44 static int setup(const efi_handle_t handle, 45 const struct efi_system_table *systable) 46 { 47 efi_status_t ret; 48 49 boottime = systable->boottime; 50 51 ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, 52 TPL_CALLBACK, notify, (void *)&timer_ticks, 53 &event_notify); 54 if (ret != EFI_SUCCESS) { 55 efi_st_error("could not create event\n"); 56 return EFI_ST_FAILURE; 57 } 58 ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, 59 TPL_CALLBACK, notify, NULL, &event_wait); 60 if (ret != EFI_SUCCESS) { 61 efi_st_error("could not create event\n"); 62 return EFI_ST_FAILURE; 63 } 64 return EFI_ST_SUCCESS; 65 } 66 67 /* 68 * Tear down unit test. 69 * 70 * Close the events created in setup. 71 * 72 * @return: EFI_ST_SUCCESS for success 73 */ 74 static int teardown(void) 75 { 76 efi_status_t ret; 77 78 if (event_notify) { 79 ret = boottime->close_event(event_notify); 80 event_notify = NULL; 81 if (ret != EFI_SUCCESS) { 82 efi_st_error("could not close event\n"); 83 return EFI_ST_FAILURE; 84 } 85 } 86 if (event_wait) { 87 ret = boottime->close_event(event_wait); 88 event_wait = NULL; 89 if (ret != EFI_SUCCESS) { 90 efi_st_error("could not close event\n"); 91 return EFI_ST_FAILURE; 92 } 93 } 94 return EFI_ST_SUCCESS; 95 } 96 97 /* 98 * Execute unit test. 99 * 100 * Run a 10 ms periodic timer and check that it is called 10 times 101 * while waiting for 100 ms single shot timer. 102 * 103 * Run a 100 ms single shot timer and check that it is called once 104 * while waiting for 100 ms periodic timer for two periods. 105 * 106 * @return: EFI_ST_SUCCESS for success 107 */ 108 static int execute(void) 109 { 110 efi_uintn_t index; 111 efi_status_t ret; 112 113 /* Set 10 ms timer */ 114 timer_ticks = 0; 115 ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 116 if (ret != EFI_SUCCESS) { 117 efi_st_error("Could not set timer\n"); 118 return EFI_ST_FAILURE; 119 } 120 /* Set 100 ms timer */ 121 ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 122 if (ret != EFI_SUCCESS) { 123 efi_st_error("Could not set timer\n"); 124 return EFI_ST_FAILURE; 125 } 126 127 /* Set some arbitrary non-zero value to make change detectable. */ 128 index = 5; 129 ret = boottime->wait_for_event(1, &event_wait, &index); 130 if (ret != EFI_SUCCESS) { 131 efi_st_error("Could not wait for event\n"); 132 return EFI_ST_FAILURE; 133 } 134 ret = boottime->check_event(event_wait); 135 if (ret != EFI_NOT_READY) { 136 efi_st_error("Signaled state was not cleared.\n"); 137 efi_st_printf("ret = %u\n", (unsigned int)ret); 138 return EFI_ST_FAILURE; 139 } 140 if (index != 0) { 141 efi_st_error("WaitForEvent returned wrong index\n"); 142 return EFI_ST_FAILURE; 143 } 144 if (timer_ticks < 8 || timer_ticks > 12) { 145 efi_st_printf("Notification count periodic: %u\n", timer_ticks); 146 efi_st_error("Incorrect timing of events\n"); 147 return EFI_ST_FAILURE; 148 } 149 ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); 150 if (index != 0) { 151 efi_st_error("Could not cancel timer\n"); 152 return EFI_ST_FAILURE; 153 } 154 /* Set 10 ms timer */ 155 timer_ticks = 0; 156 ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000); 157 if (index != 0) { 158 efi_st_error("Could not set timer\n"); 159 return EFI_ST_FAILURE; 160 } 161 /* Set 100 ms timer */ 162 ret = boottime->set_timer(event_wait, EFI_TIMER_PERIODIC, 1000000); 163 if (index != 0) { 164 efi_st_error("Could not set timer\n"); 165 return EFI_ST_FAILURE; 166 } 167 ret = boottime->wait_for_event(1, &event_wait, &index); 168 if (ret != EFI_SUCCESS) { 169 efi_st_error("Could not wait for event\n"); 170 return EFI_ST_FAILURE; 171 } 172 if (timer_ticks != 1) { 173 efi_st_printf("Notification count single shot: %u\n", 174 timer_ticks); 175 efi_st_error("Single shot timer failed\n"); 176 return EFI_ST_FAILURE; 177 } 178 ret = boottime->wait_for_event(1, &event_wait, &index); 179 if (ret != EFI_SUCCESS) { 180 efi_st_error("Could not wait for event\n"); 181 return EFI_ST_FAILURE; 182 } 183 if (timer_ticks != 1) { 184 efi_st_printf("Notification count stopped timer: %u\n", 185 timer_ticks); 186 efi_st_error("Stopped timer fired\n"); 187 return EFI_ST_FAILURE; 188 } 189 ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); 190 if (ret != EFI_SUCCESS) { 191 efi_st_error("Could not cancel timer\n"); 192 return EFI_ST_FAILURE; 193 } 194 195 return EFI_ST_SUCCESS; 196 } 197 198 EFI_UNIT_TEST(events) = { 199 .name = "event services", 200 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 201 .setup = setup, 202 .execute = execute, 203 .teardown = teardown, 204 }; 205