• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "esp_err.h"
18 #include "esp_attr.h"
19 
20 #include "esp_private/system_internal.h"
21 #include "esp_private/usb_console.h"
22 #include "esp_ota_ops.h"
23 
24 #include "soc/cpu.h"
25 #include "soc/rtc.h"
26 #include "hal/timer_hal.h"
27 #include "hal/cpu_hal.h"
28 #include "hal/wdt_types.h"
29 #include "hal/wdt_hal.h"
30 
31 #include "esp_private/panic_internal.h"
32 #include "port/panic_funcs.h"
33 
34 #include "sdkconfig.h"
35 
36 #if CONFIG_ESP32_ENABLE_COREDUMP
37 #include "esp_core_dump.h"
38 #endif
39 
40 #if CONFIG_APPTRACE_ENABLE
41 #include "esp_app_trace.h"
42 #if CONFIG_SYSVIEW_ENABLE
43 #include "SEGGER_RTT.h"
44 #endif
45 
46 #if CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO == -1
47 #define APPTRACE_ONPANIC_HOST_FLUSH_TMO   ESP_APPTRACE_TMO_INFINITE
48 #else
49 #define APPTRACE_ONPANIC_HOST_FLUSH_TMO   (1000*CONFIG_APPTRACE_ONPANIC_HOST_FLUSH_TMO)
50 #endif
51 #endif // CONFIG_APPTRACE_ENABLE
52 
53 #if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
54 #include "hal/uart_hal.h"
55 #endif
56 
57 #if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
58 #include "esp_gdbstub.h"
59 #endif
60 
61 bool g_panic_abort = false;
62 static char *s_panic_abort_details = NULL;
63 
64 static wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL};
65 
66 #if !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
67 
68 #if CONFIG_ESP_CONSOLE_UART
69 static uart_hal_context_t s_panic_uart = { .dev = CONFIG_ESP_CONSOLE_UART_NUM == 0 ? &UART0 : &UART1 };
70 
panic_print_char(const char c)71 void panic_print_char(const char c)
72 {
73     uint32_t sz = 0;
74     while(!uart_hal_get_txfifo_len(&s_panic_uart));
75     uart_hal_write_txfifo(&s_panic_uart, (uint8_t*) &c, 1, &sz);
76 }
77 #endif // CONFIG_ESP_CONSOLE_UART
78 
79 
80 #if CONFIG_ESP_CONSOLE_USB_CDC
panic_print_char(const char c)81 void panic_print_char(const char c)
82 {
83     esp_usb_console_write_buf(&c, 1);
84     /* result ignored */
85 }
86 #endif // CONFIG_ESP_CONSOLE_USB_CDC
87 
88 #if CONFIG_ESP_CONSOLE_NONE
panic_print_char(const char c)89 void panic_print_char(const char c)
90 {
91     /* no-op */
92 }
93 #endif // CONFIG_ESP_CONSOLE_NONE
94 
panic_print_str(const char * str)95 void panic_print_str(const char *str)
96 {
97     for(int i = 0; str[i] != 0; i++) {
98         panic_print_char(str[i]);
99     }
100 }
101 
panic_print_hex(int h)102 void panic_print_hex(int h)
103 {
104     int x;
105     int c;
106     // Does not print '0x', only the digits (8 digits to print)
107     for (x = 0; x < 8; x++) {
108         c = (h >> 28) & 0xf; // extract the leftmost byte
109         if (c < 10) {
110             panic_print_char('0' + c);
111         } else {
112             panic_print_char('a' + c - 10);
113         }
114         h <<= 4; // move the 2nd leftmost byte to the left, to be extracted next
115     }
116 }
117 
panic_print_dec(int d)118 void panic_print_dec(int d)
119 {
120     // can print at most 2 digits!
121     int n1, n2;
122     n1 = d % 10; // extract ones digit
123     n2 = d / 10; // extract tens digit
124     if (n2 == 0) {
125         panic_print_char(' ');
126     } else {
127         panic_print_char(n2 + '0');
128     }
129     panic_print_char(n1 + '0');
130 }
131 #endif  // CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
132 
133 /*
134   If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
135   an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
136   the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
137   all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
138   one second.
139 
140   We have to do this before we do anything that might cause issues in the WDT interrupt handlers,
141   for example stalling the other core on ESP32 may cause the ESP32_ECO3_CACHE_LOCK_FIX
142   handler to get stuck.
143 */
esp_panic_handler_reconfigure_wdts(void)144 void esp_panic_handler_reconfigure_wdts(void)
145 {
146     wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
147     wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
148 
149     //Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
150     //Reconfigure TWDT (Timer Group 0)
151     wdt_hal_init(&wdt0_context, WDT_MWDT0, MWDT0_TICK_PRESCALER, false); //Prescaler: wdt counts in ticks of TG0_WDT_TICK_US
152     wdt_hal_write_protect_disable(&wdt0_context);
153     wdt_hal_config_stage(&wdt0_context, 0, 1000*1000/MWDT0_TICKS_PER_US, WDT_STAGE_ACTION_RESET_SYSTEM);   //1 second before reset
154     wdt_hal_enable(&wdt0_context);
155     wdt_hal_write_protect_enable(&wdt0_context);
156 
157     //Disable IWDT (Timer Group 1)
158     wdt_hal_write_protect_disable(&wdt1_context);
159     wdt_hal_disable(&wdt1_context);
160     wdt_hal_write_protect_enable(&wdt1_context);
161 }
162 
163 /*
164   This disables all the watchdogs for when we call the gdbstub.
165 */
disable_all_wdts(void)166 static inline void disable_all_wdts(void)
167 {
168     wdt_hal_context_t wdt0_context = {.inst = WDT_MWDT0, .mwdt_dev = &TIMERG0};
169     wdt_hal_context_t wdt1_context = {.inst = WDT_MWDT1, .mwdt_dev = &TIMERG1};
170 
171     //Todo: Refactor to use Interrupt or Task Watchdog API, and a system level WDT context
172     //Task WDT is the Main Watchdog Timer of Timer Group 0
173     wdt_hal_write_protect_disable(&wdt0_context);
174     wdt_hal_disable(&wdt0_context);
175     wdt_hal_write_protect_enable(&wdt0_context);
176 
177     //Interupt WDT is the Main Watchdog Timer of Timer Group 1
178     wdt_hal_write_protect_disable(&wdt1_context);
179     wdt_hal_disable(&wdt1_context);
180     wdt_hal_write_protect_enable(&wdt1_context);
181 }
182 
print_abort_details(const void * f)183 static void print_abort_details(const void *f)
184 {
185     panic_print_str(s_panic_abort_details);
186 }
187 
188 // Control arrives from chip-specific panic handler, environment prepared for
189 // the 'main' logic of panic handling. This means that chip-specific stuff have
190 // already been done, and panic_info_t has been filled.
esp_panic_handler(panic_info_t * info)191 void esp_panic_handler(panic_info_t *info)
192 {
193     // The port-level panic handler has already called this, but call it again
194     // to reset the TG0WDT period
195     esp_panic_handler_reconfigure_wdts();
196 
197     // If the exception was due to an abort, override some of the panic info
198     if (g_panic_abort) {
199         info->description = NULL;
200         info->details = s_panic_abort_details ? print_abort_details : NULL;
201         info->reason = NULL;
202         info->exception = PANIC_EXCEPTION_ABORT;
203     }
204 
205    /*
206      * For any supported chip, the panic handler prints the contents of panic_info_t in the following format:
207      *
208      *
209      * Guru Meditation Error: Core <core> (<exception>). <description>
210      * <details>
211      *
212      * <state>
213      *
214      * <elf_info>
215      *
216      *
217      * ----------------------------------------------------------------------------------------
218      * core - core where exception was triggered
219      * exception - what kind of exception occured
220      * description - a short description regarding the exception that occured
221      * details - more details about the exception
222      * state - processor state like register contents, and backtrace
223      * elf_info - details about the image currently running
224      *
225      * NULL fields in panic_info_t are not printed.
226      *
227      * */
228     if (info->reason) {
229         panic_print_str("Guru Meditation Error: Core ");
230         panic_print_dec(info->core);
231         panic_print_str(" panic'ed (");
232         panic_print_str(info->reason);
233         panic_print_str("). ");
234     }
235 
236     if (info->description) {
237         panic_print_str(info->description);
238     }
239 
240     panic_print_str("\r\n");
241 
242     PANIC_INFO_DUMP(info, details);
243 
244     panic_print_str("\r\n");
245 
246     // If on-chip-debugger is attached, and system is configured to be aware of this,
247     // then only print up to details. Users should be able to probe for the other information
248     // in debug mode.
249     if (esp_cpu_in_ocd_debug_mode()) {
250         panic_print_str("Setting breakpoint at 0x");
251         panic_print_hex((uint32_t)info->addr);
252         panic_print_str(" and returning...\r\n");
253         disable_all_wdts();
254 #if CONFIG_APPTRACE_ENABLE
255 #if CONFIG_SYSVIEW_ENABLE
256         SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
257 #else
258         esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH,
259                                   APPTRACE_ONPANIC_HOST_FLUSH_TMO);
260 #endif
261 #endif
262 
263         cpu_hal_set_breakpoint(0, info->addr); // use breakpoint 0
264         return;
265     }
266 
267     // start panic WDT to restart system if we hang in this handler
268     if (!wdt_hal_is_enabled(&rtc_wdt_ctx)) {
269         wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
270         uint32_t stage_timeout_ticks = (uint32_t)(7000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL);
271         wdt_hal_write_protect_disable(&rtc_wdt_ctx);
272         wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_SYSTEM);
273         // 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
274         // @ 115200 UART speed it will take more than 6 sec to print them out.
275         wdt_hal_enable(&rtc_wdt_ctx);
276         wdt_hal_write_protect_enable(&rtc_wdt_ctx);
277 
278     }
279 
280     esp_panic_handler_reconfigure_wdts(); // Restart WDT again
281 
282     PANIC_INFO_DUMP(info, state);
283     panic_print_str("\r\n");
284 
285     panic_print_str("\r\nELF file SHA256: ");
286     char sha256_buf[65];
287     esp_ota_get_app_elf_sha256(sha256_buf, sizeof(sha256_buf));
288     panic_print_str(sha256_buf);
289     panic_print_str("\r\n");
290 
291     panic_print_str("\r\n");
292 
293 #if CONFIG_APPTRACE_ENABLE
294     disable_all_wdts();
295 #if CONFIG_SYSVIEW_ENABLE
296     SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
297 #else
298     esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH,
299                               APPTRACE_ONPANIC_HOST_FLUSH_TMO);
300 #endif
301     esp_panic_handler_reconfigure_wdts(); // restore WDT config
302 #endif // CONFIG_APPTRACE_ENABLE
303 
304 #if CONFIG_ESP_SYSTEM_PANIC_GDBSTUB
305     disable_all_wdts();
306     wdt_hal_write_protect_disable(&rtc_wdt_ctx);
307     wdt_hal_disable(&rtc_wdt_ctx);
308     wdt_hal_write_protect_enable(&rtc_wdt_ctx);
309     panic_print_str("Entering gdb stub now.\r\n");
310     esp_gdbstub_panic_handler((esp_gdbstub_frame_t*)info->frame);
311 #else
312 #if CONFIG_ESP_COREDUMP_ENABLE
313     static bool s_dumping_core;
314     if (s_dumping_core) {
315         panic_print_str("Re-entered core dump! Exception happened during core dump!\r\n");
316     } else {
317         disable_all_wdts();
318         s_dumping_core = true;
319 #if CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH
320         esp_core_dump_to_flash(info);
321 #endif
322 #if CONFIG_ESP_COREDUMP_ENABLE_TO_UART && !CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
323         esp_core_dump_to_uart(info);
324 #endif
325         s_dumping_core = false;
326 
327         esp_panic_handler_reconfigure_wdts();
328     }
329 #endif /* CONFIG_ESP_COREDUMP_ENABLE */
330     wdt_hal_write_protect_disable(&rtc_wdt_ctx);
331     wdt_hal_disable(&rtc_wdt_ctx);
332     wdt_hal_write_protect_enable(&rtc_wdt_ctx);
333 #if CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT
334 
335     if (esp_reset_reason_get_hint() == ESP_RST_UNKNOWN) {
336         switch (info->exception)
337         {
338         case PANIC_EXCEPTION_IWDT:
339             esp_reset_reason_set_hint(ESP_RST_INT_WDT);
340             break;
341         case PANIC_EXCEPTION_TWDT:
342             esp_reset_reason_set_hint(ESP_RST_TASK_WDT);
343             break;
344         case PANIC_EXCEPTION_ABORT:
345         case PANIC_EXCEPTION_FAULT:
346         default:
347             esp_reset_reason_set_hint(ESP_RST_PANIC);
348             break; // do not touch the previously set reset reason hint
349         }
350     }
351 
352     panic_print_str("Rebooting...\r\n");
353     panic_restart();
354 #else
355     disable_all_wdts();
356     panic_print_str("CPU halted.\r\n");
357     while (1);
358 #endif /* CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT || CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT */
359 #endif /* CONFIG_ESP_SYSTEM_PANIC_GDBSTUB */
360 }
361 
362 
panic_abort(const char * details)363 void __attribute__((noreturn)) panic_abort(const char *details)
364 {
365     g_panic_abort = true;
366     s_panic_abort_details = (char*) details;
367 
368 #if CONFIG_APPTRACE_ENABLE
369 #if CONFIG_SYSVIEW_ENABLE
370     SEGGER_RTT_ESP32_FlushNoLock(CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH, APPTRACE_ONPANIC_HOST_FLUSH_TMO);
371 #else
372     esp_apptrace_flush_nolock(ESP_APPTRACE_DEST_TRAX, CONFIG_APPTRACE_POSTMORTEM_FLUSH_THRESH,
373                               APPTRACE_ONPANIC_HOST_FLUSH_TMO);
374 #endif
375 #endif
376 
377     *((int *) 0) = 0; // NOLINT(clang-analyzer-core.NullDereference) should be an invalid operation on targets
378     while(1);
379 }
380 
381 /* Weak versions of reset reason hint functions.
382  * If these weren't provided, reset reason code would be linked into the app
383  * even if the app never called esp_reset_reason().
384  */
esp_reset_reason_set_hint(esp_reset_reason_t hint)385 void IRAM_ATTR __attribute__((weak)) esp_reset_reason_set_hint(esp_reset_reason_t hint)
386 {
387 }
388 
esp_reset_reason_get_hint(void)389 esp_reset_reason_t IRAM_ATTR  __attribute__((weak)) esp_reset_reason_get_hint(void)
390 {
391     return ESP_RST_UNKNOWN;
392 }
393