From a6d01fc2de1f3f92ea19fabe3ad839dce76fdeb0 Mon Sep 17 00:00:00 2001 From: Gunar Schorcht Date: Thu, 5 Sep 2019 13:13:30 +0200 Subject: [PATCH] cpu/esp8266: vendor files changed for RTOS SDK --- cpu/esp8266/vendor/esp-gdbstub/gdbcmds | 1 - cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h | 99 +- .../vendor/esp-gdbstub/gdbstub-entry.S | 663 +++++------ .../vendor/esp-gdbstub/gdbstub-entry.h | 1 - cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h | 25 + cpu/esp8266/vendor/esp-gdbstub/gdbstub.c | 1025 ++++++++++------- cpu/esp8266/vendor/esp-gdbstub/gdbstub.h | 1 + cpu/esp8266/vendor/esp/README.md | 2 +- cpu/esp8266/vendor/esp/common_macros.h | 2 +- 9 files changed, 1040 insertions(+), 779 deletions(-) create mode 100644 cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbcmds b/cpu/esp8266/vendor/esp-gdbstub/gdbcmds index 61dfdbeda7..92cce51515 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbcmds +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbcmds @@ -1,4 +1,3 @@ -file ../ld/esp8266.riot-os.sdk.app.ld #set remotedebug 1 set remotelogfile gdb_rsp_logfile.txt set serial baud 115200 diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h index 849d733220..1a02b0cc8a 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-cfg.h @@ -5,60 +5,75 @@ extern "C" { #endif -/* -Enable this define if you're using the RTOS SDK. It will use a custom exception handler instead of the HAL -and do some other magic to make everything work and compile under FreeRTOS. -*/ -#ifndef GDBSTUB_FREERTOS -#define GDBSTUB_FREERTOS 1 -#endif - -/* -Enable this to make the exception and debugging handlers switch to a private stack. This will use -up 1K of RAM, but may be useful if you're debugging stack or stack pointer corruption problems. It's -normally disabled because not many situations need it. If for some reason the GDB communication -stops when you run into an error in your code, try enabling this. -*/ +/** + * @brief Enable own stack for gdbstub + * + * Enable this to make the exception and debugging handlers switch to a + * private stack. This will use GDBSTUB_STACK_SIZE of RAM, but may be useful + * if you're debugging stack or stack pointer corruption problems. It's + * normally disabled because not many situations need it. If for some reason + * the GDB communication stops when you run into an error in your code, try + * enabling this. + */ #ifndef GDBSTUB_USE_OWN_STACK -#define GDBSTUB_USE_OWN_STACK 0 +#define GDBSTUB_USE_OWN_STACK (0) #endif -/* -If this is defined, gdbstub will break the program when you press Ctrl-C in gdb. it does this by -hooking the UART interrupt. Unfortunately, this means receiving stuff over the serial port won't -work for your program anymore. This will fail if your program sets an UART interrupt handler after -the gdbstub_init call. -*/ +/** + * @brief Size of gdbstub stack + * + * If own stack is enale for gdbstub (\ref GDBSTUB_USE_OWN_STACK), + * GDBSTUB_STACK_SIZE defines the size of this stack. + */ +#ifndef GDBSTUB_STACK_SIZE +#define GDBSTUB_STACK_SIZE (1024) +#endif + +/** + * @brief Enable Ctrl-C handling + * + * If Ctrl-C is enabled, gdbstub interrupts the program when you press the + * Ctrl-C key either in gdb or, if used, in the console window. Ctrl-C handling + * is realized by hooking the UART interrupt. + */ #ifndef GDBSTUB_CTRLC_BREAK -#define GDBSTUB_CTRLC_BREAK 1 +#define GDBSTUB_CTRLC_BREAK (1) #endif -/* -Enabling this will redirect console output to GDB. This basically means that printf/os_printf output -will show up in your gdb session, which is useful if you use gdb to do stuff. It also means that if -you use a normal terminal, you can't read the printfs anymore. -*/ +/** + * @brief Redirect console output to GDB + * + * Enabling this will redirect console output to GDB. This basically means + * that printf/os_printf output will show up in your gdb session, which is + * useful if you use gdb to do stuff. It also means that if you use a normal + * terminal, you can't read the printfs anymore. + */ #ifndef GDBSTUB_REDIRECT_CONSOLE_OUTPUT -#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT 1 +#define GDBSTUB_REDIRECT_CONSOLE_OUTPUT (1) #endif -/* -Enable this if you want the GDB stub to wait for you to attach GDB before running. It does this by -breaking in the init routine; use the gdb 'c' command (continue) to start the program. -*/ +/** + * @brief Break on init + * + * Enable this if you want the GDB stub to wait for you to attach GDB before + * running. It does this by breaking in the init routine; use the gdb 'c' + * command (continue) to start the program. + */ #ifndef GDBSTUB_BREAK_ON_INIT -#define GDBSTUB_BREAK_ON_INIT 1 +#define GDBSTUB_BREAK_ON_INIT (1) #endif -/* -Function attributes for function types. -Gdbstub functions are placed in flash or IRAM using attributes, as defined here. The gdbinit function -(and related) can always be in flash, because it's called in the normal code flow. The rest of the -gdbstub functions can be in flash too, but only if there's no chance of them being called when the -flash somehow is disabled (eg during SPI operations or flash write/erase operations). If the routines -are called when the flash is disabled (eg due to a Ctrl-C at the wrong time), the ESP8266 will most -likely crash. -*/ +/** + * @brief Function attributes for function types. + * + * gdbstub functions are placed in flash or IRAM using attributes, as defined + * here. The gdbinit function (and related) can always be in flash, because + * it's called in the normal code flow. The rest of the gdbstub functions can + * be in flash too, but only if there's no chance of them being called when the + * flash somehow is disabled (eg during SPI operations or flash write/erase + * operations). If the routines are called when the flash is disabled (e.g. + * due to a Ctrl-C at the wrong time), the ESP8266 will most likely crash. + */ #define ATTR_GDBINIT ICACHE_FLASH_ATTR #ifndef ATTR_GDBFN #define ATTR_GDBFN diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S index 8ff28da66e..a1f79dcc4d 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.S @@ -8,397 +8,398 @@ #include "gdbstub-cfg.h" +#include "gdbstub-exc.h" #include #include #include -#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL) -#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL) -#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL) +#include "xtensa/xtensa_context.h" +#define DEBUG_PC (EPC + XCHAL_DEBUGLEVEL) +#define DEBUG_EXCSAVE (EXCSAVE + XCHAL_DEBUGLEVEL) +#define DEBUG_PS (EPS + XCHAL_DEBUGLEVEL) -.global gdbstub_savedRegs +.global gdbstub_regs +.global gdbstub_debug_exception_entry #if GDBSTUB_USE_OWN_STACK .global gdbstub_exceptionStack #endif - .text -.literal_position + .text + .literal_position - .text - .align 4 - -/* -The savedRegs struct: - uint32_t pc; - uint32_t ps; - uint32_t sar; - uint32_t vpri; - uint32_t a0; - uint32_t a[14]; //a2..a15 - uint32_t litbase; - uint32_t sr176; - uint32_t sr208; - uint32_t a1; - uint32_t reason; -*/ - -/* -This is the debugging exception routine; it's called by the debugging vector - -We arrive here with all regs intact except for a2. The old contents of A2 are saved -into the DEBUG_EXCSAVE special function register. EPC is the original PC. -*/ + .text + .align 4 +/** + * @brief Debugging exception routine; it's called by the debugging vector + */ gdbstub_debug_exception_entry: -/* - //Minimum no-op debug exception handler, for debug - rsr a2,DEBUG_PC - addi a2,a2,3 - wsr a2,DEBUG_PC - xsr a2, DEBUG_EXCSAVE - rfi XCHAL_DEBUGLEVEL -*/ -//Save all regs to structure - movi a2, gdbstub_savedRegs - s32i a0, a2, 0x10 - s32i a1, a2, 0x58 - rsr a0, DEBUG_PS - s32i a0, a2, 0x04 - rsr a0, DEBUG_EXCSAVE //was R2 - s32i a0, a2, 0x14 - s32i a3, a2, 0x18 - s32i a4, a2, 0x1c - s32i a5, a2, 0x20 - s32i a6, a2, 0x24 - s32i a7, a2, 0x28 - s32i a8, a2, 0x2c - s32i a9, a2, 0x30 - s32i a10, a2, 0x34 - s32i a11, a2, 0x38 - s32i a12, a2, 0x3c - s32i a13, a2, 0x40 - s32i a14, a2, 0x44 - s32i a15, a2, 0x48 - rsr a0, SAR - s32i a0, a2, 0x08 - rsr a0, LITBASE - s32i a0, a2, 0x4C - rsr a0, 176 - s32i a0, a2, 0x50 - rsr a0, 208 - s32i a0, a2, 0x54 - rsr a0, DEBUGCAUSE - s32i a0, a2, 0x5C - rsr a4, DEBUG_PC - s32i a4, a2, 0x00 + /* + * All registers except A2 are intact when we arrive here. The original + * contents of A2 was save in the EXCSAVE2/DEBUG_EXCSAVE register by + * _DebugExceptionVector stub. EPC2/DEBUG_PC register contains the + * original PC and EPC2/DEBUG_PC the original PS register + */ -#if GDBSTUB_USE_OWN_STACK - //Move to our own stack - movi a1, exceptionStack+255*4 + /* Save all regs to standard exception frame structure XtExcFrame */ + movi a2, gdbstub_regs + + s32i a0, a2, XT_STK_A0 /* save A0 (return address) before we used it */ + s32i a1, a2, XT_STK_A1 /* save A1 (stack pointer) */ + + rsr a0, DEBUG_PC /* read original PC from EPC2 and save it */ + s32i a0, a2, XT_STK_PC + + rsr a0, DEBUG_PS /* read original PS from ESP2 and save it */ + s32i a0, a2, XT_STK_PS + + rsr a0, DEBUG_EXCSAVE /* read original A2 from EXCSAVE2 and save it */ + s32i a0, a2, XT_STK_A2 + + s32i a3, a2, XT_STK_A3 /* save remaining A registers */ + s32i a4, a2, XT_STK_A4 + s32i a5, a2, XT_STK_A5 + s32i a6, a2, XT_STK_A6 + s32i a7, a2, XT_STK_A7 + s32i a8, a2, XT_STK_A8 + s32i a9, a2, XT_STK_A9 + s32i a10, a2, XT_STK_A10 + s32i a11, a2, XT_STK_A11 + s32i a12, a2, XT_STK_A12 + s32i a13, a2, XT_STK_A13 + s32i a14, a2, XT_STK_A14 + s32i a15, a2, XT_STK_A15 + + rsr a0, SAR /* read SAR and save it */ + s32i a0, a2, XT_STK_SAR + +#if XCHAL_HAVE_LOOPS + rsr a0, lbeg + s32i a0, a2, XT_STK_LBEG + rsr a0, lend + s32i a0, a2, XT_STK_LEND + rsr a0, lcount + s32i a0, a2, XT_STK_LCOUNT #endif -//If ICOUNT is -1, disable it by setting it to 0, otherwise we will keep triggering on the same instruction. - rsr a2, ICOUNT - movi a3, -1 - bne a2, a3, noIcountReset - movi a3, 0 - wsr a3, ICOUNT +#ifdef XT_USE_SWPRI + rsr a0, vpri + s32i a0, a2, XT_STK_VPRI +#endif + +#ifdef XT_USE_OVLY + rsr a0, ovly + s32i a0, a2, XT_STK_OVLY +#endif + + /* Save additional registers required for gdb_stub */ + movi a2, gdbstub_regs + XtExcFrameSize + rsr a0, LITBASE + s32i a0, a2, XT_STK_LITBASE + rsr a0, 176 + s32i a0, a2, XT_STK_SR176 + rsr a0, 208 + s32i a0, a2, XT_STK_SR208 + rsr a0, DEBUGCAUSE + s32i a0, a2, XT_STK_REASON + +#if GDBSTUB_USE_OWN_STACK + /* Move to our own stack */ + movi a1, gdbstub_exceptionStack + GDBSTUB_STACK_SIZE - 4 +#endif + + /* + * If ICOUNT is -1, disable it by setting it to 0, otherwise we will + * keep triggering on the same instruction. + */ + rsr a2, ICOUNT + movi a3, -1 + bne a2, a3, noIcountReset + movi a3, 0 + wsr a3, ICOUNT + noIcountReset: + rsr a2, ps + addi a2, a2, -PS_EXCM_MASK + wsr a2, ps + rsync - rsr a2, ps - addi a2, a2, -PS_EXCM_MASK - wsr a2, ps - rsync - -//Call into the C code to do the actual handling. - call0 gdbstub_handle_debug_exception + /* Call into the C code to do the actual handling. */ + call0 gdbstub_handle_debug_exception DebugExceptionExit: - rsr a2, ps - addi a2, a2, PS_EXCM_MASK - wsr a2, ps - rsync + rsr a2, ps + addi a2, a2, PS_EXCM_MASK + wsr a2, ps + rsync - //Restore registers from the gdbstub_savedRegs struct - movi a2, gdbstub_savedRegs - l32i a0, a2, 0x00 - wsr a0, DEBUG_PC -// l32i a0, a2, 0x54 -// wsr a0, 208 - l32i a0, a2, 0x50 - //wsr a0, 176 //Some versions of gcc do not understand this... - .byte 0x00, 176, 0x13 //so we hand-assemble the instruction. - l32i a0, a2, 0x4C - wsr a0, LITBASE - l32i a0, a2, 0x08 - wsr a0, SAR - l32i a15, a2, 0x48 - l32i a14, a2, 0x44 - l32i a13, a2, 0x40 - l32i a12, a2, 0x3c - l32i a11, a2, 0x38 - l32i a10, a2, 0x34 - l32i a9, a2, 0x30 - l32i a8, a2, 0x2c - l32i a7, a2, 0x28 - l32i a6, a2, 0x24 - l32i a5, a2, 0x20 - l32i a4, a2, 0x1c - l32i a3, a2, 0x18 - l32i a0, a2, 0x14 - wsr a0, DEBUG_EXCSAVE //was R2 - l32i a0, a2, 0x04 - wsr a0, DEBUG_PS - l32i a1, a2, 0x58 - l32i a0, a2, 0x10 + /* Restore registers from the gdbstub_regs struct. */ - //Read back vector-saved a2 value, put back address of this routine. - movi a2, gdbstub_debug_exception_entry - xsr a2, DEBUG_EXCSAVE + movi a2, gdbstub_regs + XtExcFrameSize - //All done. Return to where we came from. - rfi XCHAL_DEBUGLEVEL +#if 0 + /* TODO: check whether it is really necessary to recover SR178 and SR208 + * Some versions of gcc do not understand instruction 'wsr ' where n is + * the decimal number of the special register. A hand-assembled version of + * instruction would have to be used instead. + * + * .byte 0x00, , 0x13 + * + * However, writing to SR176 or SR208 leads to an IllegalInstruction + * exception + */ - - -#if GDBSTUB_FREERTOS -/* -FreeRTOS exception handling code. For some reason or another, we can't just hook the main exception vector: it -seems FreeRTOS uses that for something else too (interrupts). FreeRTOS has its own fatal exception handler, and we -hook that. Unfortunately, that one is called from a few different places (eg directly in the DoubleExceptionVector) -so the precise location of the original register values are somewhat of a mystery when we arrive here... - -As a 'solution', we'll just decode the most common case of the user_fatal_exception_handler being called from -the user exception handler vector: -- excsave1 - orig a0 -- a1: stack frame: - sf+16: orig a1 - sf+8: ps - sf+4: epc - sf+12: orig a0 - sf: magic no? -*/ - .global gdbstub_handle_user_exception - .global gdbstub_user_exception_entry - .align 4 -gdbstub_user_exception_entry: -//Save all regs to structure - movi a0, gdbstub_savedRegs - s32i a1, a0, 0x14 //was a2 - s32i a3, a0, 0x18 - s32i a4, a0, 0x1c - s32i a5, a0, 0x20 - s32i a6, a0, 0x24 - s32i a7, a0, 0x28 - s32i a8, a0, 0x2c - s32i a9, a0, 0x30 - s32i a10, a0, 0x34 - s32i a11, a0, 0x38 - s32i a12, a0, 0x3c - s32i a13, a0, 0x40 - s32i a14, a0, 0x44 - s32i a15, a0, 0x48 - rsr a2, SAR - s32i a2, a0, 0x08 - rsr a2, LITBASE - s32i a2, a0, 0x4C - rsr a2, 176 - s32i a2, a0, 0x50 - rsr a2, 208 - s32i a2, a0, 0x54 - rsr a2, EXCCAUSE - s32i a2, a0, 0x5C - -//Get the rest of the regs from the stack struct - l32i a3, a1, 12 - s32i a3, a0, 0x10 - l32i a3, a1, 16 - s32i a3, a0, 0x58 - l32i a3, a1, 8 - s32i a3, a0, 0x04 - l32i a3, a1, 4 - s32i a3, a0, 0x00 - -#if GDBSTUB_USE_OWN_STACK - movi a1, exceptionStack+255*4 + l32i a0, a2, XT_STK_SR208 + wsr a0, 208 + l32i a0, a2, XT_STK_SR176 + wsr a0, 176 #endif - rsr a2, ps - addi a2, a2, -PS_EXCM_MASK - wsr a2, ps - rsync + l32i a0, a2, XT_STK_LITBASE + wsr a0, LITBASE - call0 gdbstub_handle_user_exception - -UserExceptionExit: - -/* -Okay, from here on, it Does Not Work. There's not really any continuing from an exception in the -FreeRTOS case; there isn't any effort put in reversing the mess the exception code made yet. Maybe this -is still something we need to implement later, if there's any demand for it, or maybe we should modify -FreeRTOS to allow this in the future. (Which will then kill backwards compatibility... hmmm.) -*/ - j UserExceptionExit - - - .global gdbstub_handle_uart_int - .global gdbstub_uart_entry - .align 4 -gdbstub_uart_entry: - //On entry, the stack frame is at SP+16. - //This is a small stub to present that as the first arg to the gdbstub_handle_uart function. - movi a2, 16 - add a2, a2, a1 - movi a3, gdbstub_handle_uart_int - jx a3 + movi a2, gdbstub_regs +#ifdef XT_USE_OVLY + l32i a0, a2, XT_STK_OVLY + wsr a0, ovly #endif +#ifdef XT_USE_SWPRI + l32i a0, a2, XT_STK_VPRI + wsr a0, vpri +#endif + +#if XCHAL_HAVE_LOOPS + l32i a0, a2, XT_STK_LCOUNT + wsr a0, lcount + l32i a0, a2, XT_STK_LEND + wsr a0, lend + l32i a0, a2, XT_STK_LBEG + wsr a0, lbeg +#endif + + l32i a0, a2, XT_STK_SAR + wsr a0, sar + l32i a15, a2, XT_STK_A15 + l32i a14, a2, XT_STK_A14 + l32i a13, a2, XT_STK_A13 + l32i a12, a2, XT_STK_A12 + l32i a11, a2, XT_STK_A11 + l32i a10, a2, XT_STK_A10 + l32i a9, a2, XT_STK_A9 + l32i a8, a2, XT_STK_A8 + l32i a7, a2, XT_STK_A7 + l32i a6, a2, XT_STK_A6 + l32i a5, a2, XT_STK_A5 + l32i a4, a2, XT_STK_A4 + l32i a3, a2, XT_STK_A3 + + l32i a0, a2, XT_STK_A2 /* read original A2 and save it to EXCSAVE2 */ + wsr a0, DEBUG_EXCSAVE + l32i a0, a2, XT_STK_PS /* read original PS and save it to EPS2 */ + wsr a0, DEBUG_PS + l32i a0, a2, XT_STK_PC /* read original PC and save it to EPS2 */ + wsr a0, DEBUG_PC + + l32i a1, a2, XT_STK_A1 /* restore A1 (stack pointer) */ + l32i a0, a2, XT_STK_A0 /* restore A0 (return address) */ + + /* Read back vector-saved a2 value, put back address of this routine. */ + movi a2, gdbstub_debug_exception_entry + xsr a2, DEBUG_EXCSAVE + + /* All done. Return to where we came from. */ + rfi XCHAL_DEBUGLEVEL - .global gdbstub_save_extra_sfrs_for_exception - .align 4 -//The Xtensa OS HAL does not save all the special function register things. This bit of assembly -//fills the gdbstub_savedRegs struct with them. + .global gdbstub_save_extra_sfrs_for_exception + .align 4 +/* + * The Xtensa standard exception handlers does not save all the special + * function register things. This bit of assembly fills the gdbstub_regs struct + * with them. + */ gdbstub_save_extra_sfrs_for_exception: - movi a2, gdbstub_savedRegs - rsr a3, LITBASE - s32i a3, a2, 0x4C - rsr a3, 176 - s32i a3, a2, 0x50 - rsr a3, 208 - s32i a3, a2, 0x54 - rsr a3, EXCCAUSE - s32i a3, a2, 0x5C - ret - .global gdbstub_init_debug_entry - .global _DebugExceptionVector - .align 4 + /* a14-a15 are only saved by standard exception handlers for Windowed ABI */ + #ifdef __XTENSA_CALL0_ABI__ + movi a2, gdbstub_regs + s32i a14, a2, XT_STK_A14 + s32i a15, a2, XT_STK_A15 + #endif + + /* Save additional registers required for gdb_stub */ + movi a2, gdbstub_regs + XtExcFrameSize + rsr a3, LITBASE + s32i a3, a2, XT_STK_LITBASE + rsr a3, 176 + s32i a3, a2, XT_STK_SR176 + rsr a3, 208 + s32i a3, a2, XT_STK_SR208 + rsr a3, EXCCAUSE + s32i a3, a2, XT_STK_REASON + + ret + + + .global gdbstub_init_debug_entry + .global _DebugExceptionVector + .align 4 +/* + * This puts the following 2 instructions into the debug exception vector: + * xsr a2, DEBUG_EXCSAVE + * jx a2 + */ gdbstub_init_debug_entry: -//This puts the following 2 instructions into the debug exception vector: -// xsr a2, DEBUG_EXCSAVE -// jx a2 - movi a2, _DebugExceptionVector - movi a3, 0xa061d220 - s32i a3, a2, 0 - movi a3, 0x00000002 - s32i a3, a2, 4 -//Tell the just-installed debug vector where to go. - movi a2, gdbstub_debug_exception_entry - wsr a2, DEBUG_EXCSAVE + movi a2, _DebugExceptionVector + movi a3, 0xa061d220 + s32i a3, a2, 0 + movi a3, 0x00000002 + s32i a3, a2, 4 - ret + /* Tell the just-installed debug vector where to go. */ + movi a2, gdbstub_debug_exception_entry + wsr a2, DEBUG_EXCSAVE + + ret -//Set up ICOUNT register to step one single instruction - .global gdbstub_icount_ena_single_step - .align 4 + .global gdbstub_icount_ena_single_step + .align 4 +/* + * Set up ICOUNT register to step one single instruction + */ gdbstub_icount_ena_single_step: - movi a3, XCHAL_DEBUGLEVEL //Only count steps in non-debug mode - movi a2, -2 - wsr a3, ICOUNTLEVEL - wsr a2, ICOUNT - isync - ret + movi a3, XCHAL_DEBUGLEVEL /* Only count steps in non-debug mode */ + movi a2, -2 + wsr a3, ICOUNTLEVEL + wsr a2, ICOUNT + isync + ret +/* + * The following routines all assume that only one breakpoint and watchpoint + * is available, which is the case for the ESP8266 Xtensa core. + */ -//These routines all assume only one breakpoint and watchpoint is available, which -//is the case for the ESP8266 Xtensa core. - - - .global gdbstub_set_hw_breakpoint + .global gdbstub_set_hw_breakpoint + .align 4 +/* + * set an hw breakpoint + * paramters: a2 = addr, a3 = len (unused here) + */ gdbstub_set_hw_breakpoint: - //a2 - addr, a3 - len (unused here) - rsr a4, IBREAKENABLE - bbsi a4, 0, return_w_error - wsr a2, IBREAKA - movi a2, 1 - wsr a2, IBREAKENABLE - isync - movi a2, 1 - ret - .global gdbstub_del_hw_breakpoint +call0 40000080 + rsr a4, IBREAKENABLE + bbsi a4, 0, return_w_error + wsr a2, IBREAKA + movi a2, 1 + wsr a2, IBREAKENABLE + isync + movi a2, 1 + ret + + + .global gdbstub_del_hw_breakpoint + .align 4 +/* + * delete an hw breakpoint + * paramters: a2 = addr + */ gdbstub_del_hw_breakpoint: - //a2 - addr - rsr a5, IBREAKENABLE - bbci a5, 0, return_w_error - rsr a3, IBREAKA - bne a3, a2, return_w_error - movi a2,0 - wsr a2, IBREAKENABLE - isync - movi a2, 1 - ret - .global gdbstub_set_hw_watchpoint - //a2 - addr, a3 - mask, a4 - type (1=read, 2=write, 3=access) + rsr a5, IBREAKENABLE + bbci a5, 0, return_w_error + rsr a3, IBREAKA + bne a3, a2, return_w_error + movi a2,0 + wsr a2, IBREAKENABLE + isync + movi a2, 1 + ret + + + .global gdbstub_set_hw_watchpoint + .align 4 +/* + * set an hw breakpoint + * paramters: a2 = addr, a3 = mask, a4 = type (1=read, 2=write, 3=access) + */ gdbstub_set_hw_watchpoint: - //Check if any of the masked address bits are set. If so, that is an error. - movi a5,0x0000003F - xor a5, a5, a3 - bany a2, a5, return_w_error - //Check if watchpoint already is set - rsr a5, DBREAKC - movi a6, 0xC0000000 - bany a6, a5, return_w_error - //Set watchpoint - wsr a2, DBREAKA - //Combine type and mask - movi a6, 0x3F - and a3, a3, a6 - slli a4, a4, 30 - or a3, a3, a4 - wsr a3, DBREAKC + /* Check if any of the masked address bits are set. If so, that is an error. */ + movi a5,0x0000003F + xor a5, a5, a3 + bany a2, a5, return_w_error -// movi a2, 1 - mov a2, a3 - isync - ret + /* Check if watchpoint already is set */ + rsr a5, DBREAKC + movi a6, 0xC0000000 + bany a6, a5, return_w_error + + /* Set watchpoint */ + wsr a2, DBREAKA + + /* Combine type and mask */ + movi a6, 0x3F + and a3, a3, a6 + slli a4, a4, 30 + or a3, a3, a4 + wsr a3, DBREAKC + + mov a2, a3 + isync + ret - .global gdbstub_del_hw_watchpoint - //a2 - addr + .global gdbstub_del_hw_watchpoint + .align 4 +/* + * delete a hw breakpoint + * paramters: a2 = addr + */ gdbstub_del_hw_watchpoint: - //See if the address matches - rsr a3, DBREAKA - bne a3, a2, return_w_error - //See if the bp actually is set - rsr a3, DBREAKC - movi a2, 0xC0000000 - bnone a3, a2, return_w_error - //Disable bp - movi a2,0 - wsr a2,DBREAKC - movi a2,1 - isync - ret + /* see if the address matches */ + rsr a3, DBREAKA + bne a3, a2, return_w_error + /* see if the bp actually is set */ + rsr a3, DBREAKC + movi a2, 0xC0000000 + bnone a3, a2, return_w_error + /* Disable bp */ + movi a2,0 + wsr a2,DBREAKC + movi a2,1 + isync + ret return_w_error: - movi a2, 0 - ret + movi a2, 0 + ret -//Breakpoint, with an attempt at a functional function prologue and epilogue... - .global gdbstub_do_break_breakpoint_addr - .global gdbstub_do_break - .align 4 + .global gdbstub_do_break_breakpoint_addr + .global gdbstub_do_break + .align 4 +/* + * Breakpoint, with an attempt at a functional function prologue and epilogue... + */ gdbstub_do_break: - addi a1, a1, -16 - s32i a15, a1, 12 - mov a15, a1 + addi a1, a1, -16 + s32i a15, a1, 12 + mov a15, a1 gdbstub_do_break_breakpoint_addr: - break 0,0 + break 0,0 - mov a1, a15 - l32i a15, a1, 12 - addi a1, a1, 16 - ret + mov a1, a15 + l32i a15, a1, 12 + addi a1, a1, 16 + ret diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h index cecee2ad8e..63faaddbc2 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-entry.h @@ -6,7 +6,6 @@ extern "C" { #endif void gdbstub_init_debug_entry(void); -void gdbstub_do_break(void); void gdbstub_icount_ena_single_step(void); void gdbstub_save_extra_sfrs_for_exception(void); void gdbstub_uart_entry(void); diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h new file mode 100644 index 0000000000..bbcc266bae --- /dev/null +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub-exc.h @@ -0,0 +1,25 @@ +#ifndef GDBSTUB_EXC_H +#define GDBSTUB_EXC_H + +#include "xtensa/xtensa_context.h" + +/** + * @brief Structure of additional registers in excpeption fram as used by GDB + */ +STRUCT_BEGIN +STRUCT_FIELD (long, 4, XT_STK_LITBASE, litbase) +STRUCT_FIELD (long, 4, XT_STK_SR176, sr176) +STRUCT_FIELD (long, 4, XT_STK_SR208, sr208) +/* + * 'reason' is abused for both the debug and the exception vector: + * if bit 7 is set, this contains an exception reason, otherwise it + * contains a debug vector bitmap. + */ +STRUCT_FIELD (long, 4, XT_STK_REASON, reason) +STRUCT_END(XtExcFrameGdb) + +#ifdef __cplusplus +extern "C" { +#endif + +#endif /* GDBSTUB_EXC_H */ diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c index 5c80cdfdb1..3933f1dad7 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.c @@ -7,54 +7,47 @@ * License: ESPRESSIF MIT License *******************************************************************************/ +#include #include -#include "gdbstub.h" -#include "ets_sys.h" #include "eagle_soc.h" -#include "c_types.h" -#include "gpio.h" +#include "esp_attr.h" +#include "esp_common.h" +#include "periph/uart.h" +#include "rom/ets_sys.h" +#include "sdk/sdk.h" #include "xtensa/corebits.h" #include "gdbstub.h" +#include "gdbstub-exc.h" #include "gdbstub-entry.h" #include "gdbstub-cfg.h" -// From xtruntime-frames.h -struct XTensa_exception_frame_s { - uint32_t pc; - uint32_t ps; - uint32_t sar; - uint32_t vpri; - uint32_t a0; - uint32_t a[14]; //a2..a15 - // These are added manually by the exception code; the HAL doesn't - // set these on an exception. - uint32_t litbase; - uint32_t sr176; - uint32_t sr208; - uint32_t a1; - // 'reason' is abused for both the debug and the exception vector: if bit 7 is set, - // this contains an exception reason, otherwise it contains a debug vector bitmap. - uint32_t reason; -}; +#if GDBSTUB_CTRLC_BREAK +#include "isrpipe.h" +#include "sched.h" +#include "thread.h" +#endif +#if GDBSTUB_BREAK_ON_INIT +#include "irq.h" +#endif -struct XTensa_rtos_int_frame_s { - uint32_t exitPtr; - uint32_t pc; - uint32_t ps; - uint32_t a[16]; - uint32_t sar; -}; +#define ets_isr_t xt_handler -// OS-less SDK defines. Defines some headers for things that aren't in the -// include files, plus the xthal stack frame struct. -#include "sdk/sdk.h" +/* register frame structure as used by gdbstub */ +typedef struct { + XtExcFrame exc_frame; /* exception frame as used by exception handlers */ + XtExcFrameGdb exc_frame_gdb; /* gdb exception frame extensions */ +} gdb_exception_frame_t; + +/* + * Defines some things that aren't in the include files + */ #define EXCEPTION_GDB_SP_OFFSET 0x100 -//We need some UART register defines. +/* We need some UART register defines. */ #define ETS_UART_INUM 5 #define REG_UART_BASE( i ) (0x60000000+(i)*0xf00) #define UART_STATUS( i ) (REG_UART_BASE( i ) + 0x1C) @@ -70,144 +63,150 @@ struct XTensa_rtos_int_frame_s { #define UART_RXFIFO_TOUT_INT_CLR (BIT(8)) #define UART_RXFIFO_FULL_INT_CLR (BIT(0)) -// Length of buffer used to reserve GDB commands. Has to be at least able to -// fit the G command, which implies a minimum size of about 190 bytes. +/* + * Length of buffer used to reserve GDB commands. Has to be at least able to + * fit the G command, which implies a minimum size of about 190 bytes. + */ #define PBUFLEN 256 -// Length of gdb stdout buffer, for console redirection -#define OBUFLEN 32 +/* Length of gdb stdout buffer, for console redirection */ +#define OBUFLEN 256 + +/* + * The asm stub saves the Xtensa registers here when a debugging exception + * happens. + */ +gdb_exception_frame_t gdbstub_regs; -// The asm stub saves the Xtensa registers here when a debugging exception -// happens. -struct XTensa_exception_frame_s gdbstub_savedRegs; #if GDBSTUB_USE_OWN_STACK -// This is the debugging exception stack. -int exceptionStack[256]; +/* This is the debugging exception stack. */ +int gdbstub_exceptionStack[GDBSTUB_STACK_SIZE / sizeof(int)]; #endif -static unsigned char cmd[PBUFLEN]; // GDB command input buffer -static char chsum; // Running checksum of the output packet +static unsigned char cmd[PBUFLEN]; /* GDB command input buffer */ +static char chsum; /* Running checksum of the out put packet */ #if GDBSTUB_REDIRECT_CONSOLE_OUTPUT -static unsigned char obuf[OBUFLEN]; // GDB stdout buffer -static int obufpos=0; // Current position in the buffer +static unsigned char obuf[OBUFLEN]; /* GDB stdout buffer */ +static int obufpos=0; /* Current position in the buffer */ #endif -static int32_t singleStepPs = -1; // Stores ps when single-stepping - // instruction. -1 when not in use. +static int32_t singleStepPs = -1; /* Stores ps when single-stepping */ + /* instruction. -1 when not in use. */ -// Small function to feed the hardware watchdog. Needed to stop the ESP from -// resetting due to a watchdog timeout while reading a command. -static void ATTR_GDBFN keepWDTalive(void) -{ - uint64_t *wdtval = (uint64_t*)0x3ff21048; - uint64_t *wdtovf = (uint64_t*)0x3ff210cc; - int *wdtctl = (int*)0x3ff210c8; - *wdtovf = *wdtval+1600000; - *wdtctl |= (1 << 31); -} +static bool gdbstub_initialized = false; -// Receive a char from the uart. Uses polling and feeds the watchdog. +/* Receive a char from the UART. Uses polling and feeds the watchdog. */ static int ATTR_GDBFN gdbRecvChar(void) { int i; - while (((READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT)==0) - keepWDTalive(); + while (((READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT)==0) { + WDT_FEED(); + } i = READ_PERI_REG(UART_FIFO(0)); return i; } -// Send a char to the uart. +/* Send a char to the UART. */ static void ATTR_GDBFN gdbSendChar(char c) { - while (((READ_PERI_REG(UART_STATUS(0)) >> UART_TXFIFO_CNT_S)&UART_TXFIFO_CNT)>=126) - ; - WRITE_PERI_REG(UART_FIFO(0), c); + uart_write(UART_DEV(0), (const uint8_t *)&c, 1); } -// Send the start of a packet; reset checksum calculation. +/* Send the start of a packet; reset checksum calculation. */ static void ATTR_GDBFN gdbPacketStart(void) { chsum=0; gdbSendChar('$'); } -// Send a char as part of a packet +/* Send a char as part of a packet */ static void ATTR_GDBFN gdbPacketChar(char c) { - if (c == '#' || c == '$' || c == '}' || c == '*') - { + if (c == '#' || c == '$' || c == '}' || c == '*') { gdbSendChar('}'); gdbSendChar(c ^ 0x20); chsum += (c ^ 0x20) +'}'; } - else - { + else { gdbSendChar(c); chsum += c; } } -// Send a string as part of a packet +/* Send a string as part of a packet */ static void ATTR_GDBFN gdbPacketStr(char *c) { - while (*c != 0) - { + while (*c != 0) { gdbPacketChar(*c); c++; } } -// Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent. +/* Send a hex val as part of a packet. 'bits'/4 dictates the number of hex chars sent. */ static void ATTR_GDBFN gdbPacketHex(int val, int bits) { char hexChars[]="0123456789abcdef"; int i; - for (i = bits; i > 0; i -= 4) + for (i = bits; i > 0; i -= 4) { gdbPacketChar(hexChars[(val >> (i-4)) & 0xf]); + } } -// Finish sending a packet. +/* Finish sending a packet. */ static void ATTR_GDBFN gdbPacketEnd(void) { gdbSendChar('#'); gdbPacketHex(chsum, 8); } -// Error states used by the routines that grab stuff from the incoming gdb packet +/* + * Error states used by the routines that grab stuff from the incoming + * gdb packet + */ #define ST_ENDPACKET -1 #define ST_ERR -2 #define ST_OK -3 #define ST_CONT -4 -// Grab a hex value from the gdb packet. Ptr will get positioned on the end -// of the hex string, as far as the routine has read into it. Bits/4 indicates -// the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much -// hex chars as possible. -static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) { +/* + * Grab a hex value from the gdb packet. Ptr will get positioned on the end + * of the hex string, as far as the routine has read into it. Bits/4 indicates + * the max amount of hex chars it gobbles up. Bits can be -1 to eat up as much + * hex chars as possible. + */ +static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) +{ int i; - int no; - unsigned int v=0; - no=bits/4; - if (bits==-1) no=64; - for (i=0; i='0' && c<='9') { + if (c >= '0' && c <= '9') { v <<= 4; - v|=(c-'0'); - } else if (c>='A' && c<='F') { + v |= (c - '0'); + } + else if (c >= 'A' && c <= 'F') { v <<= 4; - v|=(c-'A')+10; - } else if (c>='a' && c<='f') { + v |= (c - 'A') + 10; + } + else if (c >= 'a' && c <= 'f') { v <<= 4; - v|=(c-'a')+10; - } else if (c=='#') { - if (bits==-1) { + v |= (c - 'a') + 10; + } + else if (c == '#') { + if (bits == -1) { (*ptr)--; return v; } return ST_ENDPACKET; - } else { - if (bits==-1) { + } + else { + if (bits == -1) { (*ptr)--; return v; } @@ -217,7 +216,7 @@ static long ATTR_GDBFN gdbGetHexVal(unsigned char **ptr, int bits) { return v; } -// Swap an int into the form gdb wants it +/* Swap an int into the form gdb wants it */ static int ATTR_GDBFN iswap(int i) { int r; @@ -228,41 +227,43 @@ static int ATTR_GDBFN iswap(int i) return r; } -// Read a byte from the ESP8266 memory. +/* Read a byte from the ESP8266 memory. */ static unsigned char ATTR_GDBFN readbyte(unsigned int p) { int *i = (int*)(p & (~3)); - if (p < 0x20000000 || p >= 0x60000000) + if (p < 0x20000000 || p >= 0x60000000) { return -1; + } return *i >> ((p & 3) * 8); } -// Write a byte to the ESP8266 memory. +/* Write a byte to the ESP8266 memory. */ static void ATTR_GDBFN writeByte(unsigned int p, unsigned char d) { int *i = (int*)(p & (~3)); - if (p < 0x20000000 || p >= 0x60000000) return; + if (p < 0x20000000 || p >= 0x60000000) { + return; + } if ((p & 3) == 0) *i = (*i & 0xffffff00) | (d << 0); if ((p & 3) == 1) *i = (*i & 0xffff00ff) | (d << 8); if ((p & 3) == 2) *i = (*i & 0xff00ffff) | (d << 16); if ((p & 3) == 3) *i = (*i & 0x00ffffff) | (d << 24); } -// Returns 1 if it makes sense to write to addr p +/* Returns 1 if it makes sense to write to addr p */ static int ATTR_GDBFN validWrAddr(int p) { - if (p >= 0x3ff00000 && p < 0x40000000) return 1; - if (p >= 0x40100000 && p < 0x40140000) return 1; - if (p >= 0x60000000 && p < 0x60002000) return 1; - return 0; + return ((p >= 0x3ff00000 && p < 0x40000000) || + (p >= 0x40100000 && p < 0x40140000) || + (p >= 0x60000000 && p < 0x60002000)) ? 1 : 0; } /* -Register file in the format lx106 gdb port expects it. -Inspired by gdb/regformats/reg-xtensa.dat from -https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar -As decoded by Cesanta. -*/ + * Register file in the format lx106 gdb port expects it. + * Inspired by gdb/regformats/reg-xtensa.dat from + * https://github.com/jcmvbkbc/crosstool-NG/blob/lx106-g%2B%2B/overlays/xtensa_lx106.tar + * As decoded by Cesanta. + */ struct regfile { uint32_t a[16]; @@ -274,201 +275,285 @@ struct regfile uint32_t ps; }; - -//Send the reason execution is stopped to GDB. +/* Send the reason execution is stopped to GDB. */ static void ATTR_GDBFN sendReason(void) { #if 0 - char *reason=""; //default + char *reason=""; /* default */ #endif + gdbPacketStart(); gdbPacketChar('T'); - if (gdbstub_savedRegs.reason == 0xff) - { - gdbPacketHex(2, 8); //sigint + if (gdbstub_regs.exc_frame_gdb.reason == 0xff) { + gdbPacketHex(2, 8); /* sigint */ } - else if (gdbstub_savedRegs.reason & 0x80) + else if (gdbstub_regs.exc_frame_gdb.reason & 0x80) { - // exception-to-signal mapping - char exceptionSignal[] = { 4, 31, 11, 11, 2, 6 , 8, 0, 6, 7, 0, 0, 7, 7, 7, 7}; - unsigned int i=0; - // We stopped because of an exception. - // Convert exception code to a signal number and send it. - i = gdbstub_savedRegs.reason & 0x7f; + /* exception-to-signal mapping */ + char exceptionSignal[] = { + SIGILL, /* IllegalInstructionCause >> SIGILL - 4 */ + SIGUSR2, /* SyscallCause >> SIGUSR2 - 31 */ + SIGSEGV, /* InstructionFetchErrorCause >> SIGSEGV - 11 */ + SIGSEGV, /* LoadStoreErrorCause >> SIGSEGV - 11 */ + SIGINT, /* Level1InterruptCause >> SIGINT - 2 */ + SIGABRT, /* AllocaCause >> SIGABRT - 6 */ + SIGFPE, /* IntegerDivideByZeroCause >> SIGFPE - 8 */ + 0, /* not used >> 0 */ + SIGABRT, /* PrivilegedCause >> SIGABRT - 6 */ + SIGEMT, /* LoadStoreAlignmentCause >> SIGEMT - 7 */ + 0, /* not used >> 0 */ + 0, /* not used >> 0 */ + SIGEMT, /* InstrPIFDataErrorCause >> SIGEMT - 7 */ + SIGEMT, /* LoadStorePIFDataErrorCause >> SIGEMT - 7 */ + SIGEMT, /* InstrPIFAddrErrorCause >> SIGEMT - 7 */ + SIGEMT /* LoadStorePIFAddrErrorCause >> SIGEMT - 7 */ + }; + unsigned int i = 0; + + /* We stopped because of an exception. */ + /* Convert exception code to a signal number and send it. */ + i = gdbstub_regs.exc_frame_gdb.reason & 0x7f; if (i < sizeof(exceptionSignal)) gdbPacketHex(exceptionSignal[i], 8); else - gdbPacketHex(11, 8); + gdbPacketHex(SIGSEGV, 8); } else { - // We stopped because of a debugging exception. - gdbPacketHex(5, 8); //sigtrap - // Current Xtensa GDB versions don't seem to request this, so let's - // leave it off. + /* We stopped because of a debugging exception. */ + gdbPacketHex(5, 8); /* sigtrap */ + + /* Current Xtensa GDB versions don't seem to request this, so let's leave it off. */ #if 0 - if (gdbstub_savedRegs.reason&(1 << 0)) reason="break"; - if (gdbstub_savedRegs.reason&(1 << 1)) reason="hwbreak"; - if (gdbstub_savedRegs.reason&(1 << 2)) reason="watch"; - if (gdbstub_savedRegs.reason&(1 << 3)) reason="swbreak"; - if (gdbstub_savedRegs.reason&(1 << 4)) reason="swbreak"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 0)) reason="break"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 1)) reason="hwbreak"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 2)) reason="watch"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 3)) reason="swbreak"; + if (gdbstub_regs.exc_frame_gdb.reason&(1 << 4)) reason="swbreak"; gdbPacketStr(reason); gdbPacketChar(':'); - //ToDo: watch: send address + /* TODO: watch: send address */ #endif } gdbPacketEnd(); } -// Handle a command as received from GDB. +/* + * Handle a command as received from GDB. + */ static int ATTR_GDBFN gdbHandleCommand(unsigned char *cmd, int len) { - // Handle a command int i, j, k; - unsigned char *data=cmd+1; - if (cmd[0] == 'g') - { // send all registers to gdb + unsigned char *data = cmd + 1; + + if (cmd[0] == 'g') { + /* + * send all registers to gdb + * format corresponds to struct regfile + */ + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; /* a register array */ gdbPacketStart(); - gdbPacketHex(iswap(gdbstub_savedRegs.a0), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.a1), 32); - for (i = 2; i < 16; i++) - gdbPacketHex(iswap(gdbstub_savedRegs.a[i-2]), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.pc), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.sar), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.litbase), 32); - gdbPacketHex(iswap(gdbstub_savedRegs.sr176), 32); - gdbPacketHex(0, 32); - gdbPacketHex(iswap(gdbstub_savedRegs.ps), 32); + for (int i = 0; i < 16; i++) { + gdbPacketHex(iswap(ar[i]), 32); + } + gdbPacketHex(iswap(gdbstub_regs.exc_frame.pc), 32); + gdbPacketHex(iswap(gdbstub_regs.exc_frame.sar), 32); + gdbPacketHex(iswap(gdbstub_regs.exc_frame_gdb.litbase), 32); + gdbPacketHex(iswap(gdbstub_regs.exc_frame_gdb.sr176), 32); + gdbPacketHex(0, 32); /* sr208 is not sent */ + gdbPacketHex(iswap(gdbstub_regs.exc_frame.ps), 32); gdbPacketEnd(); } - else if (cmd[0]=='G') - { //receive content for all registers from gdb - gdbstub_savedRegs.a0 = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.a1 = iswap(gdbGetHexVal(&data, 32)); - for (i = 2; i < 16; i++) - gdbstub_savedRegs.a[i-2]=iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.pc = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.sar = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.litbase = iswap(gdbGetHexVal(&data, 32)); - gdbstub_savedRegs.sr176 = iswap(gdbGetHexVal(&data, 32)); + + else if (cmd[0]=='G') { + /* + * receive content for all registers from gdb + * format corresponds to struct regfile + */ + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; /* a register array */ + gdbPacketStart(); + for (int i = 0; i < 16; i++) { + ar[i] = iswap(gdbGetHexVal(&data, 32)); + } + gdbstub_regs.exc_frame.pc = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame.sar = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame_gdb.litbase = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame_gdb.sr176 = iswap(gdbGetHexVal(&data, 32)); gdbGetHexVal(&data, 32); - gdbstub_savedRegs.ps = iswap(gdbGetHexVal(&data, 32)); + gdbstub_regs.exc_frame.ps = iswap(gdbGetHexVal(&data, 32)); gdbPacketStart(); gdbPacketStr("OK"); gdbPacketEnd(); } - else if (cmd[0]=='m') { //read memory to gdb - i=gdbGetHexVal(&data, -1); + + else if (cmd[0]=='m') { + /* read memory to gdb */ + i = gdbGetHexVal(&data, -1); data++; - j=gdbGetHexVal(&data, -1); + j = gdbGetHexVal(&data, -1); + gdbPacketStart(); - for (k=0; k= PBUFLEN) { + return ST_ERR; } - cmd[p++]=c; - if (p>=PBUFLEN) return ST_ERR; } - //A # has been received. Get and check the received chsum. - sentchs[0]=gdbRecvChar(); - sentchs[1]=gdbRecvChar(); - ptr=&sentchs[0]; - rchsum=gdbGetHexVal(&ptr, 8); -// ets_printf("c %x r %x\n", chsum, rchsum); - if (rchsum!=chsum) { + /* # has been received. Get the received chsum. */ + sentchs[0] = gdbRecvChar(); + sentchs[1] = gdbRecvChar(); + + /* check the received checksum */ + ptr = sentchs; + rchsum = gdbGetHexVal(&ptr, 8); + if (rchsum != chsum) { + /* wrong checksum, request retransmission */ gdbSendChar('-'); +_gdbstub_in_rcv_packet = false; return ST_ERR; - } else { - gdbSendChar('+'); - return gdbHandleCommand(cmd, p); } + + /* ack the package and handle the command */ + gdbSendChar('+'); +_gdbstub_in_rcv_packet = false; + return gdbHandleCommand(cmd, p); } -//Get the value of one of the A registers -static unsigned int ATTR_GDBFN getaregval(int reg) { - if (reg==0) return gdbstub_savedRegs.a0; - if (reg==1) return gdbstub_savedRegs.a1; - return gdbstub_savedRegs.a[reg-2]; +/* get the value of one of an A registers */ +static unsigned int ATTR_GDBFN getaregval(int reg) +{ + assert(reg >= 0 && reg < 16); + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; + return ar[reg]; } -//Set the value of one of the A registers -static void ATTR_GDBFN setaregval(int reg, unsigned int val) { +/* set the value of one of an A registers */ +static void ATTR_GDBFN setaregval(int reg, unsigned int val) +{ ets_printf("%x -> %x\n", val, reg); - if (reg==0) gdbstub_savedRegs.a0=val; - if (reg==1) gdbstub_savedRegs.a1=val; - gdbstub_savedRegs.a[reg-2]=val; + assert(reg >= 0 && reg < 16); + unsigned *ar = (unsigned*)&gdbstub_regs.exc_frame.a0; + ar[reg] = val; } -//Emulate the l32i/s32i instruction we're stopped at. -static void ATTR_GDBFN emulLdSt(void) { - unsigned char i0=readbyte(gdbstub_savedRegs.pc); - unsigned char i1=readbyte(gdbstub_savedRegs.pc+1); - unsigned char i2=readbyte(gdbstub_savedRegs.pc+2); +/* Emulate the l32i/s32i instruction we're stopped at. */ +static void ATTR_GDBFN emulLdSt(void) +{ + unsigned char i0 = readbyte(gdbstub_regs.exc_frame.pc); + unsigned char i1 = readbyte(gdbstub_regs.exc_frame.pc+1); + unsigned char i2 = readbyte(gdbstub_regs.exc_frame.pc+2); int *p; - if ((i0 & 0xf)==2 && (i1 & 0xf0)==0x20) { - //l32i - p=(int*)getaregval(i1 & 0xf)+(i2*4); + + if ((i0 & 0xf) == 2 && (i1 & 0xf0) == 0x20) { + /* l32i */ + p = (int*)getaregval(i1 & 0xf) + (i2 * 4); setaregval(i0 >> 4, *p); - gdbstub_savedRegs.pc+=3; - } else if ((i0 & 0xf)==0x8) { - //l32i.n - p=(int*)getaregval(i1 & 0xf)+((i1 >> 4)*4); + gdbstub_regs.exc_frame.pc += 3; + } + else if ((i0 & 0xf) == 0x8) { + /* l32i.n */ + p = (int*)getaregval(i1 & 0xf) + ((i1 >> 4) * 4); setaregval(i0 >> 4, *p); - gdbstub_savedRegs.pc+=2; - } else if ((i0 & 0xf)==2 && (i1 & 0xf0)==0x60) { - //s32i - p=(int*)getaregval(i1 & 0xf)+(i2*4); - *p=getaregval(i0 >> 4); - gdbstub_savedRegs.pc+=3; - } else if ((i0 & 0xf)==0x9) { - //s32i.n - p=(int*)getaregval(i1 & 0xf)+((i1 >> 4)*4); - *p=getaregval(i0 >> 4); - gdbstub_savedRegs.pc+=2; - } else { + gdbstub_regs.exc_frame.pc += 2; + } + else if ((i0 & 0xf) == 2 && (i1 & 0xf0) == 0x60) { + /* s32i */ + p = (int*)getaregval(i1 & 0xf) + (i2*4); + *p = getaregval(i0 >> 4); + gdbstub_regs.exc_frame.pc += 3; + } + else if ((i0 & 0xf) == 0x9) { + /* s32i.n */ + p = (int*)getaregval(i1 & 0xf) + ((i1 >> 4) * 4); + *p = getaregval(i0 >> 4); + gdbstub_regs.exc_frame.pc += 2; + } + else { ets_printf("GDBSTUB: No l32i/s32i instruction: %x %x %x. Huh?", i2, i1, i0); } } -// We just caught a debug exception and need to handle it. This is called -// from an assembly routine in gdbstub-entry.S +void gdbstub_print_regs(void) +{ + ets_printf("pc : %08x\t", gdbstub_regs.exc_frame.pc); + ets_printf("ps : %08x\t", gdbstub_regs.exc_frame.ps); + ets_printf("exccause: %08x\t", gdbstub_regs.exc_frame.exccause); + ets_printf("excvaddr: %08x\n", gdbstub_regs.exc_frame.excvaddr); + ets_printf("a0 : %08x\t", gdbstub_regs.exc_frame.a0); + ets_printf("a1 : %08x\t", gdbstub_regs.exc_frame.a1); + ets_printf("a2 : %08x\t", gdbstub_regs.exc_frame.a2); + ets_printf("a3 : %08x\n", gdbstub_regs.exc_frame.a3); + ets_printf("a4 : %08x\t", gdbstub_regs.exc_frame.a4); + ets_printf("a5 : %08x\t", gdbstub_regs.exc_frame.a5); + ets_printf("a6 : %08x\t", gdbstub_regs.exc_frame.a6); + ets_printf("a7 : %08x\n", gdbstub_regs.exc_frame.a7); + ets_printf("a8 : %08x\t", gdbstub_regs.exc_frame.a8); + ets_printf("a9 : %08x\t", gdbstub_regs.exc_frame.a9); + ets_printf("a10 : %08x\t", gdbstub_regs.exc_frame.a10); + ets_printf("a11 : %08x\n", gdbstub_regs.exc_frame.a11); + ets_printf("a12 : %08x\t", gdbstub_regs.exc_frame.a12); + ets_printf("a13 : %08x\t", gdbstub_regs.exc_frame.a13); + ets_printf("a14 : %08x\t", gdbstub_regs.exc_frame.a14); + ets_printf("a15 : %08x\n", gdbstub_regs.exc_frame.a15); +#if XCHAL_HAVE_LOOPS + ets_printf("lbeg : %08x\t", gdbstub_regs.exc_frame.lbeg); + ets_printf("lend : %08x\t", gdbstub_regs.exc_frame.lend); + ets_printf("lcount : %08x\n", gdbstub_regs.exc_frame.lcount); +#endif /* XCHAL_HAVE_LOOPS */ +#ifdef XT_USE_SWPRI + ets_printf("vpri : %08x\n", gdbstub_regs.exc_frame.vpri); +#endif +#ifdef XT_USE_OVLY +#ifdef XT_USE_SWPRI + ets_printf("ovly : %08x\n", gdbstub_regs.exc_frame.ovly); +#endif +#endif + ets_printf("litbase : %08x\t", gdbstub_regs.exc_frame_gdb.litbase); + ets_printf("sr176 : %08x\t", gdbstub_regs.exc_frame_gdb.sr176); + ets_printf("sr208 : %08x\t", gdbstub_regs.exc_frame_gdb.sr208); + ets_printf("reason : %08x\n", gdbstub_regs.exc_frame_gdb.reason); +} + +/* + * We just caught a debug exception and need to handle it. This is called + * from an assembly routine in gdbstub-entry.S + */ void ATTR_GDBFN gdbstub_handle_debug_exception(void) { ets_wdt_disable(); if (singleStepPs != -1) { - // We come here after single-stepping an instruction. Interrupts are - // disabled for the single step. Re-enable them here. - gdbstub_savedRegs.ps = (gdbstub_savedRegs.ps & ~0xf) | (singleStepPs & 0xf); + /* + * We come here after single-stepping an instruction. Interrupts are + * disabled for the single step. Re-enable them here. + */ + gdbstub_regs.exc_frame.ps = (gdbstub_regs.exc_frame.ps & ~0xf) | (singleStepPs & 0xf); singleStepPs = -1; } sendReason(); - while (gdbReadCommand()!=ST_CONT) - ; + while (gdbReadCommand() != ST_CONT) { } - if ((gdbstub_savedRegs.reason & 0x84) == 0x4) + if ((gdbstub_regs.exc_frame_gdb.reason & 0x84) == 0x4) { - //We stopped due to a watchpoint. We can't re-execute the current instruction - //because it will happily re-trigger the same watchpoint, so we emulate it - //while we're still in debugger space. + /* + * We stopped due to a watchpoint. We can't re-execute the current + * instruction because it will happily re-trigger the same watchpoint, + * so we emulate it while we're still in debugger space. + */ emulLdSt(); - } else if ((gdbstub_savedRegs.reason & 0x88)==0x8) { - //We stopped due to a BREAK instruction. Skip over it. - //Check the instruction first; gdb may have replaced it with the original instruction - //if it's one of the breakpoints it set. - if (readbyte(gdbstub_savedRegs.pc+2)==0 && - (readbyte(gdbstub_savedRegs.pc+1) & 0xf0)==0x40 && - (readbyte(gdbstub_savedRegs.pc) & 0x0f)==0x00) { - gdbstub_savedRegs.pc+=3; + } + else if ((gdbstub_regs.exc_frame_gdb.reason & 0x88) == 0x8) { + /* + * We stopped due to a BREAK instruction. Skip over it. Check the + * instruction first; gdb may have replaced it with the + * original instruction if it's one of the breakpoints it set. + */ + if ((readbyte(gdbstub_regs.exc_frame.pc + 2) & 0xff) == 0 && + (readbyte(gdbstub_regs.exc_frame.pc + 1) & 0xf0) == 0x40 && + (readbyte(gdbstub_regs.exc_frame.pc) & 0x0f) == 0x00) { + gdbstub_regs.exc_frame.pc += 3; } - } else if ((gdbstub_savedRegs.reason & 0x90)==0x10) { - //We stopped due to a BREAK.N instruction. Skip over it, after making sure the instruction - //actually is a BREAK.N - if ((readbyte(gdbstub_savedRegs.pc+1) & 0xf0)==0xf0 && - readbyte(gdbstub_savedRegs.pc)==0x2d) { - gdbstub_savedRegs.pc+=3; + } + else if ((gdbstub_regs.exc_frame_gdb.reason & 0x90) == 0x10) { + /* + * We stopped due to a BREAK.N instruction. Skip over it, after + * making sure the instruction actually is a BREAK.N + */ + if ((readbyte(gdbstub_regs.exc_frame.pc+1) & 0xf0) == 0xf0 && + (readbyte(gdbstub_regs.exc_frame.pc) & 0xff) == 0x2d) { + gdbstub_regs.exc_frame.pc+=3; } } ets_wdt_enable(); } - -#ifdef MODULE_ESP_SDK_INT_HANDLING - -// Non-OS exception handler. Gets called by the Xtensa HAL. -static void ATTR_GDBFN gdb_exception_handler (void* arg) +static void ATTR_GDBFN gdb_exception_handler(XtExcFrame *frame) { - struct XTensa_exception_frame_s* frame = (struct XTensa_exception_frame_s*)arg; + assert(frame != NULL); - // Save the extra registers the Xtensa HAL doesn't save + ets_printf("GDB entry after exception @%08x\n", frame->pc); + + /* + * On entry, registers ps, pc, a0...a15, sar, lbeg, lend, lcount, vpri, + * ovly have been already saved by _xt_user_exc including _xt_context_save + */ + + /* copy the registers the Xtensa exception handler did save to gdbstub_regs */ + ets_memcpy(&gdbstub_regs.exc_frame, frame, sizeof(XtExcFrame)); + + /* save the extra registers the exception vectors doesn't save */ gdbstub_save_extra_sfrs_for_exception(); - // Copy registers the Xtensa HAL did save to gdbstub_savedRegs - ets_memcpy(&gdbstub_savedRegs, frame, 19*4); - - // Credits go to Cesanta for this trick. A1 seems to be destroyed, but because it - // has a fixed offset from the address of the passed frame, we can recover it. - gdbstub_savedRegs.a1 = (uint32_t)frame + EXCEPTION_GDB_SP_OFFSET; - - gdbstub_savedRegs.reason |= 0x80; //mark as an exception reason + gdbstub_regs.exc_frame_gdb.reason |= 0x80; /* mark as an exception reason */ ets_wdt_disable(); + sendReason(); - while (gdbReadCommand() != ST_CONT) - ; + while (gdbReadCommand() != ST_CONT) { } + ets_wdt_enable(); - // Copy any changed registers back to the frame the Xtensa HAL uses. - ets_memcpy(frame, &gdbstub_savedRegs, 19*4); + /* Copy changed registers back to the standard exception frame. */ + ets_memcpy(frame, &gdbstub_regs.exc_frame, sizeof(XtExcFrame)); } -#else -/* TODO -static void ATTR_GDBFN gdb_exception_handler (XtExcFrame *frame) -{ - ets_printf("GDB EXCEPTION\n"); - while (1) ; -} -*/ -#endif // MODULE_ESP_SDK_INT_HANDLING - - #if GDBSTUB_REDIRECT_CONSOLE_OUTPUT -// Replacement putchar1 routine. Instead of spitting out the character -// directly, it will buffer up to OBUFLEN characters (or up to a \n, -// whichever comes earlier) and send it out as a gdb stdout packet. -static void ATTR_GDBFN gdb_semihost_putchar1(char c) +/* + * The following functions realize the communication with the gdb for console + * output. Each *printf function finally calls ets_printf which in turn calls + * ets_putc. Instead of spitting out the characters directly, the characters + * are be buffered up to OBUFLEN characters or up to a \n and sent out as a hex + * coded gdb packet. + */ + +int gdbstub_obuf_flush(void) { - obuf[obufpos++]=c; - if (c=='\n' || obufpos==OBUFLEN) - { - int i; - gdbPacketStart(); - gdbPacketChar('O'); - for (i=0; isp != NULL); + + XtExcFrame* frame = (XtExcFrame *)sched_active_thread->sp; + int doDebug=0; int fifolen=0; - //Save the extra registers the Xtensa HAL doesn't save + + /* Save the extra registers the standard exception handlers don't save */ gdbstub_save_extra_sfrs_for_exception(); - fifolen=(READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S)&UART_RXFIFO_CNT; - while (fifolen!=0) + fifolen = (READ_PERI_REG(UART_STATUS(0)) >> UART_RXFIFO_CNT_S) & UART_RXFIFO_CNT; + while (fifolen != 0) { - //Check if any of the chars is control-C. Throw away rest. - if ((READ_PERI_REG(UART_FIFO(0)) & 0xFF)==0x3) + uint8_t data = READ_PERI_REG(UART_FIFO(0)) & 0xff; + if (data == 0x03) { + /* if char is control-C, break execution and do in debug mode */ doDebug=1; + } + else if (data != '+' && data != '-' && !_gdbstub_in_rcv_packet) { + /* if char is not '+' (gdb ack/nak), forward it to stdio */ + extern isrpipe_t stdio_uart_isrpipe; + isrpipe_write_one(&stdio_uart_isrpipe, data); + } fifolen--; } - WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR|UART_RXFIFO_TOUT_INT_CLR); + WRITE_PERI_REG(UART_INT_CLR(0), UART_RXFIFO_FULL_INT_CLR | UART_RXFIFO_TOUT_INT_CLR); if (doDebug) { - // Copy registers the Xtensa HAL did save to gdbstub_savedRegs - ets_memcpy(&gdbstub_savedRegs, frame, 19*4); - gdbstub_savedRegs.a1=(uint32_t)frame+EXCEPTION_GDB_SP_OFFSET; + /* copy the registers the Xtensa exception handler did save to gdbstub_regs */ + ets_memcpy(&gdbstub_regs.exc_frame, frame, sizeof(XtExcFrame)); - //mark as user break reason - gdbstub_savedRegs.reason=0xff; + /* mark as user break reason */ + gdbstub_regs.exc_frame_gdb.reason = 0xff; ets_wdt_disable(); + sendReason(); - while(gdbReadCommand()!=ST_CONT); + while (gdbReadCommand() != ST_CONT) { } + ets_wdt_enable(); - // Copy any changed registers back to the frame the Xtensa HAL uses. - ets_memcpy(frame, &gdbstub_savedRegs, 19*4); + + /* Copy changed registers back to the standard exception frame. */ + ets_memcpy(frame, &gdbstub_regs.exc_frame, sizeof(XtExcFrame)); } } static void ATTR_GDBINIT install_uart_hdlr(void) { + /* set UART interrupt handler to the handler of gdbstub */ ets_isr_attach(ETS_UART_INUM, (ets_isr_t)uart_hdlr, NULL); + /* clear all interrupts */ SET_PERI_REG_MASK(UART_INT_ENA(0), UART_RXFIFO_FULL_INT_ENA|UART_RXFIFO_TOUT_INT_ENA); - // enable uart interrupt + /* enable uart interrupt */ ets_isr_unmask((1 << ETS_UART_INUM)); } -#endif // GDBSTUB_CTRLC_BREAK +#endif /* GDBSTUB_CTRLC_BREAK */ -// gdbstub initialization routine. +extern bool _esp_output_active; + +/* gdbstub initialization routine. */ void ATTR_GDBINIT gdbstub_init(void) { - #if GDBSTUB_REDIRECT_CONSOLE_OUTPUT - ets_install_putc1(gdb_semihost_putchar1); - #endif - #if GDBSTUB_CTRLC_BREAK install_uart_hdlr(); #endif install_exceptions(); gdbstub_init_debug_entry(); + gdbstub_initialized = true; #if GDBSTUB_BREAK_ON_INIT + /* before break, PS.INTLEVEL has to be set correctly to allow debug exceptions */ + uint32_t _old_intlevel; + __asm__ volatile ("rsil %0, " XTSTR(XCHAL_DEBUGLEVEL - 1) : "=a" (_old_intlevel)); + (void)_old_intlevel; + /* now lets break on init */ gdbstub_do_break(); #endif } diff --git a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h index d9e8b4a094..f47b2b1e0d 100644 --- a/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h +++ b/cpu/esp8266/vendor/esp-gdbstub/gdbstub.h @@ -6,6 +6,7 @@ extern "C" { #endif void gdbstub_init(void); +void gdbstub_do_break(void); #ifdef __cplusplus } diff --git a/cpu/esp8266/vendor/esp/README.md b/cpu/esp8266/vendor/esp/README.md index bf5deb40d3..cc57fa847b 100644 --- a/cpu/esp8266/vendor/esp/README.md +++ b/cpu/esp8266/vendor/esp/README.md @@ -1,3 +1,3 @@ -All files in this directory are part of [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). They are under the copyright of their respective owners. Please note the copyright notice in these files. +All files in this directory are part of [esp-open-rtos](https://github.com/SuperHouse/esp-open-rtos.git). They are under the copyright of their respective owners. All of these files are BSD Licensed as described in the file [LICENSE](https://github.com/SuperHouse/esp-open-rtos/blob/master/LICENSE). diff --git a/cpu/esp8266/vendor/esp/common_macros.h b/cpu/esp8266/vendor/esp/common_macros.h index d14c34639c..cca23c921f 100644 --- a/cpu/esp8266/vendor/esp/common_macros.h +++ b/cpu/esp8266/vendor/esp/common_macros.h @@ -33,7 +33,7 @@ extern "C" { #define UNUSED __attributed((unused)) -#ifndef BIT +#if defined(MCU_ESP8266) && !defined(BIT) #define BIT(X) (1<<(X)) #endif