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 size_t index; 115 efi_status_t ret; 116 UINTN 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 efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", 148 notification_count); 149 if (notification_count < 8 || notification_count > 12) { 150 efi_st_error("Incorrect timing of events\n"); 151 return EFI_ST_FAILURE; 152 } 153 ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); 154 if (index != 0) { 155 efi_st_error("Could not cancel timer\n"); 156 return EFI_ST_FAILURE; 157 } 158 /* Raise TPL level */ 159 old_tpl = boottime->raise_tpl(TPL_CALLBACK); 160 if (old_tpl != TPL_APPLICATION) { 161 efi_st_error("Initial TPL level was not TPL_APPLICATION"); 162 return EFI_ST_FAILURE; 163 } 164 /* Set 10 ms timer */ 165 notification_count = 0; 166 ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 167 if (index != 0) { 168 efi_st_error("Could not set timer\n"); 169 return EFI_ST_FAILURE; 170 } 171 /* Set 100 ms timer */ 172 ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 173 if (ret != EFI_SUCCESS) { 174 efi_st_error("Could not set timer\n"); 175 return EFI_ST_FAILURE; 176 } 177 do { 178 ret = boottime->check_event(event_wait); 179 } while (ret == EFI_NOT_READY); 180 if (ret != EFI_SUCCESS) { 181 efi_st_error("Could not check event\n"); 182 return EFI_ST_FAILURE; 183 } 184 efi_st_printf("Notification count with TPL level TPL_CALLBACK: %u\n", 185 notification_count); 186 if (notification_count != 0) { 187 efi_st_error("Suppressed timer fired\n"); 188 return EFI_ST_FAILURE; 189 } 190 /* Set 1 ms timer */ 191 ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); 192 if (ret != EFI_SUCCESS) { 193 efi_st_error("Could not set timer\n"); 194 return EFI_ST_FAILURE; 195 } 196 /* Restore the old TPL level */ 197 boottime->restore_tpl(TPL_APPLICATION); 198 ret = boottime->wait_for_event(1, &event_wait, &index); 199 if (ret != EFI_SUCCESS) { 200 efi_st_error("Could not wait for event\n"); 201 return EFI_ST_FAILURE; 202 } 203 efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", 204 notification_count); 205 if (notification_count < 1) { 206 efi_st_error("Queued timer event did not fire\n"); 207 return EFI_ST_FAILURE; 208 } 209 ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); 210 if (ret != EFI_SUCCESS) { 211 efi_st_error("Could not cancel timer\n"); 212 return EFI_ST_FAILURE; 213 } 214 215 return EFI_ST_SUCCESS; 216 } 217 218 EFI_UNIT_TEST(tpl) = { 219 .name = "task priority levels", 220 .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 221 .setup = setup, 222 .execute = execute, 223 .teardown = teardown, 224 }; 225