efi_selftest_tpl.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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. #include <efi_selftest.h>
  12. static struct efi_event *event_notify;
  13. static struct efi_event *event_wait;
  14. static unsigned int counter;
  15. static struct efi_boot_services *boottime;
  16. /*
  17. * Notification function, increments a counter.
  18. *
  19. * @event notified event
  20. * @context pointer to the counter
  21. */
  22. static void EFIAPI notify(struct efi_event *event, void *context)
  23. {
  24. if (!context)
  25. return;
  26. ++*(unsigned int *)context;
  27. }
  28. /*
  29. * Setup unit test.
  30. *
  31. * Create two timer events.
  32. * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT.
  33. *
  34. * @handle: handle of the loaded image
  35. * @systable: system table
  36. */
  37. static int setup(const efi_handle_t handle,
  38. const struct efi_system_table *systable)
  39. {
  40. efi_status_t ret;
  41. boottime = systable->boottime;
  42. ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
  43. TPL_CALLBACK, notify, (void *)&counter,
  44. &event_notify);
  45. if (ret != EFI_SUCCESS) {
  46. efi_st_error("could not create event\n");
  47. return 1;
  48. }
  49. ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
  50. TPL_HIGH_LEVEL, notify, NULL, &event_wait);
  51. if (ret != EFI_SUCCESS) {
  52. efi_st_error("could not create event\n");
  53. return 1;
  54. }
  55. return 0;
  56. }
  57. /*
  58. * Tear down unit test.
  59. *
  60. * Close the events created in setup.
  61. */
  62. static int teardown(void)
  63. {
  64. efi_status_t ret;
  65. if (event_notify) {
  66. ret = boottime->close_event(event_notify);
  67. event_notify = NULL;
  68. if (ret != EFI_SUCCESS) {
  69. efi_st_error("could not close event\n");
  70. return 1;
  71. }
  72. }
  73. if (event_wait) {
  74. ret = boottime->close_event(event_wait);
  75. event_wait = NULL;
  76. if (ret != EFI_SUCCESS) {
  77. efi_st_error("could not close event\n");
  78. return 1;
  79. }
  80. }
  81. boottime->restore_tpl(TPL_APPLICATION);
  82. return 0;
  83. }
  84. /*
  85. * Execute unit test.
  86. *
  87. * Run a 10 ms periodic timer and check that it is called 10 times
  88. * while waiting for 100 ms single shot timer.
  89. *
  90. * Raise the TPL level to the level of the 10 ms timer and observe
  91. * that the notification function is not called again.
  92. *
  93. * Lower the TPL level and check that the queued notification
  94. * function is called.
  95. */
  96. static int execute(void)
  97. {
  98. unsigned long index;
  99. efi_status_t ret;
  100. UINTN old_tpl;
  101. /* Set 10 ms timer */
  102. counter = 0;
  103. ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
  104. if (ret != EFI_SUCCESS) {
  105. efi_st_error("Could not set timer\n");
  106. return 1;
  107. }
  108. /* Set 100 ms timer */
  109. ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
  110. if (ret != EFI_SUCCESS) {
  111. efi_st_error("Could not set timer\n");
  112. return 1;
  113. }
  114. index = 5;
  115. ret = boottime->wait_for_event(1, &event_wait, &index);
  116. if (ret != EFI_SUCCESS) {
  117. efi_st_error("Could not wait for event\n");
  118. return 1;
  119. }
  120. ret = boottime->check_event(event_wait);
  121. if (ret != EFI_NOT_READY) {
  122. efi_st_error("Signaled state was not cleared.\n");
  123. efi_st_printf("ret = %u\n", (unsigned int)ret);
  124. return 1;
  125. }
  126. if (index != 0) {
  127. efi_st_error("WaitForEvent returned wrong index\n");
  128. return 1;
  129. }
  130. efi_st_printf("Counter with TPL level TPL_APPLICATION: %u\n", counter);
  131. if (counter < 8 || counter > 12) {
  132. efi_st_error("Incorrect timing of events\n");
  133. return 1;
  134. }
  135. ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0);
  136. if (index != 0) {
  137. efi_st_error("Could not cancel timer\n");
  138. return 1;
  139. }
  140. /* Raise TPL level */
  141. old_tpl = boottime->raise_tpl(TPL_CALLBACK);
  142. if (old_tpl != TPL_APPLICATION) {
  143. efi_st_error("Initial TPL level was not TPL_APPLICATION");
  144. return 1;
  145. }
  146. /* Set 10 ms timer */
  147. counter = 0;
  148. ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000);
  149. if (index != 0) {
  150. efi_st_error("Could not set timer\n");
  151. return 1;
  152. }
  153. /* Set 100 ms timer */
  154. ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000);
  155. if (ret != EFI_SUCCESS) {
  156. efi_st_error("Could not set timer\n");
  157. return 1;
  158. }
  159. do {
  160. ret = boottime->check_event(event_wait);
  161. } while (ret == EFI_NOT_READY);
  162. if (ret != EFI_SUCCESS) {
  163. efi_st_error("Could not check event\n");
  164. return 1;
  165. }
  166. efi_st_printf("Counter with TPL level TPL_CALLBACK: %u\n", counter);
  167. if (counter != 0) {
  168. efi_st_error("Suppressed timer fired\n");
  169. return 1;
  170. }
  171. /* Set 1 ms timer */
  172. ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000);
  173. if (ret != EFI_SUCCESS) {
  174. efi_st_error("Could not set timer\n");
  175. return 1;
  176. }
  177. /* Restore the old TPL level */
  178. boottime->restore_tpl(TPL_APPLICATION);
  179. ret = boottime->wait_for_event(1, &event_wait, &index);
  180. if (ret != EFI_SUCCESS) {
  181. efi_st_error("Could not wait for event\n");
  182. return 1;
  183. }
  184. efi_st_printf("Counter with TPL level TPL_APPLICATION: %u\n", counter);
  185. if (counter < 1) {
  186. efi_st_error("Queued timer event did not fire\n");
  187. return 1;
  188. }
  189. ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0);
  190. if (index != 0) {
  191. efi_st_error("Could not cancel timer\n");
  192. return 1;
  193. }
  194. return 0;
  195. }
  196. EFI_UNIT_TEST(tpl) = {
  197. .name = "task priority levels",
  198. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  199. .setup = setup,
  200. .execute = execute,
  201. .teardown = teardown,
  202. };