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 297f8ec5b6SHeinrich Schuchardt if (count) 30e67e7249SHeinrich Schuchardt ++*count; 311835f6eaSHeinrich Schuchardt } 321835f6eaSHeinrich Schuchardt 331835f6eaSHeinrich Schuchardt /* 341835f6eaSHeinrich Schuchardt * Setup unit test. 351835f6eaSHeinrich Schuchardt * 361835f6eaSHeinrich Schuchardt * Create two timer events. 371835f6eaSHeinrich Schuchardt * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. 381835f6eaSHeinrich Schuchardt * 391835f6eaSHeinrich Schuchardt * @handle: handle of the loaded image 401835f6eaSHeinrich Schuchardt * @systable: system table 41e67e7249SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success 421835f6eaSHeinrich Schuchardt */ 431835f6eaSHeinrich Schuchardt static int setup(const efi_handle_t handle, 441835f6eaSHeinrich Schuchardt const struct efi_system_table *systable) 451835f6eaSHeinrich Schuchardt { 461835f6eaSHeinrich Schuchardt efi_status_t ret; 471835f6eaSHeinrich Schuchardt 481835f6eaSHeinrich Schuchardt boottime = systable->boottime; 491835f6eaSHeinrich Schuchardt 501835f6eaSHeinrich Schuchardt ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, 51e67e7249SHeinrich Schuchardt TPL_CALLBACK, notify, 52e67e7249SHeinrich Schuchardt (void *)¬ification_count, 531835f6eaSHeinrich Schuchardt &event_notify); 541835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 551835f6eaSHeinrich Schuchardt efi_st_error("could not create event\n"); 56e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 571835f6eaSHeinrich Schuchardt } 581835f6eaSHeinrich Schuchardt ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, 591835f6eaSHeinrich Schuchardt TPL_HIGH_LEVEL, notify, NULL, &event_wait); 601835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 611835f6eaSHeinrich Schuchardt efi_st_error("could not create event\n"); 62e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 631835f6eaSHeinrich Schuchardt } 64e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 651835f6eaSHeinrich Schuchardt } 661835f6eaSHeinrich Schuchardt 671835f6eaSHeinrich Schuchardt /* 681835f6eaSHeinrich Schuchardt * Tear down unit test. 691835f6eaSHeinrich Schuchardt * 701835f6eaSHeinrich Schuchardt * Close the events created in setup. 71e67e7249SHeinrich Schuchardt * 72e67e7249SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success 731835f6eaSHeinrich Schuchardt */ 741835f6eaSHeinrich Schuchardt static int teardown(void) 751835f6eaSHeinrich Schuchardt { 761835f6eaSHeinrich Schuchardt efi_status_t ret; 771835f6eaSHeinrich Schuchardt 781835f6eaSHeinrich Schuchardt if (event_notify) { 791835f6eaSHeinrich Schuchardt ret = boottime->close_event(event_notify); 801835f6eaSHeinrich Schuchardt event_notify = NULL; 811835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 821835f6eaSHeinrich Schuchardt efi_st_error("could not close event\n"); 83e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 841835f6eaSHeinrich Schuchardt } 851835f6eaSHeinrich Schuchardt } 861835f6eaSHeinrich Schuchardt if (event_wait) { 871835f6eaSHeinrich Schuchardt ret = boottime->close_event(event_wait); 881835f6eaSHeinrich Schuchardt event_wait = NULL; 891835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 901835f6eaSHeinrich Schuchardt efi_st_error("could not close event\n"); 91e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 921835f6eaSHeinrich Schuchardt } 931835f6eaSHeinrich Schuchardt } 941835f6eaSHeinrich Schuchardt boottime->restore_tpl(TPL_APPLICATION); 95e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 961835f6eaSHeinrich Schuchardt } 971835f6eaSHeinrich Schuchardt 981835f6eaSHeinrich Schuchardt /* 991835f6eaSHeinrich Schuchardt * Execute unit test. 1001835f6eaSHeinrich Schuchardt * 1011835f6eaSHeinrich Schuchardt * Run a 10 ms periodic timer and check that it is called 10 times 1021835f6eaSHeinrich Schuchardt * while waiting for 100 ms single shot timer. 1031835f6eaSHeinrich Schuchardt * 1041835f6eaSHeinrich Schuchardt * Raise the TPL level to the level of the 10 ms timer and observe 1051835f6eaSHeinrich Schuchardt * that the notification function is not called again. 1061835f6eaSHeinrich Schuchardt * 1071835f6eaSHeinrich Schuchardt * Lower the TPL level and check that the queued notification 1081835f6eaSHeinrich Schuchardt * function is called. 109e67e7249SHeinrich Schuchardt * 110e67e7249SHeinrich Schuchardt * @return: EFI_ST_SUCCESS for success 1111835f6eaSHeinrich Schuchardt */ 1121835f6eaSHeinrich Schuchardt static int execute(void) 1131835f6eaSHeinrich Schuchardt { 114*f5a2a938SHeinrich Schuchardt efi_uintn_t index; 1151835f6eaSHeinrich Schuchardt efi_status_t ret; 116152cade3SHeinrich Schuchardt efi_uintn_t old_tpl; 1171835f6eaSHeinrich Schuchardt 1181835f6eaSHeinrich Schuchardt /* Set 10 ms timer */ 119e67e7249SHeinrich Schuchardt notification_count = 0; 1201835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 1211835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1221835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 123e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1241835f6eaSHeinrich Schuchardt } 1251835f6eaSHeinrich Schuchardt /* Set 100 ms timer */ 1261835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 1271835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1281835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 129e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1301835f6eaSHeinrich Schuchardt } 1311835f6eaSHeinrich Schuchardt index = 5; 1321835f6eaSHeinrich Schuchardt ret = boottime->wait_for_event(1, &event_wait, &index); 1331835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1341835f6eaSHeinrich Schuchardt efi_st_error("Could not wait for event\n"); 135e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1361835f6eaSHeinrich Schuchardt } 1371835f6eaSHeinrich Schuchardt ret = boottime->check_event(event_wait); 1381835f6eaSHeinrich Schuchardt if (ret != EFI_NOT_READY) { 1391835f6eaSHeinrich Schuchardt efi_st_error("Signaled state was not cleared.\n"); 1401835f6eaSHeinrich Schuchardt efi_st_printf("ret = %u\n", (unsigned int)ret); 141e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1421835f6eaSHeinrich Schuchardt } 1431835f6eaSHeinrich Schuchardt if (index != 0) { 1441835f6eaSHeinrich Schuchardt efi_st_error("WaitForEvent returned wrong index\n"); 145e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1461835f6eaSHeinrich Schuchardt } 147e67e7249SHeinrich Schuchardt efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", 148e67e7249SHeinrich Schuchardt notification_count); 149e67e7249SHeinrich Schuchardt if (notification_count < 8 || notification_count > 12) { 1501835f6eaSHeinrich Schuchardt efi_st_error("Incorrect timing of events\n"); 151e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1521835f6eaSHeinrich Schuchardt } 1531835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); 1541835f6eaSHeinrich Schuchardt if (index != 0) { 1551835f6eaSHeinrich Schuchardt efi_st_error("Could not cancel timer\n"); 156e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1571835f6eaSHeinrich Schuchardt } 1581835f6eaSHeinrich Schuchardt /* Raise TPL level */ 1591835f6eaSHeinrich Schuchardt old_tpl = boottime->raise_tpl(TPL_CALLBACK); 1601835f6eaSHeinrich Schuchardt if (old_tpl != TPL_APPLICATION) { 1611835f6eaSHeinrich Schuchardt efi_st_error("Initial TPL level was not TPL_APPLICATION"); 162e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1631835f6eaSHeinrich Schuchardt } 1641835f6eaSHeinrich Schuchardt /* Set 10 ms timer */ 165e67e7249SHeinrich Schuchardt notification_count = 0; 1661835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); 1671835f6eaSHeinrich Schuchardt if (index != 0) { 1681835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 169e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1701835f6eaSHeinrich Schuchardt } 1711835f6eaSHeinrich Schuchardt /* Set 100 ms timer */ 1721835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); 1731835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1741835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 175e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1761835f6eaSHeinrich Schuchardt } 1771835f6eaSHeinrich Schuchardt do { 1781835f6eaSHeinrich Schuchardt ret = boottime->check_event(event_wait); 1791835f6eaSHeinrich Schuchardt } while (ret == EFI_NOT_READY); 1801835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1811835f6eaSHeinrich Schuchardt efi_st_error("Could not check event\n"); 182e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1831835f6eaSHeinrich Schuchardt } 184e67e7249SHeinrich Schuchardt efi_st_printf("Notification count with TPL level TPL_CALLBACK: %u\n", 185e67e7249SHeinrich Schuchardt notification_count); 186e67e7249SHeinrich Schuchardt if (notification_count != 0) { 1871835f6eaSHeinrich Schuchardt efi_st_error("Suppressed timer fired\n"); 188e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1891835f6eaSHeinrich Schuchardt } 1901835f6eaSHeinrich Schuchardt /* Set 1 ms timer */ 1911835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); 1921835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1931835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 194e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1951835f6eaSHeinrich Schuchardt } 1961835f6eaSHeinrich Schuchardt /* Restore the old TPL level */ 1971835f6eaSHeinrich Schuchardt boottime->restore_tpl(TPL_APPLICATION); 1981835f6eaSHeinrich Schuchardt ret = boottime->wait_for_event(1, &event_wait, &index); 1991835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 2001835f6eaSHeinrich Schuchardt efi_st_error("Could not wait for event\n"); 201e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2021835f6eaSHeinrich Schuchardt } 203e67e7249SHeinrich Schuchardt efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", 204e67e7249SHeinrich Schuchardt notification_count); 205e67e7249SHeinrich Schuchardt if (notification_count < 1) { 2061835f6eaSHeinrich Schuchardt efi_st_error("Queued timer event did not fire\n"); 207e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2081835f6eaSHeinrich Schuchardt } 2091835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); 210abe99463SHeinrich Schuchardt if (ret != EFI_SUCCESS) { 2111835f6eaSHeinrich Schuchardt efi_st_error("Could not cancel timer\n"); 212e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2131835f6eaSHeinrich Schuchardt } 2141835f6eaSHeinrich Schuchardt 215e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 2161835f6eaSHeinrich Schuchardt } 2171835f6eaSHeinrich Schuchardt 2181835f6eaSHeinrich Schuchardt EFI_UNIT_TEST(tpl) = { 2191835f6eaSHeinrich Schuchardt .name = "task priority levels", 2201835f6eaSHeinrich Schuchardt .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 2211835f6eaSHeinrich Schuchardt .setup = setup, 2221835f6eaSHeinrich Schuchardt .execute = execute, 2231835f6eaSHeinrich Schuchardt .teardown = teardown, 2241835f6eaSHeinrich Schuchardt }; 225