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