11835f6eaSHeinrich Schuchardt /* 21835f6eaSHeinrich Schuchardt * efi_selftest_events 31835f6eaSHeinrich Schuchardt * 41835f6eaSHeinrich Schuchardt * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 51835f6eaSHeinrich Schuchardt * 61835f6eaSHeinrich Schuchardt * SPDX-License-Identifier: GPL-2.0+ 71835f6eaSHeinrich Schuchardt * 81835f6eaSHeinrich Schuchardt * This unit test uses timer events to check the handling of 91835f6eaSHeinrich Schuchardt * task priority levels. 101835f6eaSHeinrich Schuchardt */ 111835f6eaSHeinrich Schuchardt 121835f6eaSHeinrich Schuchardt #include <efi_selftest.h> 131835f6eaSHeinrich Schuchardt 141835f6eaSHeinrich Schuchardt static struct efi_event *event_notify; 151835f6eaSHeinrich Schuchardt static struct efi_event *event_wait; 16e67e7249SHeinrich Schuchardt static unsigned int notification_count; 171835f6eaSHeinrich Schuchardt static struct efi_boot_services *boottime; 181835f6eaSHeinrich Schuchardt 191835f6eaSHeinrich Schuchardt /* 20e67e7249SHeinrich Schuchardt * Notification function, increments the notification count. 211835f6eaSHeinrich Schuchardt * 221835f6eaSHeinrich Schuchardt * @event notified event 23e67e7249SHeinrich Schuchardt * @context pointer to the notification count 241835f6eaSHeinrich Schuchardt */ 251835f6eaSHeinrich Schuchardt static void EFIAPI notify(struct efi_event *event, void *context) 261835f6eaSHeinrich Schuchardt { 27e67e7249SHeinrich Schuchardt unsigned int *count = context; 28e67e7249SHeinrich Schuchardt 29e67e7249SHeinrich Schuchardt ++*count; 301835f6eaSHeinrich Schuchardt } 311835f6eaSHeinrich Schuchardt 321835f6eaSHeinrich Schuchardt /* 331835f6eaSHeinrich Schuchardt * Setup unit test. 341835f6eaSHeinrich Schuchardt * 351835f6eaSHeinrich Schuchardt * Create two timer events. 361835f6eaSHeinrich Schuchardt * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. 371835f6eaSHeinrich Schuchardt * 381835f6eaSHeinrich Schuchardt * @handle: handle of the loaded image 391835f6eaSHeinrich Schuchardt * @systable: system table 40e67e7249SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success 411835f6eaSHeinrich Schuchardt */ 421835f6eaSHeinrich Schuchardt static int setup(const efi_handle_t handle, 431835f6eaSHeinrich Schuchardt const struct efi_system_table *systable) 441835f6eaSHeinrich Schuchardt { 451835f6eaSHeinrich Schuchardt efi_status_t ret; 461835f6eaSHeinrich Schuchardt 471835f6eaSHeinrich Schuchardt boottime = systable->boottime; 481835f6eaSHeinrich Schuchardt 491835f6eaSHeinrich Schuchardt ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, 50e67e7249SHeinrich Schuchardt TPL_CALLBACK, notify, 51e67e7249SHeinrich Schuchardt (void *)¬ification_count, 521835f6eaSHeinrich Schuchardt &event_notify); 531835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 541835f6eaSHeinrich Schuchardt efi_st_error("could not create event\n"); 55e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 561835f6eaSHeinrich Schuchardt } 571835f6eaSHeinrich Schuchardt ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, 581835f6eaSHeinrich Schuchardt TPL_HIGH_LEVEL, notify, NULL, &event_wait); 591835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 601835f6eaSHeinrich Schuchardt efi_st_error("could not create event\n"); 61e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 621835f6eaSHeinrich Schuchardt } 63e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 641835f6eaSHeinrich Schuchardt } 651835f6eaSHeinrich Schuchardt 661835f6eaSHeinrich Schuchardt /* 671835f6eaSHeinrich Schuchardt * Tear down unit test. 681835f6eaSHeinrich Schuchardt * 691835f6eaSHeinrich Schuchardt * Close the events created in setup. 70e67e7249SHeinrich Schuchardt * 71e67e7249SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success 721835f6eaSHeinrich Schuchardt */ 731835f6eaSHeinrich Schuchardt static int teardown(void) 741835f6eaSHeinrich Schuchardt { 751835f6eaSHeinrich Schuchardt efi_status_t ret; 761835f6eaSHeinrich Schuchardt 771835f6eaSHeinrich Schuchardt if (event_notify) { 781835f6eaSHeinrich Schuchardt ret = boottime->close_event(event_notify); 791835f6eaSHeinrich Schuchardt event_notify = NULL; 801835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 811835f6eaSHeinrich Schuchardt efi_st_error("could not close event\n"); 82e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 831835f6eaSHeinrich Schuchardt } 841835f6eaSHeinrich Schuchardt } 851835f6eaSHeinrich Schuchardt if (event_wait) { 861835f6eaSHeinrich Schuchardt ret = boottime->close_event(event_wait); 871835f6eaSHeinrich Schuchardt event_wait = NULL; 881835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 891835f6eaSHeinrich Schuchardt efi_st_error("could not close event\n"); 90e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 911835f6eaSHeinrich Schuchardt } 921835f6eaSHeinrich Schuchardt } 931835f6eaSHeinrich Schuchardt boottime->restore_tpl(TPL_APPLICATION); 94e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 951835f6eaSHeinrich Schuchardt } 961835f6eaSHeinrich Schuchardt 971835f6eaSHeinrich Schuchardt /* 981835f6eaSHeinrich Schuchardt * Execute unit test. 991835f6eaSHeinrich Schuchardt * 1001835f6eaSHeinrich Schuchardt * Run a 10 ms periodic timer and check that it is called 10 times 1011835f6eaSHeinrich Schuchardt * while waiting for 100 ms single shot timer. 1021835f6eaSHeinrich Schuchardt * 1031835f6eaSHeinrich Schuchardt * Raise the TPL level to the level of the 10 ms timer and observe 1041835f6eaSHeinrich Schuchardt * that the notification function is not called again. 1051835f6eaSHeinrich Schuchardt * 1061835f6eaSHeinrich Schuchardt * Lower the TPL level and check that the queued notification 1071835f6eaSHeinrich Schuchardt * function is called. 108e67e7249SHeinrich Schuchardt * 109e67e7249SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success 1101835f6eaSHeinrich Schuchardt */ 1111835f6eaSHeinrich Schuchardt static int execute(void) 1121835f6eaSHeinrich Schuchardt { 113*ca379e1bSHeinrich Schuchardt size_t index; 1141835f6eaSHeinrich Schuchardt efi_status_t ret; 1151835f6eaSHeinrich Schuchardt UINTN old_tpl; 1161835f6eaSHeinrich Schuchardt 1171835f6eaSHeinrich Schuchardt /* Set 10 ms timer */ 118e67e7249SHeinrich Schuchardt notification_count = 0; 1191835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 1201835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1211835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 122e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1231835f6eaSHeinrich Schuchardt } 1241835f6eaSHeinrich Schuchardt /* Set 100 ms timer */ 1251835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 1261835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1271835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 128e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1291835f6eaSHeinrich Schuchardt } 1301835f6eaSHeinrich Schuchardt index = 5; 1311835f6eaSHeinrich Schuchardt ret = boottime->wait_for_event(1, &event_wait, &index); 1321835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1331835f6eaSHeinrich Schuchardt efi_st_error("Could not wait for event\n"); 134e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1351835f6eaSHeinrich Schuchardt } 1361835f6eaSHeinrich Schuchardt ret = boottime->check_event(event_wait); 1371835f6eaSHeinrich Schuchardt if (ret != EFI_NOT_READY) { 1381835f6eaSHeinrich Schuchardt efi_st_error("Signaled state was not cleared.\n"); 1391835f6eaSHeinrich Schuchardt efi_st_printf("ret = %u\n", (unsigned int)ret); 140e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1411835f6eaSHeinrich Schuchardt } 1421835f6eaSHeinrich Schuchardt if (index != 0) { 1431835f6eaSHeinrich Schuchardt efi_st_error("WaitForEvent returned wrong index\n"); 144e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1451835f6eaSHeinrich Schuchardt } 146e67e7249SHeinrich Schuchardt efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", 147e67e7249SHeinrich Schuchardt notification_count); 148e67e7249SHeinrich Schuchardt if (notification_count < 8 || notification_count > 12) { 1491835f6eaSHeinrich Schuchardt efi_st_error("Incorrect timing of events\n"); 150e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1511835f6eaSHeinrich Schuchardt } 1521835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); 1531835f6eaSHeinrich Schuchardt if (index != 0) { 1541835f6eaSHeinrich Schuchardt efi_st_error("Could not cancel timer\n"); 155e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1561835f6eaSHeinrich Schuchardt } 1571835f6eaSHeinrich Schuchardt /* Raise TPL level */ 1581835f6eaSHeinrich Schuchardt old_tpl = boottime->raise_tpl(TPL_CALLBACK); 1591835f6eaSHeinrich Schuchardt if (old_tpl != TPL_APPLICATION) { 1601835f6eaSHeinrich Schuchardt efi_st_error("Initial TPL level was not TPL_APPLICATION"); 161e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1621835f6eaSHeinrich Schuchardt } 1631835f6eaSHeinrich Schuchardt /* Set 10 ms timer */ 164e67e7249SHeinrich Schuchardt notification_count = 0; 1651835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 1661835f6eaSHeinrich Schuchardt if (index != 0) { 1671835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 168e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1691835f6eaSHeinrich Schuchardt } 1701835f6eaSHeinrich Schuchardt /* Set 100 ms timer */ 1711835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 1721835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1731835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 174e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1751835f6eaSHeinrich Schuchardt } 1761835f6eaSHeinrich Schuchardt do { 1771835f6eaSHeinrich Schuchardt ret = boottime->check_event(event_wait); 1781835f6eaSHeinrich Schuchardt } while (ret == EFI_NOT_READY); 1791835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1801835f6eaSHeinrich Schuchardt efi_st_error("Could not check event\n"); 181e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1821835f6eaSHeinrich Schuchardt } 183e67e7249SHeinrich Schuchardt efi_st_printf("Notification count with TPL level TPL_CALLBACK: %u\n", 184e67e7249SHeinrich Schuchardt notification_count); 185e67e7249SHeinrich Schuchardt if (notification_count != 0) { 1861835f6eaSHeinrich Schuchardt efi_st_error("Suppressed timer fired\n"); 187e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1881835f6eaSHeinrich Schuchardt } 1891835f6eaSHeinrich Schuchardt /* Set 1 ms timer */ 1901835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); 1911835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1921835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 193e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1941835f6eaSHeinrich Schuchardt } 1951835f6eaSHeinrich Schuchardt /* Restore the old TPL level */ 1961835f6eaSHeinrich Schuchardt boottime->restore_tpl(TPL_APPLICATION); 1971835f6eaSHeinrich Schuchardt ret = boottime->wait_for_event(1, &event_wait, &index); 1981835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1991835f6eaSHeinrich Schuchardt efi_st_error("Could not wait for event\n"); 200e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2011835f6eaSHeinrich Schuchardt } 202e67e7249SHeinrich Schuchardt efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", 203e67e7249SHeinrich Schuchardt notification_count); 204e67e7249SHeinrich Schuchardt if (notification_count < 1) { 2051835f6eaSHeinrich Schuchardt efi_st_error("Queued timer event did not fire\n"); 206e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2071835f6eaSHeinrich Schuchardt } 2081835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); 2091835f6eaSHeinrich Schuchardt if (index != 0) { 2101835f6eaSHeinrich Schuchardt efi_st_error("Could not cancel timer\n"); 211e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2121835f6eaSHeinrich Schuchardt } 2131835f6eaSHeinrich Schuchardt 214e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 2151835f6eaSHeinrich Schuchardt } 2161835f6eaSHeinrich Schuchardt 2171835f6eaSHeinrich Schuchardt EFI_UNIT_TEST(tpl) = { 2181835f6eaSHeinrich Schuchardt .name = "task priority levels", 2191835f6eaSHeinrich Schuchardt .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 2201835f6eaSHeinrich Schuchardt .setup = setup, 2211835f6eaSHeinrich Schuchardt .execute = execute, 2221835f6eaSHeinrich Schuchardt .teardown = teardown, 2231835f6eaSHeinrich Schuchardt }; 224