diff --git a/components/esp8266/source/panic.c b/components/esp8266/source/panic.c new file mode 100644 index 00000000..9289221d --- /dev/null +++ b/components/esp8266/source/panic.c @@ -0,0 +1,133 @@ +// Copyright 2018 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "c_types.h" + +#include "esp8266/ets_sys.h" +#include "esp8266/eagle_soc.h" +#include "esp8266/uart_register.h" + +/* + * Todo: panic output UART ID, we may add it to 'kconfig' to select target UART. + */ +#define PANIC_UART 0 + +/* + * @brief output a character + * + * @param c a character + * + * @return none + */ +static IRAM_ATTR void panit_putc(char c) +{ + while (1) { + uint32_t fifo_cnt = READ_PERI_REG(UART_STATUS(PANIC_UART)) & (UART_TXFIFO_CNT << UART_TXFIFO_CNT_S); + + if ((fifo_cnt >> UART_TXFIFO_CNT_S & UART_TXFIFO_CNT) < 126) + break; + } + + WRITE_PERI_REG(UART_FIFO(PANIC_UART) , c); +} + +/* + * @brief output a left-aligned string + * + * @param s string pointer + * @param left_aligned left-aligned bytes + * + * @return none + */ +static IRAM_ATTR void panic_puts(const char *s, int left_aligned) +{ + int bytes = left_aligned - strlen(s); + + while (bytes-- > 0) + panit_putc(' '); + + while (*s) + panit_putc(*s++); +} + +/* + * @brief output a hex value string of 32-bites data + * + * @param hex 32-bites data + * + * @return none + */ +static IRAM_ATTR void panic_puthex(int hex) +{ + char buf[8]; + int bytes = 0; + + while (bytes < 8) { + char c = (uint32_t)hex % 16; + + if (c < 10) + c = c + '0'; + else + c = c - 10 + 'a'; + + buf[bytes++] = c; + hex >>= 4; + } + + while (bytes) + panit_putc(buf[--bytes]); +} + +/* + * @brief output xtensa register value map when crash + * + * @param frame xtensa register value map pointer + * + * @return none + */ +void IRAM_ATTR panicHandler(void *frame) +{ + int *regs = (int *)frame; + int x, y; + const char *sdesc[] = { + "PC", "PS", "A0", "A1", + "A2", "A3", "A4", "A5", + "A6", "A7", "A8", "A9", + "A10", "A11", "A12", "A13", + "A14", "A15", "SAR", "EXCCAUSE" + }; + + /* NMI can interrupt exception. */ + ETS_INTR_LOCK(); + + for (x = 0; x < 20; x += 4) { + for (y = 0; y < 4; y++) { + panic_puts(sdesc[x + y], 8); + panic_puts(": 0x", 0); + panic_puthex(regs[x + y + 1]); + panic_puts(" ", 0); + } + panit_putc('\n'); + } + + /* + * Todo: add more option to select here to 'Kconfig': + * 1. blocking + * 2. restart + * 3. GBD break + */ + while (1); +} diff --git a/components/esp8266/source/xtensa_vectors.S b/components/esp8266/source/xtensa_vectors.S index cedfa0ae..6dfc0df2 100644 --- a/components/esp8266/source/xtensa_vectors.S +++ b/components/esp8266/source/xtensa_vectors.S @@ -122,6 +122,9 @@ STRUCT_END(HighPriFrame) #define PRI_N_STACK_SIZE 512 /* default to 1 kB stack for each level-N handling */ #define PRI_N_STACK_SIZE2 256 /* default to 1 kB stack for each level-N handling */ +#define PANIC_STK_FRMSZ 0x60 + + .global panicHandler // Allocate save area and stack: // (must use .bss, not .comm, because the subsequent .set does not work otherwise) @@ -669,6 +672,8 @@ Double exceptions are not a normal occurrence. They indicate a bug of some kind. .align 4 .literal_position _DoubleExceptionVector: + wsr a0, EXCSAVE_1 + j _xt_ext_panic #if XCHAL_HAVE_DEBUG break 1, 4 /* unhandled double exception */ @@ -692,9 +697,9 @@ Kernel Exception (including Level 1 Interrupt from kernel mode). .align 4 .literal_position _KernelExceptionVector: - wsr a0, EXCSAVE_1 /* preserve a0 */ - call0 _xt_kernel_exc /* kernel exception handler */ + j _xt_ext_panic + /* never returns here - call0 is used as a jump (see note at top) */ .end literal_prefix @@ -768,7 +773,11 @@ _xt_user_exc: #endif beqi a0, EXCCAUSE_SYSCALL, _xt_to_syscall_exc beqi a0, EXCCAUSE_LOAD_STORE_ERROR, LoadStoreErrorHandler + beqi a0, EXCCAUSE_LEVEL1INTERRUPT, _xt_user_entry1 + j _xt_ext_panic + +_xt_user_entry1: /* Allocate interrupt stack frame and save minimal context. */ mov a0, sp /* sp == a1 */ addi sp, sp, -XT_STK_FRMSZ /* allocate interrupt stack frame */ @@ -1395,3 +1404,41 @@ nmi_rfi: rfi XCHAL_NMILEVEL #endif #endif /* NMI */ + + .global _xt_ext_panic + .type _xt_ext_panic, @function + .align 4 + .literal_position +_xt_ext_panic: + /* Allocate exception frame and save minimal context. */ + mov a0, sp + addi sp, sp, -XT_STK_FRMSZ + s32i a0, sp, XT_STK_A1 + + rsr a0, PS /* save interruptee's PS */ + s32i a0, sp, XT_STK_PS + rsr a0, EPC_1 /* save interruptee's PC */ + s32i a0, sp, XT_STK_PC + + s32i a12, sp, XT_STK_A12 /* _xt_context_save requires A12- */ + s32i a13, sp, XT_STK_A13 /* A13 to have already been saved */ + s32i a14, sp, XT_STK_A14 + s32i a15, sp, XT_STK_A15 + call0 _xt_context_save + + /* Save exc cause and vaddr into exception frame */ + rsr a0, EXCCAUSE + s32i a0, sp, XT_STK_EXCCAUSE + + /* _xt_context_save seems to save the current a0, but we need the interuptees a0. Fix this. */ + rsr a0, EXCSAVE_1 /* save interruptee's a0 */ + + s32i a0, sp, XT_STK_A0 + + /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */ + movi a0, PS_INTLEVEL(5) | PS_UM | PS_WOE + wsr a0, PS + + //Call panic handler + mov a2, sp + call0 panicHandler diff --git a/components/freertos/include/freertos/xtensa_context.h b/components/freertos/include/freertos/xtensa_context.h index 7ae4c4ea..88458f76 100644 --- a/components/freertos/include/freertos/xtensa_context.h +++ b/components/freertos/include/freertos/xtensa_context.h @@ -77,6 +77,7 @@ space to help manage the spilling of the register windows. #define XT_STK_A14 0x44 /* Call0 callee-save */ #define XT_STK_A15 0x48 /* Call0 callee-save */ #define XT_STK_SAR 0x4C +#define XT_STK_EXCCAUSE 0x50 #if XCHAL_HAVE_LOOPS #define XT_STK_LBEG 0x50