/ components / esp_system / panic.c
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  }