panic.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include <stdlib.h>
  14. #include <xtensa/config/core.h>
  15. #include "rom/rtc.h"
  16. #include "freertos/FreeRTOS.h"
  17. #include "freertos/task.h"
  18. #include "freertos/xtensa_api.h"
  19. #include "soc/uart_reg.h"
  20. #include "soc/io_mux_reg.h"
  21. #include "soc/dport_reg.h"
  22. #include "soc/rtc_cntl_reg.h"
  23. #include "soc/timer_group_struct.h"
  24. #include "soc/timer_group_reg.h"
  25. #include "soc/cpu.h"
  26. #include "esp_gdbstub.h"
  27. #include "esp_panic.h"
  28. #include "esp_attr.h"
  29. /*
  30. Panic handlers; these get called when an unhandled exception occurs or the assembly-level
  31. task switching / interrupt code runs into an unrecoverable error. The default task stack
  32. overflow handler also is in here.
  33. */
  34. /*
  35. Note: The linker script will put everything in this file in IRAM/DRAM, so it also works with flash cache disabled.
  36. */
  37. #if !CONFIG_ESP32_PANIC_SILENT_REBOOT
  38. //printf may be broken, so we fix our own printing fns...
  39. inline static void panicPutchar(char c) {
  40. while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
  41. WRITE_PERI_REG(UART_FIFO_REG(0), c);
  42. }
  43. inline static void panicPutStr(const char *c) {
  44. int x=0;
  45. while (c[x]!=0) {
  46. panicPutchar(c[x]);
  47. x++;
  48. }
  49. }
  50. inline static void panicPutHex(int a) {
  51. int x;
  52. int c;
  53. panicPutchar(' ');
  54. for (x=0; x<8; x++) {
  55. c=(a>>28)&0xf;
  56. if (c<10) panicPutchar('0'+c); else panicPutchar('a'+c-10);
  57. a<<=4;
  58. }
  59. }
  60. inline static void panicPutDec(int a) {
  61. int n1, n2;
  62. n1=a%10;
  63. n2=a/10;
  64. panicPutchar(' ');
  65. if (n2==0) panicPutchar(' '); else panicPutchar(n2+'0');
  66. panicPutchar(n1+'0');
  67. }
  68. #else
  69. //No printing wanted. Stub out these functions.
  70. inline static void panicPutchar(char c) { }
  71. inline static void panicPutStr(const char *c) { }
  72. inline static void panicPutHex(int a) { }
  73. inline static void panicPutDec(int a) { }
  74. #endif
  75. void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
  76. panicPutStr("***ERROR*** A stack overflow in task ");
  77. panicPutStr((char*)pcTaskName);
  78. panicPutStr(" has been detected.\r\n");
  79. configASSERT(0);
  80. }
  81. static const char *edesc[]={
  82. "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
  83. "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
  84. "Privileged", "LoadStoreAlignment", "res", "res",
  85. "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
  86. "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
  87. "InstrFetchProhibited", "res", "res", "res",
  88. "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
  89. "LoadProhibited", "StoreProhibited", "res", "res",
  90. "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
  91. "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
  92. };
  93. void commonErrorHandler(XtExcFrame *frame);
  94. //The fact that we've panic'ed probably means the other CPU is now running wild, possibly
  95. //messing up the serial output, so we stall it here.
  96. static void haltOtherCore()
  97. {
  98. esp_cpu_stall( xPortGetCoreID() == 0 ? 1 : 0 );
  99. }
  100. //Returns true when a debugger is attached using JTAG.
  101. static int inOCDMode() {
  102. #if CONFIG_ESP32_DEBUG_OCDAWARE
  103. int dcr;
  104. int reg=0x10200C; //DSRSET register
  105. asm("rer %0,%1":"=r"(dcr):"r"(reg));
  106. return (dcr&0x1);
  107. #else
  108. return 0; //Always return no debugger is attached.
  109. #endif
  110. }
  111. void panicHandler(XtExcFrame *frame) {
  112. int *regs=(int*)frame;
  113. //Please keep in sync with PANIC_RSN_* defines
  114. const char *reasons[]={
  115. "Unknown reason",
  116. "Unhandled debug exception",
  117. "Double exception",
  118. "Unhandled kernel exception",
  119. "Coprocessor exception",
  120. "Interrupt wdt timeout on CPU0",
  121. "Interrupt wdt timeout on CPU1",
  122. };
  123. const char *reason=reasons[0];
  124. //The panic reason is stored in the EXCCAUSE register.
  125. if (regs[20]<=PANIC_RSN_MAX) reason=reasons[regs[20]];
  126. haltOtherCore();
  127. panicPutStr("Guru Meditation Error: Core ");
  128. panicPutDec(xPortGetCoreID());
  129. panicPutStr(" panic'ed (");
  130. panicPutStr(reason);
  131. panicPutStr(")\r\n");
  132. if (inOCDMode()) {
  133. asm("break.n 1");
  134. }
  135. commonErrorHandler(frame);
  136. }
  137. static void setFirstBreakpoint(uint32_t pc) {
  138. asm(
  139. "wsr.ibreaka0 %0\n" \
  140. "rsr.ibreakenable a3\n" \
  141. "movi a4,1\n" \
  142. "or a4, a4, a3\n" \
  143. "wsr.ibreakenable a4\n" \
  144. ::"r"(pc):"a3","a4");
  145. }
  146. void xt_unhandled_exception(XtExcFrame *frame) {
  147. int *regs=(int*)frame;
  148. int x;
  149. haltOtherCore();
  150. panicPutStr("Guru Meditation Error of type ");
  151. x=regs[20];
  152. if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown");
  153. panicPutStr(" occurred on core ");
  154. panicPutDec(xPortGetCoreID());
  155. if (inOCDMode()) {
  156. panicPutStr(" at pc=");
  157. panicPutHex(regs[1]);
  158. panicPutStr(". Setting bp and returning..\r\n");
  159. //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
  160. //will kick in exactly at the context the error happened.
  161. setFirstBreakpoint(regs[1]);
  162. return;
  163. }
  164. panicPutStr(". Exception was unhandled.\r\n");
  165. commonErrorHandler(frame);
  166. }
  167. /*
  168. If watchdogs are enabled, the panic handler runs the risk of getting aborted pre-emptively because
  169. an overzealous watchdog decides to reset it. On the other hand, if we disable all watchdogs, we run
  170. the risk of somehow halting in the panic handler and not resetting. That is why this routine kills
  171. all watchdogs except the timer group 0 watchdog, and it reconfigures that to reset the chip after
  172. one second.
  173. */
  174. static void reconfigureAllWdts() {
  175. TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
  176. TIMERG0.wdt_feed=1;
  177. TIMERG0.wdt_config0.sys_reset_length=7; //3.2uS
  178. TIMERG0.wdt_config0.cpu_reset_length=7; //3.2uS
  179. TIMERG0.wdt_config0.stg0=TIMG_WDT_STG_SEL_RESET_SYSTEM; //1st stage timeout: reset system
  180. TIMERG0.wdt_config1.clk_prescale=80*500; //Prescaler: wdt counts in ticks of 0.5mS
  181. TIMERG0.wdt_config2=2000; //1 second before reset
  182. TIMERG0.wdt_config0.en=1;
  183. TIMERG0.wdt_wprotect=0;
  184. //Disable wdt 1
  185. TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
  186. TIMERG1.wdt_config0.en=0;
  187. TIMERG1.wdt_wprotect=0;
  188. }
  189. #if CONFIG_ESP32_PANIC_GDBSTUB || CONFIG_ESP32_PANIC_PRINT_HALT
  190. /*
  191. This disables all the watchdogs for when we call the gdbstub.
  192. */
  193. static void disableAllWdts() {
  194. TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
  195. TIMERG0.wdt_config0.en=0;
  196. TIMERG0.wdt_wprotect=0;
  197. TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE;
  198. TIMERG1.wdt_config0.en=0;
  199. TIMERG0.wdt_wprotect=0;
  200. }
  201. #endif
  202. /*
  203. We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
  204. serial port and either jump to the gdb stub, halt the CPU or reboot.
  205. */
  206. void commonErrorHandler(XtExcFrame *frame) {
  207. int *regs=(int*)frame;
  208. int x, y;
  209. const char *sdesc[]={
  210. "PC ","PS ","A0 ","A1 ","A2 ","A3 ","A4 ","A5 ",
  211. "A6 ","A7 ","A8 ","A9 ","A10 ","A11 ","A12 ","A13 ",
  212. "A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "};
  213. //Feed the watchdogs, so they will give us time to print out debug info
  214. reconfigureAllWdts();
  215. panicPutStr("Register dump:\r\n");
  216. for (x=0; x<24; x+=4) {
  217. for (y=0; y<4; y++) {
  218. if (sdesc[x+y][0]!=0) {
  219. panicPutStr(sdesc[x+y]);
  220. panicPutStr(": ");
  221. panicPutHex(regs[x+y+1]);
  222. panicPutStr(" ");
  223. }
  224. }
  225. panicPutStr("\r\n");
  226. }
  227. #if CONFIG_ESP32_PANIC_GDBSTUB
  228. disableAllWdts();
  229. panicPutStr("Entering gdb stub now.\r\n");
  230. esp_gdbstub_panic_handler(frame);
  231. #elif CONFIG_ESP32_PANIC_PRINT_REBOOT || CONFIG_ESP32_PANIC_SILENT_REBOOT
  232. panicPutStr("Rebooting...\r\n");
  233. for (x=0; x<100; x++) ets_delay_us(1000);
  234. software_reset();
  235. #else
  236. disableAllWdts();
  237. panicPutStr("CPU halted.\r\n");
  238. while(1);
  239. #endif
  240. }
  241. void esp_set_breakpoint_if_jtag(void *fn) {
  242. if (!inOCDMode()) return;
  243. setFirstBreakpoint((uint32_t)fn);
  244. }