panic.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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 "gdbstub.h"
  24. /*
  25. Panic handlers; these get called when an unhandled exception occurs or the assembly-level
  26. task switching / interrupt code runs into an unrecoverable error. The default task stack
  27. overflow handler also is in here.
  28. */
  29. #if !CONFIG_FREERTOS_PANIC_SILENT_REBOOT
  30. //printf may be broken, so we fix our own printing fns...
  31. inline static void panicPutchar(char c) {
  32. while (((READ_PERI_REG(UART_STATUS_REG(0))>>UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) ;
  33. WRITE_PERI_REG(UART_FIFO_REG(0), c);
  34. }
  35. inline static void panicPutStr(const char *c) {
  36. int x=0;
  37. while (c[x]!=0) {
  38. panicPutchar(c[x]);
  39. x++;
  40. }
  41. }
  42. inline static void panicPutHex(int a) {
  43. int x;
  44. int c;
  45. panicPutchar(' ');
  46. for (x=0; x<8; x++) {
  47. c=(a>>28)&0xf;
  48. if (c<10) panicPutchar('0'+c); else panicPutchar('a'+c-10);
  49. a<<=4;
  50. }
  51. }
  52. inline static void panicPutDec(int a) {
  53. int n1, n2;
  54. n1=a%10;
  55. n2=a/10;
  56. panicPutchar(' ');
  57. if (n2==0) panicPutchar(' '); else panicPutchar(n2+'0');
  58. panicPutchar(n1+'0');
  59. }
  60. #else
  61. //No printing wanted. Stub out these functions.
  62. inline static void panicPutchar(char c) { }
  63. inline static void panicPutStr(const char *c) { }
  64. inline static void panicPutHex(int a) { }
  65. inline static void panicPutDec(int a) { }
  66. #endif
  67. void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, signed char *pcTaskName ) {
  68. panicPutStr("***ERROR*** A stack overflow in task ");
  69. panicPutStr((char*)pcTaskName);
  70. panicPutStr(" has been detected.\r\n");
  71. }
  72. static const char *edesc[]={
  73. "IllegalInstruction", "Syscall", "InstructionFetchError", "LoadStoreError",
  74. "Level1Interrupt", "Alloca", "IntegerDivideByZero", "PCValue",
  75. "Privileged", "LoadStoreAlignment", "res", "res",
  76. "InstrPDAddrError", "LoadStorePIFDataError", "InstrPIFAddrError", "LoadStorePIFAddrError",
  77. "InstTLBMiss", "InstTLBMultiHit", "InstFetchPrivilege", "res",
  78. "InstrFetchProhibited", "res", "res", "res",
  79. "LoadStoreTLBMiss", "LoadStoreTLBMultihit", "LoadStorePrivilege", "res",
  80. "LoadProhibited", "StoreProhibited", "res", "res",
  81. "Cp0Dis", "Cp1Dis", "Cp2Dis", "Cp3Dis",
  82. "Cp4Dis", "Cp5Dis", "Cp6Dis", "Cp7Dis"
  83. };
  84. void commonErrorHandler(XtExcFrame *frame);
  85. //The fact that we've panic'ed probably means the other CPU is now running wild, possibly
  86. //messing up the serial output, so we kill it here.
  87. static void haltOtherCore() {
  88. if (xPortGetCoreID()==0) {
  89. //Kill app cpu
  90. CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C1<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
  91. SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 0x21<<RTC_CNTL_SW_STALL_APPCPU_C1_S);
  92. CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C0<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
  93. SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 2<<RTC_CNTL_SW_STALL_APPCPU_C0_S);
  94. } else {
  95. //Kill pro cpu
  96. CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_PROCPU_C1<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
  97. SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, 0x21<<RTC_CNTL_SW_STALL_PROCPU_C1_S);
  98. CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_PROCPU_C0<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
  99. SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 2<<RTC_CNTL_SW_STALL_PROCPU_C0_S);
  100. }
  101. }
  102. //Returns true when a debugger is attached using JTAG.
  103. static int inOCDMode() {
  104. #if CONFIG_FREERTOS_DEBUG_OCDAWARE
  105. int dcr;
  106. int reg=0x10200C; //DSRSET register
  107. asm("rer %0,%1":"=r"(dcr):"r"(reg));
  108. return (dcr&0x1);
  109. #else
  110. return 0; //Always return no debugger is attached.
  111. #endif
  112. }
  113. void panicHandler(XtExcFrame *frame) {
  114. haltOtherCore();
  115. panicPutStr("Guru Meditation Error: Core ");
  116. panicPutDec(xPortGetCoreID());
  117. panicPutStr(" panic'ed.\r\n");
  118. if (inOCDMode()) {
  119. asm("break.n 1");
  120. }
  121. commonErrorHandler(frame);
  122. }
  123. static void setFirstBreakpoint(uint32_t pc) {
  124. asm(
  125. "wsr.ibreaka0 %0\n" \
  126. "rsr.ibreakenable a3\n" \
  127. "movi a4,1\n" \
  128. "or a4, a4, a3\n" \
  129. "wsr.ibreakenable a4\n" \
  130. ::"r"(pc):"a3","a4");
  131. }
  132. void xt_unhandled_exception(XtExcFrame *frame) {
  133. int *regs=(int*)frame;
  134. int x;
  135. haltOtherCore();
  136. panicPutStr("Guru Meditation Error of type ");
  137. x=regs[20];
  138. if (x<40) panicPutStr(edesc[x]); else panicPutStr("Unknown");
  139. panicPutStr(" occurred on core ");
  140. panicPutDec(xPortGetCoreID());
  141. if (inOCDMode()) {
  142. panicPutStr(" at pc=");
  143. panicPutHex(regs[1]);
  144. panicPutStr(". Setting bp and returning..\r\n");
  145. //Stick a hardware breakpoint on the address the handler returns to. This way, the OCD debugger
  146. //will kick in exactly at the context the error happened.
  147. setFirstBreakpoint(regs[1]);
  148. return;
  149. }
  150. panicPutStr(". Exception was unhandled.\r\n");
  151. commonErrorHandler(frame);
  152. }
  153. /*
  154. We arrive here after a panic or unhandled exception, when no OCD is detected. Dump the registers to the
  155. serial port and either jump to the gdb stub, halt the CPU or reboot.
  156. */
  157. void commonErrorHandler(XtExcFrame *frame) {
  158. int *regs=(int*)frame;
  159. int x, y;
  160. const char *sdesc[]={
  161. "PC ","PS ","A0 ","A1 ","A2 ","A3 ","A4 ","A5 ",
  162. "A6 ","A7 ","A8 ","A9 ","A10 ","A11 ","A12 ","A13 ",
  163. "A14 ","A15 ","SAR ","EXCCAUSE","EXCVADDR","LBEG ","LEND ","LCOUNT "};
  164. panicPutStr("Register dump:\r\n");
  165. for (x=0; x<24; x+=4) {
  166. for (y=0; y<4; y++) {
  167. if (sdesc[x+y][0]!=0) {
  168. panicPutStr(sdesc[x+y]);
  169. panicPutStr(": ");
  170. panicPutHex(regs[x+y+1]);
  171. panicPutStr(" ");
  172. }
  173. }
  174. panicPutStr("\r\n");
  175. }
  176. #if CONFIG_FREERTOS_PANIC_GDBSTUB
  177. panicPutStr("Entering gdb stub now.\r\n");
  178. gdbstubPanicHandler(frame);
  179. #elif CONFIG_FREERTOS_PANIC_PRINT_REBOOT || CONFIG_FREERTOS_PANIC_SILENT_REBOOT
  180. panicPutStr("Rebooting...\r\n");
  181. for (x=0; x<100; x++) ets_delay_us(1000);
  182. software_reset();
  183. #else
  184. panicPutStr("CPU halted.\r\n");
  185. while(1);
  186. #endif
  187. }
  188. void setBreakpointIfJtag(void *fn) {
  189. if (!inOCDMode()) return;
  190. setFirstBreakpoint((uint32_t)fn);
  191. }