panic_arch.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "freertos/xtensa_context.h"
  7. #include "freertos/FreeRTOS.h"
  8. #include "freertos/task.h"
  9. #include "esp_debug_helpers.h"
  10. #include "esp_private/panic_internal.h"
  11. #include "esp_private/panic_reason.h"
  12. #include "soc/soc.h"
  13. #include "esp_private/cache_err_int.h"
  14. #include "sdkconfig.h"
  15. #if !CONFIG_IDF_TARGET_ESP32
  16. #include "soc/extmem_reg.h"
  17. #include "soc/ext_mem_defs.h"
  18. #include "soc/rtc_cntl_reg.h"
  19. #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
  20. #ifdef CONFIG_IDF_TARGET_ESP32S2
  21. #include "esp32s2/memprot.h"
  22. #else
  23. #include "esp_memprot.h"
  24. #endif
  25. #endif
  26. #endif // CONFIG_IDF_TARGET_ESP32
  27. void panic_print_registers(const void *f, int core)
  28. {
  29. XtExcFrame *frame = (XtExcFrame *) f;
  30. int *regs = (int *)frame;
  31. (void)regs;
  32. const char *sdesc[] = {
  33. "PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
  34. "A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
  35. "A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
  36. };
  37. /* only dump registers for 'real' crashes, if crashing via abort()
  38. the register window is no longer useful.
  39. */
  40. panic_print_str("Core ");
  41. panic_print_dec(core);
  42. panic_print_str(" register dump:");
  43. for (int x = 0; x < 24; x += 4) {
  44. panic_print_str("\r\n");
  45. for (int y = 0; y < 4; y++) {
  46. if (sdesc[x + y][0] != 0) {
  47. panic_print_str(sdesc[x + y]);
  48. panic_print_str(": 0x");
  49. panic_print_hex(regs[x + y + 1]);
  50. panic_print_str(" ");
  51. }
  52. }
  53. }
  54. // If the core which triggers the interrupt watchpoint was in ISR context, dump the epc registers.
  55. if (xPortInterruptedFromISRContext()
  56. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  57. && ((core == 0 && frame->exccause == PANIC_RSN_INTWDT_CPU0) ||
  58. (core == 1 && frame->exccause == PANIC_RSN_INTWDT_CPU1))
  59. #endif //!CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  60. ) {
  61. panic_print_str("\r\n");
  62. uint32_t __value;
  63. panic_print_str("Core ");
  64. panic_print_dec(core);
  65. panic_print_str(" was running in ISR context:\r\n");
  66. __asm__("rsr.epc1 %0" : "=a"(__value));
  67. panic_print_str("EPC1 : 0x");
  68. panic_print_hex(__value);
  69. __asm__("rsr.epc2 %0" : "=a"(__value));
  70. panic_print_str(" EPC2 : 0x");
  71. panic_print_hex(__value);
  72. __asm__("rsr.epc3 %0" : "=a"(__value));
  73. panic_print_str(" EPC3 : 0x");
  74. panic_print_hex(__value);
  75. __asm__("rsr.epc4 %0" : "=a"(__value));
  76. panic_print_str(" EPC4 : 0x");
  77. panic_print_hex(__value);
  78. }
  79. }
  80. static void print_illegal_instruction_details(const void *f)
  81. {
  82. XtExcFrame *frame = (XtExcFrame *) f;
  83. /* Print out memory around the instruction word */
  84. uint32_t epc = frame->pc;
  85. epc = (epc & ~0x3) - 4;
  86. /* check that the address was sane */
  87. if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
  88. return;
  89. }
  90. volatile uint32_t *pepc = (uint32_t *)epc;
  91. (void)pepc;
  92. panic_print_str("Memory dump at 0x");
  93. panic_print_hex(epc);
  94. panic_print_str(": ");
  95. panic_print_hex(*pepc);
  96. panic_print_str(" ");
  97. panic_print_hex(*(pepc + 1));
  98. panic_print_str(" ");
  99. panic_print_hex(*(pepc + 2));
  100. }
  101. static void print_debug_exception_details(const void *f)
  102. {
  103. int debug_rsn;
  104. asm("rsr.debugcause %0":"=r"(debug_rsn));
  105. panic_print_str("Debug exception reason: ");
  106. if (debug_rsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
  107. panic_print_str("SingleStep ");
  108. }
  109. if (debug_rsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
  110. panic_print_str("HwBreakpoint ");
  111. }
  112. if (debug_rsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
  113. //Unlike what the ISA manual says, this core seemingly distinguishes from a DBREAK
  114. //reason caused by watchdog 0 and one caused by watchdog 1 by setting bit 8 of the
  115. //debugcause if the cause is watchpoint 1 and clearing it if it's watchpoint 0.
  116. if (debug_rsn & (1 << 8)) {
  117. #if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
  118. int core = 0;
  119. #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
  120. if (f == g_exc_frames[1]) {
  121. core = 1;
  122. }
  123. #endif
  124. const char *name = pcTaskGetName(xTaskGetCurrentTaskHandleForCPU(core));
  125. panic_print_str("Stack canary watchpoint triggered (");
  126. panic_print_str(name);
  127. panic_print_str(") ");
  128. #else
  129. panic_print_str("Watchpoint 1 triggered ");
  130. #endif
  131. } else {
  132. panic_print_str("Watchpoint 0 triggered ");
  133. }
  134. }
  135. if (debug_rsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
  136. panic_print_str("BREAK instr ");
  137. }
  138. if (debug_rsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
  139. panic_print_str("BREAKN instr ");
  140. }
  141. if (debug_rsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
  142. panic_print_str("DebugIntr ");
  143. }
  144. }
  145. #if CONFIG_IDF_TARGET_ESP32S2
  146. static inline void print_cache_err_details(const void *f)
  147. {
  148. uint32_t vaddr = 0, size = 0;
  149. uint32_t status[2];
  150. status[0] = REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG);
  151. status[1] = REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG);
  152. for (int i = 0; i < 32; i++) {
  153. switch (status[0] & BIT(i)) {
  154. case EXTMEM_IC_SYNC_SIZE_FAULT_ST:
  155. vaddr = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC0_REG);
  156. size = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC1_REG);
  157. panic_print_str("Icache sync parameter configuration error, the error address and size is 0x");
  158. panic_print_hex(vaddr);
  159. panic_print_str("(0x");
  160. panic_print_hex(size);
  161. panic_print_str(")\r\n");
  162. break;
  163. case EXTMEM_IC_PRELOAD_SIZE_FAULT_ST:
  164. vaddr = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG);
  165. size = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG);
  166. panic_print_str("Icache preload parameter configuration error, the error address and size is 0x");
  167. panic_print_hex(vaddr);
  168. panic_print_str("(0x");
  169. panic_print_hex(size);
  170. panic_print_str(")\r\n");
  171. break;
  172. case EXTMEM_ICACHE_REJECT_ST:
  173. vaddr = REG_READ(EXTMEM_PRO_ICACHE_REJECT_VADDR_REG);
  174. panic_print_str("Icache reject error occurred while accessing the address 0x");
  175. panic_print_hex(vaddr);
  176. if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  177. panic_print_str(" (invalid mmu entry)");
  178. }
  179. panic_print_str("\r\n");
  180. break;
  181. default:
  182. break;
  183. }
  184. switch (status[1] & BIT(i)) {
  185. case EXTMEM_DC_SYNC_SIZE_FAULT_ST:
  186. vaddr = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC0_REG);
  187. size = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC1_REG);
  188. panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x");
  189. panic_print_hex(vaddr);
  190. panic_print_str("(0x");
  191. panic_print_hex(size);
  192. panic_print_str(")\r\n");
  193. break;
  194. case EXTMEM_DC_PRELOAD_SIZE_FAULT_ST:
  195. vaddr = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG);
  196. size = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG);
  197. panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x");
  198. panic_print_hex(vaddr);
  199. panic_print_str("(0x");
  200. panic_print_hex(size);
  201. panic_print_str(")\r\n");
  202. break;
  203. case EXTMEM_DCACHE_WRITE_FLASH_ST:
  204. panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n");
  205. break;
  206. case EXTMEM_DCACHE_REJECT_ST:
  207. vaddr = REG_READ(EXTMEM_PRO_DCACHE_REJECT_VADDR_REG);
  208. panic_print_str("Dcache reject error occurred while accessing the address 0x");
  209. panic_print_hex(vaddr);
  210. if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  211. panic_print_str(" (invalid mmu entry)");
  212. }
  213. panic_print_str("\r\n");
  214. break;
  215. case EXTMEM_MMU_ENTRY_FAULT_ST:
  216. vaddr = REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_VADDR_REG);
  217. panic_print_str("MMU entry fault error occurred while accessing the address 0x");
  218. panic_print_hex(vaddr);
  219. if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  220. panic_print_str(" (invalid mmu entry)");
  221. }
  222. panic_print_str("\r\n");
  223. break;
  224. default:
  225. break;
  226. }
  227. }
  228. }
  229. #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
  230. #define MEMPROT_OP_INVALID 0xFFFFFFFF
  231. static inline void print_memprot_err_details(const void *f)
  232. {
  233. uint32_t *fault_addr;
  234. uint32_t op_type, op_subtype;
  235. const char *operation_type;
  236. mem_type_prot_t mem_type = esp_memprot_get_active_intr_memtype();
  237. if (mem_type != MEMPROT_NONE) {
  238. if (esp_memprot_get_fault_status(mem_type, &fault_addr, &op_type, &op_subtype) != ESP_OK) {
  239. op_type = MEMPROT_OP_INVALID;
  240. }
  241. }
  242. if (op_type == MEMPROT_OP_INVALID) {
  243. operation_type = "Unknown";
  244. fault_addr = (uint32_t *)MEMPROT_OP_INVALID;
  245. } else {
  246. if (op_type == 0) {
  247. operation_type = (mem_type == MEMPROT_IRAM0_SRAM && op_subtype == 0) ? "Instruction fetch" : "Read";
  248. } else {
  249. operation_type = "Write";
  250. }
  251. }
  252. panic_print_str(operation_type);
  253. panic_print_str(" operation at address 0x");
  254. panic_print_hex((uint32_t)fault_addr);
  255. panic_print_str(" not permitted (");
  256. panic_print_str(esp_memprot_type_to_str(mem_type));
  257. panic_print_str(")\r\n");
  258. }
  259. #endif
  260. #elif CONFIG_IDF_TARGET_ESP32S3
  261. static inline void print_cache_err_details(const void *f)
  262. {
  263. uint32_t vaddr = 0, size = 0;
  264. uint32_t status;
  265. status = REG_READ(EXTMEM_CACHE_ILG_INT_ST_REG);
  266. for (int i = 0; i < 32; i++) {
  267. switch (status & BIT(i)) {
  268. case EXTMEM_ICACHE_SYNC_OP_FAULT_ST:
  269. //TODO, which size should fetch
  270. //vaddr = REG_READ(EXTMEM_ICACHE_MEM_SYNC0_REG);
  271. //size = REG_READ(EXTMEM_ICACHE_MEM_SYNC1_REG);
  272. panic_print_str("Icache sync parameter configuration error, the error address and size is 0x");
  273. panic_print_hex(vaddr);
  274. panic_print_str("(0x");
  275. panic_print_hex(size);
  276. panic_print_str(")\r\n");
  277. break;
  278. case EXTMEM_ICACHE_PRELOAD_OP_FAULT_ST:
  279. //TODO, which size should fetch
  280. vaddr = REG_READ(EXTMEM_ICACHE_PRELOAD_ADDR_REG);
  281. size = REG_READ(EXTMEM_ICACHE_PRELOAD_SIZE_REG);
  282. panic_print_str("Icache preload parameter configuration error, the error address and size is 0x");
  283. panic_print_hex(vaddr);
  284. panic_print_str("(0x");
  285. panic_print_hex(size);
  286. panic_print_str(")\r\n");
  287. break;
  288. case EXTMEM_DCACHE_SYNC_OP_FAULT_ST:
  289. //TODO, which size should fetch
  290. //vaddr = REG_READ(EXTMEM_DCACHE_MEM_SYNC0_REG);
  291. //size = REG_READ(EXTMEM_DCACHE_MEM_SYNC1_REG);
  292. panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x");
  293. panic_print_hex(vaddr);
  294. panic_print_str("(0x");
  295. panic_print_hex(size);
  296. panic_print_str(")\r\n");
  297. break;
  298. case EXTMEM_DCACHE_PRELOAD_OP_FAULT_ST:
  299. //TODO, which size should fetch
  300. vaddr = REG_READ(EXTMEM_DCACHE_PRELOAD_ADDR_REG);
  301. size = REG_READ(EXTMEM_DCACHE_PRELOAD_SIZE_REG);
  302. panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x");
  303. panic_print_hex(vaddr);
  304. panic_print_str("(0x");
  305. panic_print_hex(size);
  306. panic_print_str(")\r\n");
  307. break;
  308. case EXTMEM_DCACHE_WRITE_FLASH_ST:
  309. panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n");
  310. break;
  311. case EXTMEM_MMU_ENTRY_FAULT_ST:
  312. vaddr = REG_READ(EXTMEM_CACHE_MMU_FAULT_VADDR_REG);
  313. panic_print_str("MMU entry fault error occurred while accessing the address 0x");
  314. panic_print_hex(vaddr);
  315. if (REG_READ(EXTMEM_CACHE_MMU_FAULT_CONTENT_REG) & MMU_INVALID) {
  316. panic_print_str(" (invalid mmu entry)");
  317. }
  318. panic_print_str("\r\n");
  319. break;
  320. default:
  321. break;
  322. }
  323. }
  324. panic_print_str("\r\n");
  325. }
  326. #endif
  327. void panic_arch_fill_info(void *f, panic_info_t *info)
  328. {
  329. XtExcFrame *frame = (XtExcFrame *) f;
  330. static const char *reason[] = {
  331. "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
  332. "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
  333. "Privileged", "LoadStoreAlignment", "res", "res",
  334. "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
  335. "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
  336. "InstrFetchProhibited", "res", "res", "res",
  337. "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
  338. "LoadProhibited", "StoreProhibited", "res", "res",
  339. "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
  340. "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
  341. };
  342. if (frame->exccause < (sizeof(reason) / sizeof(char *))) {
  343. info->reason = (reason[frame->exccause]);
  344. } else {
  345. info->reason = "Unknown";
  346. }
  347. info->description = "Exception was unhandled.";
  348. if (frame->exccause == EXCCAUSE_ILLEGAL) {
  349. info->details = print_illegal_instruction_details;
  350. }
  351. info->addr = ((void *) ((XtExcFrame *) frame)->pc);
  352. }
  353. void panic_soc_fill_info(void *f, panic_info_t *info)
  354. {
  355. // [refactor-todo] this should be in the common port panic_handler.c, once
  356. // these special exceptions are supported in there.
  357. XtExcFrame *frame = (XtExcFrame *) f;
  358. if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
  359. info->core = 0;
  360. info->exception = PANIC_EXCEPTION_IWDT;
  361. } else if (frame->exccause == PANIC_RSN_INTWDT_CPU1) {
  362. info->core = 1;
  363. info->exception = PANIC_EXCEPTION_IWDT;
  364. } else if (frame->exccause == PANIC_RSN_CACHEERR) {
  365. info->core = esp_cache_err_get_cpuid();
  366. } else {}
  367. //Please keep in sync with PANIC_RSN_* defines
  368. static const char *pseudo_reason[] = {
  369. "Unknown reason",
  370. "Unhandled debug exception",
  371. "Double exception",
  372. "Unhandled kernel exception",
  373. "Coprocessor exception",
  374. "Interrupt wdt timeout on CPU0",
  375. "Interrupt wdt timeout on CPU1",
  376. "Cache disabled but cached memory region accessed",
  377. };
  378. info->reason = pseudo_reason[0];
  379. info->description = NULL;
  380. if (frame->exccause <= PANIC_RSN_MAX) {
  381. info->reason = pseudo_reason[frame->exccause];
  382. }
  383. if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
  384. info->details = print_debug_exception_details;
  385. info->exception = PANIC_EXCEPTION_DEBUG;
  386. }
  387. //MV note: ESP32S3 PMS handling?
  388. #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
  389. if (frame->exccause == PANIC_RSN_CACHEERR) {
  390. #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE && CONFIG_IDF_TARGET_ESP32S2
  391. if ( esp_memprot_is_intr_ena_any() ) {
  392. info->details = print_memprot_err_details;
  393. info->reason = "Memory protection fault";
  394. } else
  395. #endif
  396. {
  397. info->details = print_cache_err_details;
  398. }
  399. }
  400. #endif
  401. }
  402. uint32_t panic_get_address(const void *f)
  403. {
  404. return ((XtExcFrame *)f)->pc;
  405. }
  406. uint32_t panic_get_cause(const void *f)
  407. {
  408. return ((XtExcFrame *)f)->exccause;
  409. }
  410. void panic_set_address(void *f, uint32_t addr)
  411. {
  412. ((XtExcFrame *)f)->pc = addr;
  413. }
  414. void panic_print_backtrace(const void *f, int core)
  415. {
  416. XtExcFrame *xt_frame = (XtExcFrame *) f;
  417. esp_backtrace_frame_t frame = {.pc = xt_frame->pc, .sp = xt_frame->a1, .next_pc = xt_frame->a0, .exc_frame = xt_frame};
  418. esp_backtrace_print_from_frame(100, &frame, true);
  419. }