efi_selftest_watchdog.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * efi_selftest_watchdog
  4. *
  5. * Copyright (c) 2017 Heinrich Schuchardt <xypron.glpk@gmx.de>
  6. *
  7. * The 'watchdog timer' unit test checks that the watchdog timer
  8. * will not cause a system restart during the timeout period after
  9. * a timer reset.
  10. *
  11. * The 'watchdog reboot' unit test checks that the watchdog timer
  12. * actually reboots the system after a timeout. The test is only
  13. * executed on explicit request. Use the following commands:
  14. *
  15. * setenv efi_selftest watchdog reboot
  16. * bootefi selftest
  17. */
  18. #include <efi_selftest.h>
  19. /*
  20. * This is the communication structure for the notification function.
  21. */
  22. struct notify_context {
  23. /* Status code returned when resetting watchdog */
  24. efi_status_t status;
  25. /* Number of invocations of the notification function */
  26. unsigned int timer_ticks;
  27. };
  28. static struct efi_event *event_notify;
  29. static struct efi_event *event_wait;
  30. static struct efi_boot_services *boottime;
  31. static struct notify_context notification_context;
  32. static bool watchdog_reset;
  33. /*
  34. * Notification function, increments the notification count if parameter
  35. * context is provided.
  36. *
  37. * @event notified event
  38. * @context pointer to the timeout
  39. */
  40. static void EFIAPI notify(struct efi_event *event, void *context)
  41. {
  42. struct notify_context *notify_context = context;
  43. efi_status_t ret = EFI_SUCCESS;
  44. if (!notify_context)
  45. return;
  46. /* Reset watchdog timer to one second */
  47. ret = boottime->set_watchdog_timer(1, 0, 0, NULL);
  48. if (ret != EFI_SUCCESS)
  49. notify_context->status = ret;
  50. /* Count number of calls */
  51. notify_context->timer_ticks++;
  52. }
  53. /*
  54. * Setup unit test.
  55. *
  56. * Create two timer events.
  57. * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT.
  58. *
  59. * @handle: handle of the loaded image
  60. * @systable: system table
  61. * @return: EFI_ST_SUCCESS for success
  62. */
  63. static int setup(const efi_handle_t handle,
  64. const struct efi_system_table *systable)
  65. {
  66. efi_status_t ret;
  67. boottime = systable->boottime;
  68. notification_context.status = EFI_SUCCESS;
  69. notification_context.timer_ticks = 0;
  70. ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL,
  71. TPL_CALLBACK, notify,
  72. (void *)&notification_context,
  73. &event_notify);
  74. if (ret != EFI_SUCCESS) {
  75. efi_st_error("could not create event\n");
  76. return EFI_ST_FAILURE;
  77. }
  78. ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT,
  79. TPL_CALLBACK, notify, NULL, &event_wait);
  80. if (ret != EFI_SUCCESS) {
  81. efi_st_error("could not create event\n");
  82. return EFI_ST_FAILURE;
  83. }
  84. return EFI_ST_SUCCESS;
  85. }
  86. /*
  87. * Execute the test resetting the watchdog in a timely manner. No reboot occurs.
  88. *
  89. * @handle: handle of the loaded image
  90. * @systable: system table
  91. * @return: EFI_ST_SUCCESS for success
  92. */
  93. static int setup_timer(const efi_handle_t handle,
  94. const struct efi_system_table *systable)
  95. {
  96. watchdog_reset = true;
  97. return setup(handle, systable);
  98. }
  99. /*
  100. * Execute the test without resetting the watchdog. A system reboot occurs.
  101. *
  102. * @handle: handle of the loaded image
  103. * @systable: system table
  104. * @return: EFI_ST_SUCCESS for success
  105. */
  106. static int setup_reboot(const efi_handle_t handle,
  107. const struct efi_system_table *systable)
  108. {
  109. watchdog_reset = false;
  110. return setup(handle, systable);
  111. }
  112. /*
  113. * Tear down unit test.
  114. *
  115. * Close the events created in setup.
  116. *
  117. * @return: EFI_ST_SUCCESS for success
  118. */
  119. static int teardown(void)
  120. {
  121. efi_status_t ret;
  122. /* Set the watchdog timer to the five minute default value */
  123. ret = boottime->set_watchdog_timer(300, 0, 0, NULL);
  124. if (ret != EFI_SUCCESS) {
  125. efi_st_error("Setting watchdog timer failed\n");
  126. return EFI_ST_FAILURE;
  127. }
  128. if (event_notify) {
  129. ret = boottime->close_event(event_notify);
  130. event_notify = NULL;
  131. if (ret != EFI_SUCCESS) {
  132. efi_st_error("Could not close event\n");
  133. return EFI_ST_FAILURE;
  134. }
  135. }
  136. if (event_wait) {
  137. ret = boottime->close_event(event_wait);
  138. event_wait = NULL;
  139. if (ret != EFI_SUCCESS) {
  140. efi_st_error("Could not close event\n");
  141. return EFI_ST_FAILURE;
  142. }
  143. }
  144. return EFI_ST_SUCCESS;
  145. }
  146. /*
  147. * Execute unit test.
  148. *
  149. * Run a 600 ms periodic timer that resets the watchdog to one second
  150. * on every timer tick.
  151. *
  152. * Run a 1350 ms single shot timer and check that the 600ms timer has
  153. * been called 2 times.
  154. *
  155. * @return: EFI_ST_SUCCESS for success
  156. */
  157. static int execute(void)
  158. {
  159. size_t index;
  160. efi_status_t ret;
  161. /* Set the watchdog timeout to one second */
  162. ret = boottime->set_watchdog_timer(1, 0, 0, NULL);
  163. if (ret != EFI_SUCCESS) {
  164. efi_st_error("Setting watchdog timer failed\n");
  165. return EFI_ST_FAILURE;
  166. }
  167. if (watchdog_reset) {
  168. /* Set 600 ms timer */
  169. ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC,
  170. 6000000);
  171. if (ret != EFI_SUCCESS) {
  172. efi_st_error("Could not set timer\n");
  173. return EFI_ST_FAILURE;
  174. }
  175. }
  176. /* Set 1350 ms timer */
  177. ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 13500000);
  178. if (ret != EFI_SUCCESS) {
  179. efi_st_error("Could not set timer\n");
  180. return EFI_ST_FAILURE;
  181. }
  182. ret = boottime->wait_for_event(1, &event_wait, &index);
  183. if (ret != EFI_SUCCESS) {
  184. efi_st_error("Could not wait for event\n");
  185. return EFI_ST_FAILURE;
  186. }
  187. if (notification_context.status != EFI_SUCCESS) {
  188. efi_st_error("Setting watchdog timer failed\n");
  189. return EFI_ST_FAILURE;
  190. }
  191. if (notification_context.timer_ticks != 2) {
  192. efi_st_error("The timer was called %u times, expected 2.\n",
  193. notification_context.timer_ticks);
  194. return EFI_ST_FAILURE;
  195. }
  196. return EFI_ST_SUCCESS;
  197. }
  198. EFI_UNIT_TEST(watchdog1) = {
  199. .name = "watchdog timer",
  200. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  201. .setup = setup_timer,
  202. .execute = execute,
  203. .teardown = teardown,
  204. };
  205. EFI_UNIT_TEST(watchdog2) = {
  206. .name = "watchdog reboot",
  207. .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
  208. .setup = setup_reboot,
  209. .execute = execute,
  210. .teardown = teardown,
  211. .on_request = true,
  212. };