panic.c 6.6 KB

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