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