183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 21835f6eaSHeinrich Schuchardt /* 3d8b2216cSHeinrich Schuchardt * efi_selftest_tpl 41835f6eaSHeinrich Schuchardt * 51835f6eaSHeinrich Schuchardt * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de> 61835f6eaSHeinrich Schuchardt * 71835f6eaSHeinrich Schuchardt * This unit test uses timer events to check the handling of 81835f6eaSHeinrich Schuchardt * task priority levels. 91835f6eaSHeinrich Schuchardt */ 101835f6eaSHeinrich Schuchardt 111835f6eaSHeinrich Schuchardt #include <efi_selftest.h> 121835f6eaSHeinrich Schuchardt 131835f6eaSHeinrich Schuchardt static struct efi_event *event_notify; 141835f6eaSHeinrich Schuchardt static struct efi_event *event_wait; 15e67e7249SHeinrich Schuchardt static unsigned int notification_count; 161835f6eaSHeinrich Schuchardt static struct efi_boot_services *boottime; 171835f6eaSHeinrich Schuchardt 181835f6eaSHeinrich Schuchardt /* 19e67e7249SHeinrich Schuchardt * Notification function, increments the notification count. 201835f6eaSHeinrich Schuchardt * 211835f6eaSHeinrich Schuchardt * @event notified event 22e67e7249SHeinrich Schuchardt * @context pointer to the notification count 231835f6eaSHeinrich Schuchardt */ 241835f6eaSHeinrich Schuchardt static void EFIAPI notify(struct efi_event *event, void *context) 251835f6eaSHeinrich Schuchardt { 26e67e7249SHeinrich Schuchardt unsigned int *count = context; 27e67e7249SHeinrich Schuchardt 287f8ec5b6SHeinrich Schuchardt if (count) 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 { 113f5a2a938SHeinrich Schuchardt efi_uintn_t index; 1141835f6eaSHeinrich Schuchardt efi_status_t ret; 115152cade3SHeinrich Schuchardt efi_uintn_t 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 if (notification_count < 8 || notification_count > 12) { 1476a380e5bSHeinrich Schuchardt efi_st_printf( 1486a380e5bSHeinrich Schuchardt "Notification count with TPL level TPL_APPLICATION: %u\n", 1496a380e5bSHeinrich Schuchardt notification_count); 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); 154*44e7c62aSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 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); 167*44e7c62aSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 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 if (notification_count != 0) { 1856a380e5bSHeinrich Schuchardt efi_st_printf( 1866a380e5bSHeinrich Schuchardt "Notification count with TPL level TPL_CALLBACK: %u\n", 1876a380e5bSHeinrich Schuchardt notification_count); 1881835f6eaSHeinrich Schuchardt efi_st_error("Suppressed timer fired\n"); 189e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1901835f6eaSHeinrich Schuchardt } 1911835f6eaSHeinrich Schuchardt /* Set 1 ms timer */ 1921835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); 1931835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 1941835f6eaSHeinrich Schuchardt efi_st_error("Could not set timer\n"); 195e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 1961835f6eaSHeinrich Schuchardt } 1971835f6eaSHeinrich Schuchardt /* Restore the old TPL level */ 1981835f6eaSHeinrich Schuchardt boottime->restore_tpl(TPL_APPLICATION); 1991835f6eaSHeinrich Schuchardt ret = boottime->wait_for_event(1, &event_wait, &index); 2001835f6eaSHeinrich Schuchardt if (ret != EFI_SUCCESS) { 2011835f6eaSHeinrich Schuchardt efi_st_error("Could not wait for event\n"); 202e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2031835f6eaSHeinrich Schuchardt } 204e67e7249SHeinrich Schuchardt if (notification_count < 1) { 2056a380e5bSHeinrich Schuchardt efi_st_printf( 2066a380e5bSHeinrich Schuchardt "Notification count with TPL level TPL_APPLICATION: %u\n", 2076a380e5bSHeinrich Schuchardt notification_count); 2081835f6eaSHeinrich Schuchardt efi_st_error("Queued timer event did not fire\n"); 209e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2101835f6eaSHeinrich Schuchardt } 2111835f6eaSHeinrich Schuchardt ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); 212abe99463SHeinrich Schuchardt if (ret != EFI_SUCCESS) { 2131835f6eaSHeinrich Schuchardt efi_st_error("Could not cancel timer\n"); 214e67e7249SHeinrich Schuchardt return EFI_ST_FAILURE; 2151835f6eaSHeinrich Schuchardt } 2161835f6eaSHeinrich Schuchardt 217e67e7249SHeinrich Schuchardt return EFI_ST_SUCCESS; 2181835f6eaSHeinrich Schuchardt } 2191835f6eaSHeinrich Schuchardt 2201835f6eaSHeinrich Schuchardt EFI_UNIT_TEST(tpl) = { 2211835f6eaSHeinrich Schuchardt .name = "task priority levels", 2221835f6eaSHeinrich Schuchardt .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, 2231835f6eaSHeinrich Schuchardt .setup = setup, 2241835f6eaSHeinrich Schuchardt .execute = execute, 2251835f6eaSHeinrich Schuchardt .teardown = teardown, 2261835f6eaSHeinrich Schuchardt }; 227