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