panic_handler.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include <stdlib.h>
  14. #include "freertos/xtensa_context.h"
  15. #include "freertos/FreeRTOS.h"
  16. #include "freertos/task.h"
  17. #include "esp_spi_flash.h"
  18. #include "esp_private/panic_reason.h"
  19. #include "esp_private/system_internal.h"
  20. #include "esp_debug_helpers.h"
  21. #include "soc/soc_memory_layout.h"
  22. #include "soc/cpu.h"
  23. #include "soc/soc_caps.h"
  24. #include "soc/rtc.h"
  25. #include "hal/soc_hal.h"
  26. #include "hal/cpu_hal.h"
  27. #include "hal/wdt_types.h"
  28. #include "hal/wdt_hal.h"
  29. #include "sdkconfig.h"
  30. #if CONFIG_IDF_TARGET_ESP32
  31. #include "esp32/cache_err_int.h"
  32. #include "esp32/dport_access.h"
  33. #include "esp32/rom/uart.h"
  34. #elif CONFIG_IDF_TARGET_ESP32S2
  35. #include "esp32s2/cache_err_int.h"
  36. #include "esp32s2/rom/uart.h"
  37. #include "soc/extmem_reg.h"
  38. #include "soc/cache_memory.h"
  39. #include "soc/rtc_cntl_reg.h"
  40. #endif
  41. #include "panic_internal.h"
  42. extern void esp_panic_handler(panic_info_t*);
  43. static wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
  44. static XtExcFrame* xt_exc_frames[SOC_CPU_CORES_NUM] = {NULL};
  45. /*
  46. Panic handlers; these get called when an unhandled exception occurs or the assembly-level
  47. task switching / interrupt code runs into an unrecoverable error. The default task stack
  48. overflow handler and abort handler are also in here.
  49. */
  50. /*
  51. Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
  52. */
  53. static void print_illegal_instruction_details(const void* f)
  54. {
  55. XtExcFrame* frame = (XtExcFrame*) f;
  56. /* Print out memory around the instruction word */
  57. uint32_t epc = frame->pc;
  58. epc = (epc & ~0x3) - 4;
  59. /* check that the address was sane */
  60. if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
  61. return;
  62. }
  63. volatile uint32_t* pepc = (uint32_t*)epc;
  64. panic_print_str("Memory dump at 0x");
  65. panic_print_hex(epc);
  66. panic_print_str(": ");
  67. panic_print_hex(*pepc);
  68. panic_print_str(" ");
  69. panic_print_hex(*(pepc + 1));
  70. panic_print_str(" ");
  71. panic_print_hex(*(pepc + 2));
  72. }
  73. static void print_debug_exception_details(const void* f)
  74. {
  75. int debug_rsn;
  76. asm("rsr.debugcause %0":"=r"(debug_rsn));
  77. panic_print_str("Debug exception reason: ");
  78. if (debug_rsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
  79. panic_print_str("SingleStep ");
  80. }
  81. if (debug_rsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
  82. panic_print_str("HwBreakpoint ");
  83. }
  84. if (debug_rsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
  85. //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
  86. //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
  87. //debugcause if the cause is watchpoint 1 and clearing it if it's watchpoint 0.
  88. if (debug_rsn & (1 << 8)) {
  89. #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
  90. int core = 0;
  91. #if !CONFIG_FREERTOS_UNICORE
  92. if (f == xt_exc_frames[1]) {
  93. core = 1;
  94. }
  95. #endif
  96. const char *name = pcTaskGetTaskName(xTaskGetCurrentTaskHandleForCPU(core));
  97. panic_print_str("Stack canary watchpoint triggered (");
  98. panic_print_str(name);
  99. panic_print_str(") ");
  100. #else
  101. panic_print_str("Watchpoint 1 triggered ");
  102. #endif
  103. } else {
  104. panic_print_str("Watchpoint 0 triggered ");
  105. }
  106. }
  107. if (debug_rsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
  108. panic_print_str("BREAK instr ");
  109. }
  110. if (debug_rsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
  111. panic_print_str("BREAKN instr ");
  112. }
  113. if (debug_rsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
  114. panic_print_str("DebugIntr ");
  115. }
  116. }
  117. static void print_backtrace_entry(uint32_t pc, uint32_t sp)
  118. {
  119. panic_print_str("0x");
  120. panic_print_hex(pc);
  121. panic_print_str(":0x");
  122. panic_print_hex(sp);
  123. }
  124. static void print_backtrace(const void* f, int core)
  125. {
  126. XtExcFrame *frame = (XtExcFrame*) f;
  127. int depth = 100;
  128. //Initialize stk_frame with first frame of stack
  129. esp_backtrace_frame_t stk_frame = {.pc = frame->pc, .sp = frame->a1, .next_pc = frame->a0};
  130. panic_print_str("\r\nBacktrace:");
  131. print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
  132. //Check if first frame is valid
  133. bool corrupted = !(esp_stack_ptr_is_sane(stk_frame.sp) &&
  134. esp_ptr_executable((void*)esp_cpu_process_stack_pc(stk_frame.pc)));
  135. uint32_t i = ((depth <= 0) ? INT32_MAX : depth) - 1; //Account for stack frame that's already printed
  136. while (i-- > 0 && stk_frame.next_pc != 0 && !corrupted) {
  137. if (!esp_backtrace_get_next_frame(&stk_frame)) { //Get next stack frame
  138. corrupted = true;
  139. }
  140. panic_print_str(" ");
  141. print_backtrace_entry(esp_cpu_process_stack_pc(stk_frame.pc), stk_frame.sp);
  142. }
  143. //Print backtrace termination marker
  144. if (corrupted) {
  145. panic_print_str(" |<-CORRUPTED");
  146. } else if (stk_frame.next_pc != 0) { //Backtrace continues
  147. panic_print_str(" |<-CONTINUES");
  148. }
  149. }
  150. static void print_registers(const void *f, int core)
  151. {
  152. XtExcFrame* frame = (XtExcFrame*) f;
  153. int *regs = (int *)frame;
  154. int x, y;
  155. const char *sdesc[] = {
  156. "PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
  157. "A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
  158. "A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
  159. };
  160. /* only dump registers for 'real' crashes, if crashing via abort()
  161. the register window is no longer useful.
  162. */
  163. panic_print_str("Core ");
  164. panic_print_dec(core);
  165. panic_print_str(" register dump:");
  166. for (x = 0; x < 24; x += 4) {
  167. panic_print_str("\r\n");
  168. for (y = 0; y < 4; y++) {
  169. if (sdesc[x + y][0] != 0) {
  170. panic_print_str(sdesc[x + y]);
  171. panic_print_str(": 0x");
  172. panic_print_hex(regs[x + y + 1]);
  173. panic_print_str(" ");
  174. }
  175. }
  176. }
  177. // If the core which triggers the interrupt watchpoint was in ISR context, dump the epc registers.
  178. if (xPortInterruptedFromISRContext()
  179. #if !CONFIG_FREERTOS_UNICORE
  180. && ((core == 0 && frame->exccause == PANIC_RSN_INTWDT_CPU0) ||
  181. (core == 1 && frame->exccause == PANIC_RSN_INTWDT_CPU1))
  182. #endif //!CONFIG_FREERTOS_UNICORE
  183. ) {
  184. panic_print_str("\r\n");
  185. uint32_t __value;
  186. panic_print_str("Core ");
  187. panic_print_dec(core);
  188. panic_print_str(" was running in ISR context:\r\n");
  189. __asm__("rsr.epc1 %0" : "=a"(__value));
  190. panic_print_str("EPC1 : 0x");
  191. panic_print_hex(__value);
  192. __asm__("rsr.epc2 %0" : "=a"(__value));
  193. panic_print_str(" EPC2 : 0x");
  194. panic_print_hex(__value);
  195. __asm__("rsr.epc3 %0" : "=a"(__value));
  196. panic_print_str(" EPC3 : 0x");
  197. panic_print_hex(__value);
  198. __asm__("rsr.epc4 %0" : "=a"(__value));
  199. panic_print_str(" EPC4 : 0x");
  200. panic_print_hex(__value);
  201. }
  202. }
  203. static void print_state_for_core(const void *f, int core)
  204. {
  205. if (!g_panic_abort) {
  206. print_registers(f, core);
  207. panic_print_str("\r\n");
  208. }
  209. print_backtrace(f, core);
  210. }
  211. static void print_state(const void* f)
  212. {
  213. #if !CONFIG_FREERTOS_UNICORE
  214. int err_core = f == xt_exc_frames[0] ? 0 : 1;
  215. #else
  216. int err_core = 0;
  217. #endif
  218. print_state_for_core(f, err_core);
  219. panic_print_str("\r\n");
  220. #if !CONFIG_FREERTOS_UNICORE
  221. // If there are other frame info, print them as well
  222. for (int i = 0; i < SOC_CPU_CORES_NUM; i++) {
  223. // `f` is the frame for the offending core, see note above.
  224. if (err_core != i && xt_exc_frames[i] != NULL) {
  225. print_state_for_core(xt_exc_frames[i], i);
  226. panic_print_str("\r\n");
  227. }
  228. }
  229. #endif
  230. }
  231. #if CONFIG_IDF_TARGET_ESP32S2
  232. static inline void print_cache_err_details(const void* f)
  233. {
  234. uint32_t vaddr = 0, size = 0;
  235. uint32_t status[2];
  236. status[0] = REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG);
  237. status[1] = REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG);
  238. for (int i = 0; i < 32; i++) {
  239. switch (status[0] & BIT(i)) {
  240. case EXTMEM_IC_SYNC_SIZE_FAULT_ST:
  241. vaddr = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC0_REG);
  242. size = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC1_REG);
  243. panic_print_str("Icache sync parameter configuration error, the error address and size is 0x");
  244. panic_print_hex(vaddr);
  245. panic_print_str("(0x");
  246. panic_print_hex(size);
  247. panic_print_str(")\r\n");
  248. break;
  249. case EXTMEM_IC_PRELOAD_SIZE_FAULT_ST:
  250. vaddr = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG);
  251. size = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG);
  252. panic_print_str("Icache preload parameter configuration error, the error address and size is 0x");
  253. panic_print_hex(vaddr);
  254. panic_print_str("(0x");
  255. panic_print_hex(size);
  256. panic_print_str(")\r\n");
  257. break;
  258. case EXTMEM_ICACHE_REJECT_ST:
  259. vaddr = REG_READ(EXTMEM_PRO_ICACHE_REJECT_VADDR_REG);
  260. panic_print_str("Icache reject error occurred while accessing the address 0x");
  261. panic_print_hex(vaddr);
  262. if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  263. panic_print_str(" (invalid mmu entry)");
  264. }
  265. panic_print_str("\r\n");
  266. break;
  267. default:
  268. break;
  269. }
  270. switch (status[1] & BIT(i)) {
  271. case EXTMEM_DC_SYNC_SIZE_FAULT_ST:
  272. vaddr = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC0_REG);
  273. size = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC1_REG);
  274. panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x");
  275. panic_print_hex(vaddr);
  276. panic_print_str("(0x");
  277. panic_print_hex(size);
  278. panic_print_str(")\r\n");
  279. break;
  280. case EXTMEM_DC_PRELOAD_SIZE_FAULT_ST:
  281. vaddr = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG);
  282. size = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG);
  283. panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x");
  284. panic_print_hex(vaddr);
  285. panic_print_str("(0x");
  286. panic_print_hex(size);
  287. panic_print_str(")\r\n");
  288. break;
  289. case EXTMEM_DCACHE_WRITE_FLASH_ST:
  290. panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n");
  291. break;
  292. case EXTMEM_DCACHE_REJECT_ST:
  293. vaddr = REG_READ(EXTMEM_PRO_DCACHE_REJECT_VADDR_REG);
  294. panic_print_str("Dcache reject error occurred while accessing the address 0x");
  295. panic_print_hex(vaddr);
  296. if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  297. panic_print_str(" (invalid mmu entry)");
  298. }
  299. panic_print_str("\r\n");
  300. break;
  301. case EXTMEM_MMU_ENTRY_FAULT_ST:
  302. vaddr = REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_VADDR_REG);
  303. panic_print_str("MMU entry fault error occurred while accessing the address 0x");
  304. panic_print_hex(vaddr);
  305. if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  306. panic_print_str(" (invalid mmu entry)");
  307. }
  308. panic_print_str("\r\n");
  309. break;
  310. default:
  311. break;
  312. }
  313. }
  314. }
  315. #endif
  316. static void frame_to_panic_info(XtExcFrame *frame, panic_info_t* info, bool pseudo_excause)
  317. {
  318. info->core = cpu_hal_get_core_id();
  319. info->exception = PANIC_EXCEPTION_FAULT;
  320. info->details = NULL;
  321. if (pseudo_excause) {
  322. if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
  323. info->core = 0;
  324. info->exception = PANIC_EXCEPTION_IWDT;
  325. } else if (frame->exccause == PANIC_RSN_INTWDT_CPU1) {
  326. info->core = 1;
  327. info->exception = PANIC_EXCEPTION_IWDT;
  328. } else if (frame->exccause == PANIC_RSN_CACHEERR) {
  329. info->core = esp_cache_err_get_cpuid();
  330. } else {}
  331. //Please keep in sync with PANIC_RSN_* defines
  332. static const char *pseudo_reason[] = {
  333. "Unknown reason",
  334. "Unhandled debug exception",
  335. "Double exception",
  336. "Unhandled kernel exception",
  337. "Coprocessor exception",
  338. "Interrupt wdt timeout on CPU0",
  339. "Interrupt wdt timeout on CPU1",
  340. #if CONFIG_IDF_TARGET_ESP32
  341. "Cache disabled but cached memory region accessed",
  342. #elif CONFIG_IDF_TARGET_ESP32S2
  343. "Cache exception",
  344. #endif
  345. };
  346. info->reason = pseudo_reason[0];
  347. info->description = NULL;
  348. if (frame->exccause <= PANIC_RSN_MAX) {
  349. info->reason = pseudo_reason[frame->exccause];
  350. }
  351. if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
  352. info->details = print_debug_exception_details;
  353. info->exception = PANIC_EXCEPTION_DEBUG;
  354. }
  355. #if CONFIG_IDF_TARGET_ESP32S2
  356. if(frame->exccause == PANIC_RSN_CACHEERR) {
  357. info->details = print_cache_err_details;
  358. }
  359. #endif
  360. } else {
  361. static const char *reason[] = {
  362. "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
  363. "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
  364. "Privileged", "LoadStoreAlignment", "res", "res",
  365. "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
  366. "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
  367. "InstrFetchProhibited", "res", "res", "res",
  368. "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
  369. "LoadProhibited", "StoreProhibited", "res", "res",
  370. "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
  371. "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
  372. };
  373. if (frame->exccause < (sizeof(reason) / sizeof(char *))) {
  374. info->reason = (reason[frame->exccause]);
  375. } else {
  376. info->reason = "Unknown";
  377. }
  378. info->description = "Exception was unhandled.";
  379. if (info->reason == reason[0]) {
  380. info->details = print_illegal_instruction_details;
  381. }
  382. }
  383. info->state = print_state;
  384. info->addr = ((void*) ((XtExcFrame*) frame)->pc);
  385. info->frame = frame;
  386. }
  387. static void panic_handler(XtExcFrame *frame, bool pseudo_excause)
  388. {
  389. /*
  390. * Setup environment and perform necessary architecture/chip specific
  391. * steps here prior to the system panic handler.
  392. * */
  393. int core_id = cpu_hal_get_core_id();
  394. // If multiple cores arrive at panic handler, save frames for all of them
  395. xt_exc_frames[core_id] = frame;
  396. #if !CONFIG_FREERTOS_UNICORE
  397. // These are cases where both CPUs both go into panic handler. The following code ensures
  398. // only one core proceeds to the system panic handler.
  399. if (pseudo_excause) {
  400. #define BUSY_WAIT_IF_TRUE(b) { if (b) while(1); }
  401. // For WDT expiry, pause the non-offending core - offending core handles panic
  402. BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU0 && core_id == 1);
  403. BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_INTWDT_CPU1 && core_id == 0);
  404. // For cache error, pause the non-offending core - offending core handles panic
  405. BUSY_WAIT_IF_TRUE(frame->exccause == PANIC_RSN_CACHEERR && core_id != esp_cache_err_get_cpuid());
  406. }
  407. ets_delay_us(1);
  408. SOC_HAL_STALL_OTHER_CORES();
  409. #endif
  410. #if CONFIG_IDF_TARGET_ESP32
  411. esp_dport_access_int_abort();
  412. #endif
  413. #if !CONFIG_ESP_PANIC_HANDLER_IRAM
  414. // Re-enable CPU cache for current CPU if it was disabled
  415. if (!spi_flash_cache_enabled()) {
  416. spi_flash_enable_cache(core_id);
  417. panic_print_str("Re-enable cpu cache.\r\n");
  418. }
  419. #endif
  420. if (esp_cpu_in_ocd_debug_mode()) {
  421. if (frame->exccause == PANIC_RSN_INTWDT_CPU0 ||
  422. frame->exccause == PANIC_RSN_INTWDT_CPU1) {
  423. wdt_hal_write_protect_disable(&wdt0_context);
  424. wdt_hal_handle_intr(&wdt0_context);
  425. wdt_hal_write_protect_enable(&wdt0_context);
  426. }
  427. }
  428. // Convert architecture exception frame into abstracted panic info
  429. panic_info_t info;
  430. frame_to_panic_info(frame, &info, pseudo_excause);
  431. // Call the system panic handler
  432. esp_panic_handler(&info);
  433. }
  434. void panicHandler(XtExcFrame *frame)
  435. {
  436. // This panic handler gets called for when the double exception vector,
  437. // kernel exception vector gets used; as well as handling interrupt-based
  438. // faults cache error, wdt expiry. EXCAUSE register gets written with
  439. // one of PANIC_RSN_* values.
  440. panic_handler(frame, true);
  441. }
  442. void xt_unhandled_exception(XtExcFrame *frame)
  443. {
  444. panic_handler(frame, false);
  445. }
  446. static __attribute__((noreturn)) void esp_digital_reset(void)
  447. {
  448. // make sure all the panic handler output is sent from UART FIFO
  449. uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM);
  450. // switch to XTAL (otherwise we will keep running from the PLL)
  451. rtc_clk_cpu_freq_set_xtal();
  452. #if CONFIG_IDF_TARGET_ESP32
  453. esp_cpu_unstall(PRO_CPU_NUM);
  454. #endif
  455. // reset the digital part
  456. SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_SYS_RST);
  457. while (true) {
  458. ;
  459. }
  460. }
  461. void __attribute__((noreturn)) panic_restart(void)
  462. {
  463. // If resetting because of a cache error, reset the digital part
  464. // Make sure that the reset reason is not a generic panic reason as well on ESP32S2,
  465. // as esp_cache_err_get_cpuid always returns PRO_CPU_NUM
  466. if (esp_cache_err_get_cpuid() != -1 && esp_reset_reason_get_hint() != ESP_RST_PANIC) {
  467. esp_digital_reset();
  468. } else {
  469. esp_restart_noos();
  470. }
  471. }