diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 6ae200ac52a..ba4d0fb31b0 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -37,7 +37,7 @@ config XTENSA_NO_IPC bool "Core has no IPC support" select ATOMIC_OPERATIONS_C help - Uncheck this if you core does not implement "SCOMPARE1" register and "s32c1i" + Uncheck this if your core does not implement "SCOMPARE1" register and "s32c1i" instruction. config XTENSA_RESET_VECTOR diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index 2b551a6fc0a..ae980f53ee3 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -18,6 +18,7 @@ zephyr_library_sources_ifdef(CONFIG_IRQ_OFFLOAD irq_offload.c) zephyr_library_sources_ifdef(CONFIG_THREAD_LOCAL_STORAGE tls.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE xtensa_backtrace.c) zephyr_library_sources_ifdef(CONFIG_XTENSA_ENABLE_BACKTRACE debug_helpers_asm.S) +zephyr_library_sources_ifdef(CONFIG_DEBUG_COREDUMP coredump.c) zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c) diff --git a/arch/xtensa/core/coredump.c b/arch/xtensa/core/coredump.c new file mode 100644 index 00000000000..da33fbfec43 --- /dev/null +++ b/arch/xtensa/core/coredump.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2021 Intel Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#define ARCH_HDR_VER 1 +#define XTENSA_BLOCK_HDR_VER 1 + +enum xtensa_soc_code { + XTENSA_SOC_UNKNOWN = 0, + XTENSA_SOC_SAMPLE_CONTROLLER, + XTENSA_SOC_ESP32, +}; + +struct xtensa_arch_block { + /* Each Xtensa SOC can omit registers (e.g. loop + * registers) or assign different index numbers + * in xtensa-config.c. GDB identifies registers + * based on these indices + * + * (This must be the first field or the GDB server + * won't be able to unpack the struct while parsing) + */ + uint8_t soc; + + /* Future versions of Xtensa coredump + * may expand minimum set of registers + * + * (This should stay the second field for the same + * reason as the first once we have more versions) + */ + uint16_t version; + + struct { + /* Minimum set shown by GDB 'info registers', + * skipping user-defined register EXPSTATE + * + * WARNING: IF YOU CHANGE THE ORDER OF THE REGISTERS, + * YOU MUST UPDATE THE ORDER OF THE REGISTERS IN + * EACH OF THE XtensaSoc_ RegNum enums IN + * scripts/coredump/gdbstubs/arch/xtensa.py TO MATCH. + * See xtensa.py's map_register function for details + */ + uint32_t pc; + uint32_t exccause; + uint32_t excvaddr; + uint32_t sar; + uint32_t ps; +#if XCHAL_HAVE_S32C1I + uint32_t scompare1; +#endif + uint32_t a0; + uint32_t a1; + uint32_t a2; + uint32_t a3; + uint32_t a4; + uint32_t a5; + uint32_t a6; + uint32_t a7; + uint32_t a8; + uint32_t a9; + uint32_t a10; + uint32_t a11; + uint32_t a12; + uint32_t a13; + uint32_t a14; + uint32_t a15; +#if XCHAL_HAVE_LOOPS + uint32_t lbeg; + uint32_t lend; + uint32_t lcount; +#endif + } r; +} __packed; + +/* + * This might be too large for stack space if defined + * inside function. So do it here. + */ +static struct xtensa_arch_block arch_blk; + +void arch_coredump_info_dump(const z_arch_esf_t *esf) +{ + struct coredump_arch_hdr_t hdr = { + .id = COREDUMP_ARCH_HDR_ID, + .hdr_version = ARCH_HDR_VER, + .num_bytes = sizeof(arch_blk), + }; + + /* Nothing to process */ + if (esf == NULL) { + return; + } + + (void)memset(&arch_blk, 0, sizeof(arch_blk)); + + arch_blk.version = XTENSA_BLOCK_HDR_VER; + +#if CONFIG_SOC_XTENSA_SAMPLE_CONTROLLER + arch_blk.soc = XTENSA_SOC_SAMPLE_CONTROLLER; +#elif CONFIG_SOC_ESP32 + arch_blk.soc = XTENSA_SOC_ESP32; +#else + arch_blk.soc = XTENSA_SOC_UNKNOWN; +#endif + + __asm__ volatile("rsr.exccause %0" : "=r"(arch_blk.r.exccause)); + + int *bsa = *(int **)esf; + + arch_blk.r.pc = bsa[BSA_PC_OFF/4]; + __asm__ volatile("rsr.excvaddr %0" : "=r"(arch_blk.r.excvaddr)); + arch_blk.r.ps = bsa[BSA_PS_OFF/4]; +#if XCHAL_HAVE_S32C1I + arch_blk.r.scompare1 = bsa[BSA_SCOMPARE1_OFF]; +#endif + arch_blk.r.sar = bsa[BSA_SAR_OFF/4]; + arch_blk.r.a0 = bsa[BSA_A0_OFF/4]; + arch_blk.r.a1 = (uint32_t)((char *)bsa) + BASE_SAVE_AREA_SIZE; + arch_blk.r.a2 = bsa[BSA_A2_OFF/4]; + arch_blk.r.a3 = bsa[BSA_A3_OFF/4]; + if (bsa - esf > 4) { + arch_blk.r.a4 = bsa[-4]; + arch_blk.r.a5 = bsa[-3]; + arch_blk.r.a6 = bsa[-2]; + arch_blk.r.a7 = bsa[-1]; + } + if (bsa - esf > 8) { + arch_blk.r.a8 = bsa[-8]; + arch_blk.r.a9 = bsa[-7]; + arch_blk.r.a10 = bsa[-6]; + arch_blk.r.a11 = bsa[-5]; + } + if (bsa - esf > 12) { + arch_blk.r.a12 = bsa[-12]; + arch_blk.r.a13 = bsa[-11]; + arch_blk.r.a14 = bsa[-10]; + arch_blk.r.a15 = bsa[-9]; + } + #if XCHAL_HAVE_LOOPS + arch_blk.r.lbeg = bsa[BSA_LBEG_OFF/4]; + arch_blk.r.lend = bsa[BSA_LEND_OFF/4]; + arch_blk.r.lcount = bsa[BSA_LCOUNT_OFF/4]; + #endif + + /* Send for output */ + coredump_buffer_output((uint8_t *)&hdr, sizeof(hdr)); + coredump_buffer_output((uint8_t *)&arch_blk, sizeof(arch_blk)); +} + +uint16_t arch_coredump_tgt_code_get(void) +{ + return COREDUMP_TGT_XTENSA; +} diff --git a/doc/guides/debug_tools/coredump.rst b/doc/guides/debug_tools/coredump.rst index 7ea09880ddd..f07803f4c5d 100644 --- a/doc/guides/debug_tools/coredump.rst +++ b/doc/guides/debug_tools/coredump.rst @@ -4,8 +4,8 @@ Core Dump ######### The core dump module enables dumping the CPU registers and memory content -for offline debugging. This module is called when fatal error is -encountered, and the data is printed or stored according to which backends +for offline debugging. This module is called when a fatal error is +encountered and prints or stores data according to which backends are enabled. Configuration @@ -25,15 +25,15 @@ Here are the choices regarding memory dump: * ``DEBUG_COREDUMP_MEMORY_DUMP_MIN``: only dumps the stack of the exception thread, its thread struct, and some other bare minimal data to support - walking the stack in debugger. Use this only if absolute minimum of data + walking the stack in the debugger. Use this only if absolute minimum of data dump is desired. Usage ***** -When the core dump module is enabled, during fatal error, CPU registers -and memory content are being printed or stored according to which backends -are enabled. This core dump data can fed into a custom made GDB server as +When the core dump module is enabled, during a fatal error, CPU registers +and memory content are printed or stored according to which backends +are enabled. This core dump data can fed into a custom-made GDB server as a remote target for GDB (and other GDB compatible debuggers). CPU registers, memory content and stack can be examined in the debugger. diff --git a/include/debug/coredump.h b/include/debug/coredump.h index 0f2e3b2a433..afa918be179 100644 --- a/include/debug/coredump.h +++ b/include/debug/coredump.h @@ -78,6 +78,7 @@ enum coredump_tgt_code { COREDUMP_TGT_X86_64, COREDUMP_TGT_ARM_CORTEX_M, COREDUMP_TGT_RISC_V, + COREDUMP_TGT_XTENSA, }; /* Coredump header */ diff --git a/soc/xtensa/esp32/Kconfig.soc b/soc/xtensa/esp32/Kconfig.soc index a36ad340bdd..c067b21242f 100644 --- a/soc/xtensa/esp32/Kconfig.soc +++ b/soc/xtensa/esp32/Kconfig.soc @@ -8,6 +8,7 @@ config SOC_ESP32 select CLOCK_CONTROL_ESP32 select DYNAMIC_INTERRUPTS select ARCH_HAS_GDBSTUB + select ARCH_SUPPORTS_COREDUMP if SOC_ESP32 diff --git a/soc/xtensa/sample_controller/Kconfig.soc b/soc/xtensa/sample_controller/Kconfig.soc index d1ca1e189ad..0fbdce896c7 100644 --- a/soc/xtensa/sample_controller/Kconfig.soc +++ b/soc/xtensa/sample_controller/Kconfig.soc @@ -5,3 +5,4 @@ config SOC_XTENSA_SAMPLE_CONTROLLER bool "Xtensa sample_controller core" select XTENSA select XTENSA_HAL + select ARCH_SUPPORTS_COREDUMP diff --git a/subsys/debug/Kconfig b/subsys/debug/Kconfig index 40dfcb141da..284fadcd264 100644 --- a/subsys/debug/Kconfig +++ b/subsys/debug/Kconfig @@ -357,7 +357,7 @@ config GDBSTUB_SERIAL_BACKEND bool "Use serial backend" depends on SERIAL help - Use serial as backenf for GDB + Use serial as backend for GDB endchoice @@ -366,7 +366,7 @@ config GDBSTUB_SERIAL_BACKEND_NAME depends on GDBSTUB_SERIAL_BACKEND default "UART_0" help - Use serial as backenf for GDB + Use serial as backend for GDB config GDBSTUB_BUF_SZ int "GDB backend send/receive buffer size (in bytes)" diff --git a/subsys/debug/coredump/coredump_backend_flash_partition.c b/subsys/debug/coredump/coredump_backend_flash_partition.c index f8402aa0583..a870f73948a 100644 --- a/subsys/debug/coredump/coredump_backend_flash_partition.c +++ b/subsys/debug/coredump/coredump_backend_flash_partition.c @@ -273,10 +273,9 @@ out: } /** - * @brief Process the stored coredump in flash partition. + * @brief Erase the stored coredump from flash partition. * - * This reads the stored coredump data and processes it via - * the callback function. + * This erases the stored coredump data from the flash partition. * * @return 0 if successful; error otherwise */