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