test_panic_main.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <assert.h>
  4. #include <string.h>
  5. #include "freertos/FreeRTOS.h"
  6. #include "freertos/task.h"
  7. #include "esp_partition.h"
  8. #include "esp_flash.h"
  9. #include "esp_system.h"
  10. /* utility functions */
  11. static void die(const char* msg) __attribute__ ((noreturn));
  12. static const char* get_test_name(void);
  13. /* functions which cause an exception/panic in different ways */
  14. static void test_abort(void);
  15. static void test_abort_cache_disabled(void);
  16. static void test_int_wdt(void);
  17. static void test_task_wdt_cpu0(void);
  18. #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
  19. static void test_panic_extram_stack(void);
  20. #endif
  21. #if !CONFIG_FREERTOS_UNICORE
  22. static void test_task_wdt_cpu1(void);
  23. static void test_task_wdt_both_cpus(void);
  24. #endif
  25. static void test_storeprohibited(void);
  26. static void test_cache_error(void);
  27. static void test_int_wdt_cache_disabled(void);
  28. static void test_stack_overflow(void);
  29. static void test_illegal_instruction(void);
  30. static void test_instr_fetch_prohibited(void);
  31. static void test_ub(void);
  32. static void test_assert(void);
  33. static void test_assert_cache_disabled(void);
  34. void app_main(void)
  35. {
  36. /* Needed to allow the tick hook to set correct INT WDT timeouts */
  37. vTaskDelay(2);
  38. /* Test script sends to command over UART. Read it and determine how to proceed. */
  39. const char* test_name = get_test_name();
  40. if (test_name == NULL) {
  41. /* Nothing to do */
  42. return;
  43. }
  44. printf("Got test name: %s\n", test_name);
  45. #define HANDLE_TEST(name_) \
  46. if (strcmp(test_name, #name_) == 0) { \
  47. name_(); \
  48. die("Test function has returned"); \
  49. }
  50. HANDLE_TEST(test_abort);
  51. HANDLE_TEST(test_abort_cache_disabled);
  52. HANDLE_TEST(test_int_wdt);
  53. HANDLE_TEST(test_task_wdt_cpu0);
  54. #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
  55. HANDLE_TEST(test_panic_extram_stack);
  56. #endif
  57. #if !CONFIG_FREERTOS_UNICORE
  58. HANDLE_TEST(test_task_wdt_cpu1);
  59. HANDLE_TEST(test_task_wdt_both_cpus);
  60. #endif
  61. HANDLE_TEST(test_storeprohibited);
  62. HANDLE_TEST(test_cache_error);
  63. HANDLE_TEST(test_int_wdt_cache_disabled);
  64. HANDLE_TEST(test_stack_overflow);
  65. HANDLE_TEST(test_illegal_instruction);
  66. HANDLE_TEST(test_instr_fetch_prohibited);
  67. HANDLE_TEST(test_ub);
  68. HANDLE_TEST(test_assert);
  69. HANDLE_TEST(test_assert_cache_disabled);
  70. #undef HANDLE_TEST
  71. die("Unknown test name");
  72. }
  73. /* implementations of the test functions */
  74. static void test_abort(void)
  75. {
  76. abort();
  77. }
  78. static void IRAM_ATTR test_abort_cache_disabled(void)
  79. {
  80. esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
  81. abort();
  82. }
  83. static void test_int_wdt(void)
  84. {
  85. portDISABLE_INTERRUPTS();
  86. while (true) {
  87. ;
  88. }
  89. }
  90. static void test_task_wdt_cpu0(void)
  91. {
  92. while (true) {
  93. ;
  94. }
  95. }
  96. #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH && CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
  97. static void stack_in_extram(void* arg) {
  98. (void) arg;
  99. /* Abort instead of using a load/store prohibited to prevent a sanitize error */
  100. abort();
  101. }
  102. static void test_panic_extram_stack(void) {
  103. /* Start by initializing a Task which has a stack in external RAM */
  104. StaticTask_t handle;
  105. const uint32_t stack_size = 8192;
  106. void* stack = heap_caps_malloc(stack_size, MALLOC_CAP_SPIRAM);
  107. /* Make sure the stack is in external RAM */
  108. if (!esp_ptr_external_ram(stack)) {
  109. die("Allocated stack is not in external RAM!\n");
  110. }
  111. xTaskCreateStatic(stack_in_extram, "Task_stack_extram", stack_size, NULL, 4, (StackType_t*) stack, &handle);
  112. vTaskDelay(1000);
  113. }
  114. #endif // ESP_COREDUMP_ENABLE_TO_FLASH && SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY
  115. #if !CONFIG_FREERTOS_UNICORE
  116. static void infinite_loop(void* arg) {
  117. (void) arg;
  118. while(1) {
  119. ;
  120. }
  121. }
  122. static void test_task_wdt_cpu1(void)
  123. {
  124. xTaskCreatePinnedToCore(infinite_loop, "Infinite loop", 1024, NULL, 1, NULL, 1);
  125. while (true) {
  126. vTaskDelay(1);
  127. }
  128. }
  129. static void test_task_wdt_both_cpus(void)
  130. {
  131. xTaskCreatePinnedToCore(infinite_loop, "Infinite loop", 1024, NULL, 4, NULL, 1);
  132. /* Give some time to the task on CPU 1 to be scheduled */
  133. vTaskDelay(1);
  134. xTaskCreatePinnedToCore(infinite_loop, "Infinite loop", 1024, NULL, 4, NULL, 0);
  135. while (true) {
  136. ;
  137. }
  138. }
  139. #endif
  140. static void __attribute__((no_sanitize_undefined)) test_storeprohibited(void)
  141. {
  142. *(int*) 0x1 = 0;
  143. }
  144. static IRAM_ATTR void test_cache_error(void)
  145. {
  146. esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
  147. die("this should not be printed");
  148. }
  149. static void IRAM_ATTR test_int_wdt_cache_disabled(void)
  150. {
  151. esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
  152. portDISABLE_INTERRUPTS();
  153. while (true) {
  154. ;
  155. }
  156. }
  157. static void test_assert(void)
  158. {
  159. assert(0);
  160. }
  161. static void IRAM_ATTR test_assert_cache_disabled(void)
  162. {
  163. esp_flash_default_chip->os_func->start(esp_flash_default_chip->os_func_data);
  164. assert(0);
  165. }
  166. /**
  167. * This function overwrites the stack beginning from the valid area continuously towards and beyond
  168. * the end of the stack (stack base) of the current task.
  169. * This is to test stack protection measures like a watchpoint at the end of the stack.
  170. *
  171. * @note: This test DOES NOT write beyond the stack limit. It only writes up to exactly the limit itself.
  172. * The FreeRTOS stack protection mechanisms all trigger shortly before the end of the stack.
  173. */
  174. static void test_stack_overflow(void)
  175. {
  176. register uint32_t* sp asm("sp");
  177. TaskStatus_t pxTaskStatus;
  178. vTaskGetInfo(NULL, &pxTaskStatus, pdFALSE, pdFALSE);
  179. uint32_t *end = (uint32_t*) pxTaskStatus.pxStackBase;
  180. // offset - 20 bytes from SP in order to not corrupt the current frame.
  181. // Need to write from higher to lower addresses since the stack grows downwards and the watchpoint/canary is near
  182. // the end of the stack (lowest address).
  183. for (uint32_t* ptr = sp - 5; ptr != end; --ptr) {
  184. *ptr = 0;
  185. }
  186. // trigger a context switch to initiate checking the FreeRTOS stack canary
  187. vTaskDelay(pdMS_TO_TICKS(0));
  188. }
  189. static void test_illegal_instruction(void)
  190. {
  191. #if __XTENSA__
  192. __asm__ __volatile__("ill");
  193. #elif __riscv
  194. __asm__ __volatile__("unimp");
  195. #endif
  196. }
  197. static void test_instr_fetch_prohibited(void)
  198. {
  199. typedef void (*fptr_t)(void);
  200. volatile fptr_t fptr = (fptr_t) 0x4;
  201. fptr();
  202. }
  203. static void test_ub(void)
  204. {
  205. uint8_t stuff[1] = {rand()};
  206. printf("%d\n", stuff[rand()]);
  207. }
  208. /* implementations of the utility functions */
  209. #define BOOT_CMD_MAX_LEN (128)
  210. static const char* get_test_name(void)
  211. {
  212. static char test_name_str[BOOT_CMD_MAX_LEN] = {0};
  213. printf("Enter test name: ");
  214. fflush(stdout);
  215. /* Not using blocking fgets(stdin) here, as QEMU doesn't yet implement RX timeout interrupt,
  216. * which is required for the UART driver and blocking stdio to work.
  217. */
  218. int c = EOF;
  219. char *p = test_name_str;
  220. const char *end = test_name_str + sizeof(test_name_str) - 1;
  221. while (p < end) {
  222. c = getchar();
  223. if (c == EOF) {
  224. vTaskDelay(pdMS_TO_TICKS(10));
  225. } else if ((c == '\r' || c == '\n') && p != test_name_str) {
  226. /* terminate the line */
  227. puts("\n\r");
  228. fflush(stdout);
  229. *p = '\0';
  230. break;
  231. } else {
  232. /* echo the received character */
  233. putchar(c);
  234. fflush(stdout);
  235. /* and save it */
  236. *p = c;
  237. ++p;
  238. }
  239. }
  240. return test_name_str;
  241. }
  242. extern void esp_restart_noos(void) __attribute__ ((noreturn));
  243. static void die(const char* msg)
  244. {
  245. printf("Test error: %s\n\n", msg);
  246. fflush(stdout);
  247. usleep(1000);
  248. /* Don't use abort here as it would enter the panic handler */
  249. esp_restart_noos();
  250. }