1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
32
33
34
35
36
37
38
39
40
45
46
49
50
51
52
53
64
65
66
67
68
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
131
134
135
136
137
138
139
140
141
142
143
147
148
149
150
151
152
153
154
155
158
159
162
165
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
205
206
207
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
232
233
234
235
236
237
240
241
242
243
244
245
246
247
250
251
252
254
255
256
257
258
259
260
261
262
263
264
265
266
267
272
273
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
345
346
347
348
349
350
353
354
355
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
384
385
386
387
390
391
392
393
394
399
404
405
406
407
408
409
410
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
438
439
443
444
445
446
447
459
460
461
465
466
470
471
475
476
482
483
/* ... */
#include "xtensa_context.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_debug_helpers.h"
#include "esp_private/panic_internal.h"
#include "esp_private/panic_reason.h"
#include "soc/soc.h"
#include "esp_private/cache_err_int.h"
#include "sdkconfig.h"9 includes
#if !CONFIG_IDF_TARGET_ESP32
#include "soc/extmem_reg.h"
#include "soc/ext_mem_defs.h"
#include "soc/rtc_cntl_reg.h"
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
#ifdef CONFIG_IDF_TARGET_ESP32S2
#include "esp32s2/memprot.h"
#else
#include "esp_memprot.h"
#endif/* ... */
#endif/* ... */
#endif
void panic_print_registers(const void *f, int core)
{
XtExcFrame *frame = (XtExcFrame *) f;
int *regs = (int *)frame;
(void)regs;
const char *sdesc[] = {
"PC ", "PS ", "A0 ", "A1 ", "A2 ", "A3 ", "A4 ", "A5 ",
"A6 ", "A7 ", "A8 ", "A9 ", "A10 ", "A11 ", "A12 ", "A13 ",
"A14 ", "A15 ", "SAR ", "EXCCAUSE", "EXCVADDR", "LBEG ", "LEND ", "LCOUNT "
}{...};
/* ... */
panic_print_str("Core ");
panic_print_dec(core);
panic_print_str(" register dump:");
for (int x = 0; x < 24; x += 4) {
panic_print_str("\r\n");
for (int y = 0; y < 4; y++) {
if (sdesc[x + y][0] != 0) {
panic_print_str(sdesc[x + y]);
panic_print_str(": 0x");
panic_print_hex(regs[x + y + 1]);
panic_print_str(" ");
}{...}
}{...}
}{...}
if (xPortInterruptedFromISRContext()
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
&& ((core == 0 && frame->exccause == PANIC_RSN_INTWDT_CPU0) ||
(core == 1 && frame->exccause == PANIC_RSN_INTWDT_CPU1))/* ... */
#endif
) {
panic_print_str("\r\n");
uint32_t __value;
panic_print_str("Core ");
panic_print_dec(core);
panic_print_str(" was running in ISR context:\r\n");
__asm__("rsr.epc1 %0" : "=a"(__value));
panic_print_str("EPC1 : 0x");
panic_print_hex(__value);
__asm__("rsr.epc2 %0" : "=a"(__value));
panic_print_str(" EPC2 : 0x");
panic_print_hex(__value);
__asm__("rsr.epc3 %0" : "=a"(__value));
panic_print_str(" EPC3 : 0x");
panic_print_hex(__value);
__asm__("rsr.epc4 %0" : "=a"(__value));
panic_print_str(" EPC4 : 0x");
panic_print_hex(__value);
}{...}
}{ ... }
static void print_illegal_instruction_details(const void *f)
{
XtExcFrame *frame = (XtExcFrame *) f;
uint32_t epc = frame->pc;
epc = (epc & ~0x3) - 4;
if (epc < SOC_IROM_MASK_LOW || epc >= SOC_IROM_HIGH) {
return;
}{...}
volatile uint32_t *pepc = (uint32_t *)epc;
(void)pepc;
panic_print_str("Memory dump at 0x");
panic_print_hex(epc);
panic_print_str(": ");
panic_print_hex(*pepc);
panic_print_str(" ");
panic_print_hex(*(pepc + 1));
panic_print_str(" ");
panic_print_hex(*(pepc + 2));
}{ ... }
static void print_debug_exception_details(const void *f)
{
int debug_rsn;
asm("rsr.debugcause %0":"=r"(debug_rsn));
panic_print_str("Debug exception reason: ");
if (debug_rsn & XCHAL_DEBUGCAUSE_ICOUNT_MASK) {
panic_print_str("SingleStep ");
}{...}
if (debug_rsn & XCHAL_DEBUGCAUSE_IBREAK_MASK) {
panic_print_str("HwBreakpoint ");
}{...}
if (debug_rsn & XCHAL_DEBUGCAUSE_DBREAK_MASK) {
if (debug_rsn & (1 << 8)) {
#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
int core = 0;
#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE
if (f == g_exc_frames[1]) {
core = 1;
}{...}
#endif/* ... */
const char *name = pcTaskGetName(xTaskGetCurrentTaskHandleForCore(core));
panic_print_str("Stack canary watchpoint triggered (");
panic_print_str(name);
panic_print_str(") ");/* ... */
#else
panic_print_str("Watchpoint 1 triggered ");
#endif
}{...} else {
panic_print_str("Watchpoint 0 triggered ");
}{...}
}{...}
if (debug_rsn & XCHAL_DEBUGCAUSE_BREAK_MASK) {
panic_print_str("BREAK instr ");
}{...}
if (debug_rsn & XCHAL_DEBUGCAUSE_BREAKN_MASK) {
panic_print_str("BREAKN instr ");
}{...}
if (debug_rsn & XCHAL_DEBUGCAUSE_DEBUGINT_MASK) {
panic_print_str("DebugIntr ");
}{...}
}{ ... }
#if CONFIG_IDF_TARGET_ESP32S2
static inline void print_cache_err_details(const void *f)
{
uint32_t vaddr = 0, size = 0;
uint32_t status[2];
status[0] = REG_READ(EXTMEM_CACHE_DBG_STATUS0_REG);
status[1] = REG_READ(EXTMEM_CACHE_DBG_STATUS1_REG);
for (int i = 0; i < 32; i++) {
switch (status[0] & BIT(i)) {
case EXTMEM_IC_SYNC_SIZE_FAULT_ST:
vaddr = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC0_REG);
size = REG_READ(EXTMEM_PRO_ICACHE_MEM_SYNC1_REG);
panic_print_str("Icache sync parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_IC_PRELOAD_SIZE_FAULT_ST:
vaddr = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_ADDR_REG);
size = REG_READ(EXTMEM_PRO_ICACHE_PRELOAD_SIZE_REG);
panic_print_str("Icache preload parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_ICACHE_REJECT_ST:
vaddr = REG_READ(EXTMEM_PRO_ICACHE_REJECT_VADDR_REG);
panic_print_str("Icache reject error occurred while accessing the address 0x");
panic_print_hex(vaddr);
if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) {
panic_print_str(" (invalid mmu entry)");
}{...}
panic_print_str("\r\n");
break;...
default:
break;...
}{...}
switch (status[1] & BIT(i)) {
case EXTMEM_DC_SYNC_SIZE_FAULT_ST:
vaddr = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC0_REG);
size = REG_READ(EXTMEM_PRO_DCACHE_MEM_SYNC1_REG);
panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_DC_PRELOAD_SIZE_FAULT_ST:
vaddr = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_ADDR_REG);
size = REG_READ(EXTMEM_PRO_DCACHE_PRELOAD_SIZE_REG);
panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_DCACHE_WRITE_FLASH_ST:
panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n");
break;...
case EXTMEM_DCACHE_REJECT_ST:
vaddr = REG_READ(EXTMEM_PRO_DCACHE_REJECT_VADDR_REG);
panic_print_str("Dcache reject error occurred while accessing the address 0x");
panic_print_hex(vaddr);
if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) {
panic_print_str(" (invalid mmu entry)");
}{...}
panic_print_str("\r\n");
break;...
case EXTMEM_MMU_ENTRY_FAULT_ST:
vaddr = REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_VADDR_REG);
panic_print_str("MMU entry fault error occurred while accessing the address 0x");
panic_print_hex(vaddr);
if (REG_READ(EXTMEM_PRO_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) {
panic_print_str(" (invalid mmu entry)");
}{...}
panic_print_str("\r\n");
break;...
default:
break;...
}{...}
}{...}
}{...}
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
#define MEMPROT_OP_INVALID 0xFFFFFFFF
static inline void print_memprot_err_details(const void *f)
{
uint32_t *fault_addr;
uint32_t op_type = MEMPROT_OP_INVALID, op_subtype;
const char *operation_type;
mem_type_prot_t mem_type = esp_memprot_get_active_intr_memtype();
if (mem_type != MEMPROT_NONE) {
if (esp_memprot_get_fault_status(mem_type, &fault_addr, &op_type, &op_subtype) != ESP_OK) {
op_type = MEMPROT_OP_INVALID;
}{...}
}{...}
if (op_type == MEMPROT_OP_INVALID) {
operation_type = "Unknown";
fault_addr = (uint32_t *)MEMPROT_OP_INVALID;
}{...} else {
if (op_type == 0) {
operation_type = (mem_type == MEMPROT_IRAM0_SRAM && op_subtype == 0) ? "Instruction fetch" : "Read";
}{...} else {
operation_type = "Write";
}{...}
}{...}
panic_print_str(operation_type);
panic_print_str(" operation at address 0x");
panic_print_hex((uint32_t)fault_addr);
panic_print_str(" not permitted (");
panic_print_str(esp_memprot_type_to_str(mem_type));
panic_print_str(")\r\n");
}{...}
/* ... */#endif
/* ... */
#elif CONFIG_IDF_TARGET_ESP32S3
static inline void print_cache_err_details(const void *f)
{
uint32_t vaddr = 0, size = 0;
uint32_t status;
status = REG_READ(EXTMEM_CACHE_ILG_INT_ST_REG);
for (int i = 0; i < 32; i++) {
switch (status & BIT(i)) {
case EXTMEM_ICACHE_SYNC_OP_FAULT_ST:
panic_print_str("Icache sync parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_ICACHE_PRELOAD_OP_FAULT_ST:
vaddr = REG_READ(EXTMEM_ICACHE_PRELOAD_ADDR_REG);
size = REG_READ(EXTMEM_ICACHE_PRELOAD_SIZE_REG);
panic_print_str("Icache preload parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_DCACHE_SYNC_OP_FAULT_ST:
panic_print_str("Dcache sync parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_DCACHE_PRELOAD_OP_FAULT_ST:
vaddr = REG_READ(EXTMEM_DCACHE_PRELOAD_ADDR_REG);
size = REG_READ(EXTMEM_DCACHE_PRELOAD_SIZE_REG);
panic_print_str("Dcache preload parameter configuration error, the error address and size is 0x");
panic_print_hex(vaddr);
panic_print_str("(0x");
panic_print_hex(size);
panic_print_str(")\r\n");
break;...
case EXTMEM_DCACHE_WRITE_FLASH_ST:
panic_print_str("Write back error occurred while dcache tries to write back to flash\r\n");
panic_print_str("The following backtrace may not indicate the code that caused Cache invalid access\r\n");
break;...
case EXTMEM_MMU_ENTRY_FAULT_ST:
vaddr = REG_READ(EXTMEM_CACHE_MMU_FAULT_VADDR_REG);
panic_print_str("MMU entry fault error occurred while accessing the address 0x");
panic_print_hex(vaddr);
if (REG_READ(EXTMEM_CACHE_MMU_FAULT_CONTENT_REG) & SOC_MMU_INVALID) {
panic_print_str(" (invalid mmu entry)");
}{...}
panic_print_str("\r\n");
break;...
default:
break;...
}{...}
}{...}
panic_print_str("\r\n");
}{...}
/* ... */#endif
void panic_arch_fill_info(void *f, panic_info_t *info)
{
XtExcFrame *frame = (XtExcFrame *) f;
static const char *reason[] = {
"IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
"Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
"Privileged", "LoadStoreAlignment", "res", "res",
"InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
"InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
"InstrFetchProhibited", "res", "res", "res",
"LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
"LoadProhibited", "StoreProhibited", "res", "res",
"Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
"Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
}{...};
if (frame->exccause < (sizeof(reason) / sizeof(char *))) {
info->reason = (reason[frame->exccause]);
}{...} else {
info->reason = "Unknown";
}{...}
info->description = "Exception was unhandled.";
if (frame->exccause == EXCCAUSE_ILLEGAL) {
info->details = print_illegal_instruction_details;
}{...}
info->addr = ((void *)((XtExcFrame *) frame)->pc);
}{ ... }
/* ... */
bool panic_soc_check_pseudo_cause(void *f, panic_info_t *info)
{
return false;
}{ ... }
void panic_soc_fill_info(void *f, panic_info_t *info)
{
XtExcFrame *frame = (XtExcFrame *) f;
if (frame->exccause == PANIC_RSN_INTWDT_CPU0) {
info->core = 0;
info->exception = PANIC_EXCEPTION_IWDT;
}{...} else if (frame->exccause == PANIC_RSN_INTWDT_CPU1) {
info->core = 1;
info->exception = PANIC_EXCEPTION_IWDT;
}{...} else if (frame->exccause == PANIC_RSN_CACHEERR) {
info->core = esp_cache_err_get_cpuid();
}{...} else {}
static const char *pseudo_reason[] = {
"Unknown reason",
"Unhandled debug exception",
"Double exception",
"Unhandled kernel exception",
"Coprocessor exception",
"Interrupt wdt timeout on CPU0",
"Interrupt wdt timeout on CPU1",
"Cache disabled but cached memory region accessed",
}{...};
info->reason = pseudo_reason[0];
info->description = NULL;
if (frame->exccause <= PANIC_RSN_MAX) {
info->reason = pseudo_reason[frame->exccause];
}{...}
if (frame->exccause == PANIC_RSN_DEBUGEXCEPTION) {
info->details = print_debug_exception_details;
info->exception = PANIC_EXCEPTION_DEBUG;
}{...}
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
if (frame->exccause == PANIC_RSN_CACHEERR) {
#if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE && CONFIG_IDF_TARGET_ESP32S2
if (esp_memprot_is_intr_ena_any()) {
info->details = print_memprot_err_details;
info->reason = "Memory protection fault";
}{...} else
#endif
{
info->details = print_cache_err_details;
}{...}
}{...}
#endif/* ... */
}{ ... }
uint32_t panic_get_address(const void *f)
{
return ((XtExcFrame *)f)->pc;
}{ ... }
uint32_t panic_get_cause(const void *f)
{
return ((XtExcFrame *)f)->exccause;
}{ ... }
void panic_set_address(void *f, uint32_t addr)
{
((XtExcFrame *)f)->pc = addr;
}{ ... }
void panic_print_backtrace(const void *f, int core)
{
XtExcFrame *xt_frame = (XtExcFrame *) f;
esp_backtrace_frame_t frame = {.pc = xt_frame->pc, .sp = xt_frame->a1, .next_pc = xt_frame->a0, .exc_frame = xt_frame};
esp_backtrace_print_from_frame(100, &frame, true);
}{ ... }
void panic_prepare_frame_from_ctx(void* frame)
{
(void)frame;
}{ ... }