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 handling of 9 * task priority levels. 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 notification_count; 17 static struct efi_boot_services *boottime; 18 19 /* 20 * Notification function, increments the notification count. 21 * 22 * @event notified event 23 * @context pointer to the notification count 24 */ 25 static void EFIAPI notify(struct efi_event *event, void *context) 26 { 27 unsigned int *count = context; 28 29 if (count) 30 ++*count; 31 } 32 33 /* 34 * Setup unit test. 35 * 36 * Create two timer events. 37 * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. 38 * 39 * @handle: handle of the loaded image 40 * @systable: system table 41 * @return: EFI_ST_SUCCESS for success 42 */ 43 static int setup(const efi_handle_t handle, 44 const struct efi_system_table *systable) 45 { 46 efi_status_t ret; 47 48 boottime = systable->boottime; 49 50 ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, 51 TPL_CALLBACK, notify, 52 (void *)¬ification_count, 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_HIGH_LEVEL, 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 boottime->restore_tpl(TPL_APPLICATION); 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 * Raise the TPL level to the level of the 10 ms timer and observe 105 * that the notification function is not called again. 106 * 107 * Lower the TPL level and check that the queued notification 108 * function is called. 109 * 110 * @return: EFI_ST_SUCCESS for success 111 */ 112 static int execute(void) 113 { 114 efi_uintn_t index; 115 efi_status_t ret; 116 efi_uintn_t old_tpl; 117 118 /* Set 10 ms timer */ 119 notification_count = 0; 120 ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 121 if (ret != EFI_SUCCESS) { 122 efi_st_error("Could not set timer\n"); 123 return EFI_ST_FAILURE; 124 } 125 /* Set 100 ms timer */ 126 ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 127 if (ret != EFI_SUCCESS) { 128 efi_st_error("Could not set timer\n"); 129 return EFI_ST_FAILURE; 130 } 131 index = 5; 132 ret = boottime->wait_for_event(1, &event_wait, &index); 133 if (ret != EFI_SUCCESS) { 134 efi_st_error("Could not wait for event\n"); 135 return EFI_ST_FAILURE; 136 } 137 ret = boottime->check_event(event_wait); 138 if (ret != EFI_NOT_READY) { 139 efi_st_error("Signaled state was not cleared.\n"); 140 efi_st_printf("ret = %u\n", (unsigned int)ret); 141 return EFI_ST_FAILURE; 142 } 143 if (index != 0) { 144 efi_st_error("WaitForEvent returned wrong index\n"); 145 return EFI_ST_FAILURE; 146 } 147 if (notification_count < 8 || notification_count > 12) { 148 efi_st_printf( 149 "Notification count with TPL level TPL_APPLICATION: %u\n", 150 notification_count); 151 efi_st_error("Incorrect timing of events\n"); 152 return EFI_ST_FAILURE; 153 } 154 ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); 155 if (index != 0) { 156 efi_st_error("Could not cancel timer\n"); 157 return EFI_ST_FAILURE; 158 } 159 /* Raise TPL level */ 160 old_tpl = boottime->raise_tpl(TPL_CALLBACK); 161 if (old_tpl != TPL_APPLICATION) { 162 efi_st_error("Initial TPL level was not TPL_APPLICATION"); 163 return EFI_ST_FAILURE; 164 } 165 /* Set 10 ms timer */ 166 notification_count = 0; 167 ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 168 if (index != 0) { 169 efi_st_error("Could not set timer\n"); 170 return EFI_ST_FAILURE; 171 } 172 /* Set 100 ms timer */ 173 ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 174 if (ret != EFI_SUCCESS) { 175 efi_st_error("Could not set timer\n"); 176 return EFI_ST_FAILURE; 177 } 178 do { 179 ret = boottime->check_event(event_wait); 180 } while (ret == EFI_NOT_READY); 181 if (ret != EFI_SUCCESS) { 182 efi_st_error("Could not check event\n"); 183 return EFI_ST_FAILURE; 184 } 185 if (notification_count != 0) { 186 efi_st_printf( 187 "Notification count with TPL level TPL_CALLBACK: %u\n", 188 notification_count); 189 efi_st_error("Suppressed timer fired\n"); 190 return EFI_ST_FAILURE; 191 } 192 /* Set 1 ms timer */ 193 ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); 194 if (ret != EFI_SUCCESS) { 195 efi_st_error("Could not set timer\n"); 196 return EFI_ST_FAILURE; 197 } 198 /* Restore the old TPL level */ 199 boottime->restore_tpl(TPL_APPLICATION); 200 ret = boottime->wait_for_event(1, &event_wait, &index); 201 if (ret != EFI_SUCCESS) { 202 efi_st_error("Could not wait for event\n"); 203 return EFI_ST_FAILURE; 204 } 205 if (notification_count < 1) { 206 efi_st_printf( 207 "Notification count with TPL level TPL_APPLICATION: %u\n", 208 notification_count); 209 efi_st_error("Queued timer event did not fire\n"); 210 return EFI_ST_FAILURE; 211 } 212 ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); 213 if (ret != EFI_SUCCESS) { 214 efi_st_error("Could not cancel timer\n"); 215 return EFI_ST_FAILURE; 216 } 217 218 return EFI_ST_SUCCESS; 219 } 220 221 EFI_UNIT_TEST(tpl) = { 222 .name = "task priority levels", 223 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 224 .setup = setup, 225 .execute = execute, 226 .teardown = teardown, 227 }; 228