1 /*
2  * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 
9 #include "esp_spi_flash.h"
10 
11 #include "soc/extmem_reg.h"
12 #include "esp_private/panic_internal.h"
13 #include "esp_private/panic_reason.h"
14 #include "riscv/rvruntime-frames.h"
15 #include "cache_err_int.h"
16 
17 #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
18 #include "esp_private/esp_memprot_internal.h"
19 #include "esp_memprot.h"
20 #endif
21 
22 #if CONFIG_ESP_SYSTEM_USE_EH_FRAME
23 #include "eh_frame_parser.h"
24 #endif
25 
26 
27 #define DIM(array) (sizeof(array)/sizeof(*array))
28 
29 /**
30  * Structure used to define a flag/bit to test in case of cache error.
31  * The message describes the cause of the error when the bit is set in
32  * a given status register.
33  */
34 typedef struct {
35     const uint32_t bit;
36     const char *msg;
37 } register_bit_t;
38 
39 /**
40  * Function to check each bits defined in the array reg_bits in the given
41  * status register. The first bit from the array to be set in the status
42  * register will have its associated message printed. This function returns
43  * true. If not bit was set in the register, it returns false.
44  * The order of the bits in the array is important as only the first bit to
45  * be set in the register will have its associated message printed.
46  */
test_and_print_register_bits(const uint32_t status,const register_bit_t * reg_bits,const uint32_t size)47 static inline bool test_and_print_register_bits(const uint32_t status,
48         const register_bit_t *reg_bits,
49         const uint32_t size)
50 {
51     /* Browse the flag/bit array and test each one with the given status
52      * register. */
53     for (int i = 0; i < size; i++) {
54         const uint32_t bit = reg_bits[i].bit;
55         if ((status & bit) == bit) {
56             /* Reason of the panic found, print the reason. */
57             panic_print_str(reg_bits[i].msg);
58             panic_print_str("\r\n");
59 
60             return true;
61         }
62     }
63 
64     /* Panic cause not found, no message was printed. */
65     return false;
66 }
67 
68 /**
69  * Function called when a cache error occurs. It prints details such as the
70  * explanation of why the panic occured.
71  */
print_cache_err_details(const void * frame)72 static inline void print_cache_err_details(const void *frame)
73 {
74     /* Define the array that contains the status (bits) to test on the register
75      * EXTMEM_CORE0_ACS_CACHE_INT_ST_REG. each bit is accompanied by a small
76      * message.
77      * The messages have been pulled from the header file where the status bit
78      * are defined. */
79     const register_bit_t core0_acs_bits[] = {
80         {
81             .bit = EXTMEM_CORE0_DBUS_WR_ICACHE_ST,
82             .msg = "dbus tried to write cache"
83         },
84         {
85             .bit = EXTMEM_CORE0_DBUS_REJECT_ST,
86             .msg = "dbus authentication failed"
87         },
88         {
89             .bit = EXTMEM_CORE0_DBUS_ACS_MSK_ICACHE_ST,
90             .msg = "access to cache while dbus or cache is disabled"
91         },
92         {
93             .bit = EXTMEM_CORE0_IBUS_REJECT_ST,
94             .msg = "ibus authentication failed"
95         },
96         {
97             .bit = EXTMEM_CORE0_IBUS_WR_ICACHE_ST,
98             .msg = "ibus tried to write cache"
99         },
100         {
101             .bit = EXTMEM_CORE0_IBUS_ACS_MSK_ICACHE_ST,
102             .msg = "access to cache while ibus or cache is disabled"
103         },
104     };
105 
106     /* Same goes for the register EXTMEM_CACHE_ILG_INT_ST_REG and its bits. */
107     const register_bit_t cache_ilg_bits[] = {
108         {
109             .bit = EXTMEM_MMU_ENTRY_FAULT_ST,
110             .msg = "MMU entry fault"
111         },
112         {
113             .bit = EXTMEM_ICACHE_PRELOAD_OP_FAULT_ST,
114             .msg = "preload configurations fault"
115         },
116         {
117             .bit = EXTMEM_ICACHE_SYNC_OP_FAULT_ST,
118             .msg = "sync configurations fault"
119         },
120     };
121 
122     /* Read the status register EXTMEM_CORE0_ACS_CACHE_INT_ST_REG. This status
123      * register is not equal to 0 when a cache access error occured. */
124     const uint32_t core0_status = REG_READ(EXTMEM_CORE0_ACS_CACHE_INT_ST_REG);
125 
126     /* If the panic is due to a cache access error, one of the bit of the
127      * register is set. Thus, this function will return true. */
128     bool handled = test_and_print_register_bits(core0_status, core0_acs_bits, DIM(core0_acs_bits));
129 
130     /* If the panic was due to a cache illegal error, the previous call returned false and this
131      * EXTMEM_CACHE_ILG_INT_ST_REG register should not me equal to 0.
132      * Check each bit of it and print the message associated if found. */
133     if (!handled) {
134         const uint32_t cache_ilg_status = REG_READ(EXTMEM_CACHE_ILG_INT_ST_REG);
135         handled = test_and_print_register_bits(cache_ilg_status, cache_ilg_bits, DIM(cache_ilg_bits));
136 
137         /* If the error was not found, print the both registers value */
138         if (!handled) {
139             panic_print_str("EXTMEM_CORE0_ACS_CACHE_INT_ST_REG = 0x");
140             panic_print_hex(core0_status);
141             panic_print_str("\r\nEXTMEM_CACHE_ILG_INT_ST_REG = 0x");
142             panic_print_hex(cache_ilg_status);
143             panic_print_str("\r\n");
144         }
145     }
146 }
147 
148 
149 /**
150  * Function called when a memory protection error occurs (PMS). It prints details such as the
151  * explanation of why the panic occured.
152  */
153 #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
154 
155 static esp_memp_intr_source_t s_memp_intr = {MEMPROT_TYPE_INVALID, -1};
156 
157 #define PRINT_MEMPROT_ERROR(err) \
158         panic_print_str("N/A (error "); \
159         panic_print_str(esp_err_to_name(err)); \
160         panic_print_str(")");
161 
print_memprot_err_details(const void * frame)162 static inline void print_memprot_err_details(const void *frame __attribute__((unused)))
163 {
164     if (s_memp_intr.mem_type == MEMPROT_TYPE_INVALID && s_memp_intr.core == -1) {
165         panic_print_str("  - no details available -\r\n");
166         return;
167     }
168 
169     //common memprot fault info
170     panic_print_str("  memory type: ");
171     panic_print_str(esp_mprot_mem_type_to_str(s_memp_intr.mem_type));
172 
173     panic_print_str("\r\n  faulting address: ");
174     void *faulting_addr;
175     esp_err_t res = esp_mprot_get_violate_addr(s_memp_intr.mem_type, &faulting_addr, &s_memp_intr.core);
176     if (res == ESP_OK) {
177         panic_print_str("0x");
178         panic_print_hex((int)faulting_addr);
179     } else {
180         PRINT_MEMPROT_ERROR(res)
181     }
182 
183     panic_print_str( "\r\n  world: ");
184     esp_mprot_pms_world_t world;
185     res = esp_mprot_get_violate_world(s_memp_intr.mem_type, &world, &s_memp_intr.core);
186     if (res == ESP_OK) {
187         panic_print_str(esp_mprot_pms_world_to_str(world));
188     } else {
189         PRINT_MEMPROT_ERROR(res)
190     }
191 
192     panic_print_str( "\r\n  operation type: ");
193     uint32_t operation;
194     res = esp_mprot_get_violate_operation(s_memp_intr.mem_type, &operation, &s_memp_intr.core);
195     if (res == ESP_OK) {
196         panic_print_str(esp_mprot_oper_type_to_str(operation));
197     } else {
198         PRINT_MEMPROT_ERROR(res)
199     }
200 
201     if (esp_mprot_has_byte_enables(s_memp_intr.mem_type)) {
202         panic_print_str("\r\n  byte-enables: " );
203         uint32_t byte_enables;
204         res = esp_mprot_get_violate_byte_enables(s_memp_intr.mem_type, &byte_enables, &s_memp_intr.core);
205         if (res == ESP_OK) {
206             panic_print_hex(byte_enables);
207         } else {
208             PRINT_MEMPROT_ERROR(res)
209         }
210     }
211 
212     panic_print_str("\r\n");
213 }
214 #endif
215 
panic_print_registers(const void * f,int core)216 void panic_print_registers(const void *f, int core)
217 {
218     uint32_t *regs = (uint32_t *)f;
219 
220     // only print ABI name
221     const char *desc[] = {
222         "MEPC    ", "RA      ", "SP      ", "GP      ", "TP      ", "T0      ", "T1      ", "T2      ",
223         "S0/FP   ", "S1      ", "A0      ", "A1      ", "A2      ", "A3      ", "A4      ", "A5      ",
224         "A6      ", "A7      ", "S2      ", "S3      ", "S4      ", "S5      ", "S6      ", "S7      ",
225         "S8      ", "S9      ", "S10     ", "S11     ", "T3      ", "T4      ", "T5      ", "T6      ",
226         "MSTATUS ", "MTVEC   ", "MCAUSE  ", "MTVAL   ", "MHARTID "
227     };
228 
229     panic_print_str("Core ");
230     panic_print_dec(((RvExcFrame *)f)->mhartid);
231     panic_print_str(" register dump:");
232 
233     for (int x = 0; x < sizeof(desc) / sizeof(desc[0]); x += 4) {
234         panic_print_str("\r\n");
235         for (int y = 0; y < 4 && x + y < sizeof(desc) / sizeof(desc[0]); y++) {
236             if (desc[x + y][0] != 0) {
237                 panic_print_str(desc[x + y]);
238                 panic_print_str(": 0x");
239                 panic_print_hex(regs[x + y]);
240                 panic_print_str("  ");
241             }
242         }
243     }
244 }
245 
246 /**
247  * This function will be called when a SoC-level panic occurs.
248  * SoC-level panics include cache errors and watchdog interrupts.
249  */
panic_soc_fill_info(void * f,panic_info_t * info)250 void panic_soc_fill_info(void *f, panic_info_t *info)
251 {
252     RvExcFrame *frame = (RvExcFrame *) f;
253 
254     /* Please keep in sync with PANIC_RSN_* defines */
255     static const char *pseudo_reason[PANIC_RSN_COUNT] = {
256         "Unknown reason",
257         "Interrupt wdt timeout on CPU0",
258 #if SOC_CPU_NUM > 1
259         "Interrupt wdt timeout on CPU1",
260 #endif
261         "Cache error",
262 #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
263         "Memory protection fault",
264 #endif
265     };
266 
267     info->reason = pseudo_reason[0];
268     info->addr = (void *) frame->mepc;
269 
270     /* The mcause has been set by the CPU when the panic occured.
271      * All SoC-level panic will call this function, thus, this register
272      * lets us know which error was triggered. */
273     if (frame->mcause == ETS_CACHEERR_INUM) {
274         /* Panic due to a cache error, multiple cache error are possible,
275          * assign function print_cache_err_details to our structure's
276          * details field. As its name states, it will give more details
277          * about why the error happened. */
278 
279         info->core = esp_cache_err_get_cpuid();
280         info->reason = pseudo_reason[PANIC_RSN_CACHEERR];
281         info->details = print_cache_err_details;
282 
283     } else if (frame->mcause == ETS_T1_WDT_INUM) {
284         /* Watchdog interrupt occured, get the core on which it happened
285          * and update the reason/message accordingly. */
286 
287         const int core = esp_cache_err_get_cpuid();
288         info->core = core;
289         info->exception = PANIC_EXCEPTION_IWDT;
290 
291 #if SOC_CPU_NUM > 1
292         _Static_assert(PANIC_RSN_INTWDT_CPU0 + 1 == PANIC_RSN_INTWDT_CPU1,
293                        "PANIC_RSN_INTWDT_CPU1 must be equal to PANIC_RSN_INTWDT_CPU0 + 1");
294 #endif
295         info->reason = pseudo_reason[PANIC_RSN_INTWDT_CPU0 + core];
296     }
297 #if CONFIG_ESP_SYSTEM_MEMPROT_FEATURE
298     else if (frame->mcause == ETS_MEMPROT_ERR_INUM) {
299         info->reason = pseudo_reason[PANIC_RSN_MEMPROT];
300         info->details = print_memprot_err_details;
301         info->core = esp_mprot_get_active_intr(&s_memp_intr) == ESP_OK ? s_memp_intr.core : -1;
302     }
303 #endif
304 }
305 
panic_arch_fill_info(void * frame,panic_info_t * info)306 void panic_arch_fill_info(void *frame, panic_info_t *info)
307 {
308     RvExcFrame *regs = (RvExcFrame *) frame;
309     info->core = 0;
310     info->exception = PANIC_EXCEPTION_FAULT;
311 
312     //Please keep in sync with PANIC_RSN_* defines
313     static const char *reason[] = {
314         "Instruction address misaligned",
315         "Instruction access fault",
316         "Illegal instruction",
317         "Breakpoint",
318         "Load address misaligned",
319         "Load access fault",
320         "Store address misaligned",
321         "Store access fault",
322         "Environment call from U-mode",
323         "Environment call from S-mode",
324         NULL,
325         "Environment call from M-mode",
326         "Instruction page fault",
327         "Load page fault",
328         NULL,
329         "Store page fault",
330     };
331 
332     if (regs->mcause < (sizeof(reason) / sizeof(reason[0]))) {
333         if (reason[regs->mcause] != NULL) {
334             info->reason = (reason[regs->mcause]);
335         }
336     }
337 
338     info->description = "Exception was unhandled.";
339 
340     info->addr = (void *) regs->mepc;
341     info->frame = &regs;
342 }
343 
panic_print_basic_backtrace(const void * frame,int core)344 static void panic_print_basic_backtrace(const void *frame, int core)
345 {
346     // Basic backtrace
347     panic_print_str("\r\nStack memory:\r\n");
348     uint32_t sp = (uint32_t)((RvExcFrame *)frame)->sp;
349     const int per_line = 8;
350     for (int x = 0; x < 1024; x += per_line * sizeof(uint32_t)) {
351         uint32_t *spp = (uint32_t *)(sp + x);
352         panic_print_hex(sp + x);
353         panic_print_str(": ");
354         for (int y = 0; y < per_line; y++) {
355             panic_print_str("0x");
356             panic_print_hex(spp[y]);
357             panic_print_str(y == per_line - 1 ? "\r\n" : " ");
358         }
359     }
360 }
361 
panic_print_backtrace(const void * frame,int core)362 void panic_print_backtrace(const void *frame, int core)
363 {
364 #if CONFIG_ESP_SYSTEM_USE_EH_FRAME
365     if (!spi_flash_cache_enabled()) {
366         panic_print_str("\r\nWarning: SPI Flash cache is disabled, cannot process eh_frame parsing. "
367                         "Falling back to basic backtrace.\r\n");
368         panic_print_basic_backtrace(frame, core);
369     } else {
370         esp_eh_frame_print_backtrace(frame);
371     }
372 #else
373     panic_print_basic_backtrace(frame, core);
374 #endif
375 }
376 
panic_get_address(const void * f)377 uint32_t panic_get_address(const void *f)
378 {
379     return ((RvExcFrame *)f)->mepc;
380 }
381 
panic_get_cause(const void * f)382 uint32_t panic_get_cause(const void *f)
383 {
384     return ((RvExcFrame *)f)->mcause;
385 }
386 
panic_set_address(void * f,uint32_t addr)387 void panic_set_address(void *f, uint32_t addr)
388 {
389     ((RvExcFrame *)f)->mepc = addr;
390 }
391