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