From 301cb74890c2a27a8221cf86ec598d4295549e4d Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Wed, 30 Nov 2022 11:12:30 +0800 Subject: [PATCH] coredump: custom core dump stack is now supported on Xtensa targets --- .../port/riscv/esp_core_dump_port_impl.h | 28 ++++++-- .../port/xtensa/esp_core_dump_port_impl.h | 70 ++++++++++++++++--- components/espcoredump/src/core_dump_common.c | 10 +-- components/xtensa/include/xt_instr_macros.h | 7 +- 4 files changed, 92 insertions(+), 23 deletions(-) diff --git a/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h b/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h index 0d9b5bbfd40..bb142801e49 100644 --- a/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h +++ b/components/espcoredump/include_core_dump/port/riscv/esp_core_dump_port_impl.h @@ -23,23 +23,39 @@ extern "C" { #endif +/** + * @brief Define the type that will be used to describe the current context when + * doing a backup of the current stack. This same structure is used to restore the stack. + */ +typedef struct { + uint32_t sp; +} core_dump_stack_context_t; + /** * @brief Set the stack pointer to the address passed as a parameter. * @note This function must be inlined. * * @param new_sp New stack pointer to set in sp register. - * - * @return Former stack pointer address (sp register value). + * @param old_ctx CPU context, related to SP, to fill. It will be given back when restoring SP. */ -FORCE_INLINE_ATTR void* esp_core_dump_replace_sp(void* new_sp) +FORCE_INLINE_ATTR void esp_core_dump_replace_sp(void* new_sp, core_dump_stack_context_t* old_ctx) { - void* current_sp = NULL; asm volatile ("mv %0, sp \n\t\ mv sp, %1 \n\t\ " - : "=&r"(current_sp) + : "=&r"(old_ctx->sp) : "r"(new_sp)); - return current_sp; +} + + +/** + * @brief Restore the stack pointer that was returned when calling `esp_core_dump_replace_sp()` function. + * + * @param ctx CPU context, related to SP, to restore. + */ +FORCE_INLINE_ATTR void esp_core_dump_restore_sp(core_dump_stack_context_t* old_ctx) +{ + asm volatile ("mv sp, %0 \n\t" :: "r"(old_ctx->sp)); } #ifdef __cplusplus diff --git a/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h b/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h index 54daff1d517..f1b5c9ea7a0 100644 --- a/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h +++ b/components/espcoredump/include_core_dump/port/xtensa/esp_core_dump_port_impl.h @@ -33,23 +33,75 @@ extern "C" { #endif +/** + * @brief Define the type that will be used to describe the current context when + * doing a backup of the current stack. This same structure is used to restore the stack. + */ +typedef struct { + uint32_t sp; + uint32_t a0; + uint32_t ps; + uint32_t windowbase; + uint32_t windowstart; +} core_dump_stack_context_t; + /** * @brief Set the stack pointer to the address passed as a parameter. * @note This function must be inlined. * * @param new_sp New stack pointer to set in sp register. - * - * @return Former stack pointer address (sp register value). + * @param old_ctx CPU context, related to SP, to fill. It will be given back when restoring SP. */ -FORCE_INLINE_ATTR void* esp_core_dump_replace_sp(void* new_sp) +FORCE_INLINE_ATTR void esp_core_dump_replace_sp(void* new_sp, core_dump_stack_context_t* old_ctx) { - void* current_sp = NULL; - asm volatile ("mov %0, sp \n\t\ - " - : "=&r"(current_sp) - :); + /* We have to spill all the windows to the stack first as the new stack pointer + * represents a clean new environment. */ + xthal_window_spill(); + + /* Backup the special registers PS, WindowBase and WindowStart. We will need to restore them later */ + asm volatile ("mov %0, sp \n" \ + "mov %1, a0 \n" \ + "rsr.ps %2 \n"\ + "rsr.windowbase %3 \n"\ + "rsr.windowstart %4 \n"\ + : "=r"(old_ctx->sp), + "=r"(old_ctx->a0), + "=r"(old_ctx->ps), + "=r"(old_ctx->windowbase), + "=r"(old_ctx->windowstart) :); + + /* Set the new stack */ SET_STACK(new_sp); - return current_sp; +} + + +/** + * @brief Restore the stack pointer that was returned when calling `esp_core_dump_replace_sp()` function. + * + * @param ctx CPU context, related to SP, to restore. + */ +FORCE_INLINE_ATTR void esp_core_dump_restore_sp(core_dump_stack_context_t* old_ctx) +{ + /* Start by disabling WindowOverflowEnable bit from PS to make sure we won't get a Window Overflow exception + * restoring WindowBase and WindowStart registers */ + const uint32_t ps_woe = old_ctx->ps & ~(PS_WOE_MASK); + asm volatile ( \ + "wsr.ps %0 \n"\ + "rsync \n"\ + "wsr.windowbase %1 \n"\ + "rsync \n"\ + "wsr.windowstart %2 \n"\ + "rsync \n"\ + "mov sp, %3 \n" \ + "mov a0, %4 \n" \ + "wsr.ps %5 \n"\ + "rsync \n"\ + :: "r"(ps_woe), + "r"(old_ctx->windowbase), + "r"(old_ctx->windowstart), + "r"(old_ctx->sp), + "r"(old_ctx->a0), + "r"(old_ctx->ps)); } #ifdef __cplusplus diff --git a/components/espcoredump/src/core_dump_common.c b/components/espcoredump/src/core_dump_common.c index 24607d1b651..241065fa84a 100644 --- a/components/espcoredump/src/core_dump_common.c +++ b/components/espcoredump/src/core_dump_common.c @@ -57,7 +57,7 @@ extern int _coredump_rtc_fast_end; static uint8_t s_coredump_stack[ESP_COREDUMP_STACK_SIZE]; static uint8_t* s_core_dump_sp = NULL; -static uint8_t* s_core_dump_backup = NULL; +static core_dump_stack_context_t s_stack_context; /** * @brief Function setting up the core dump stack. @@ -77,9 +77,9 @@ FORCE_INLINE_ATTR void esp_core_dump_setup_stack(void) /* Replace the stack pointer depending on the architecture, but save the * current stack pointer, in order to be able too restore it later. * This function must be inlined. */ - s_core_dump_backup = esp_core_dump_replace_sp(s_core_dump_sp); + esp_core_dump_replace_sp(s_core_dump_sp, &s_stack_context); ESP_COREDUMP_LOGI("Backing up stack @ %p and use core dump stack @ %p", - s_core_dump_backup, esp_cpu_get_sp()); + s_stack_context.sp, esp_cpu_get_sp()); } /** @@ -111,8 +111,8 @@ FORCE_INLINE_ATTR void esp_core_dump_report_stack_usage(void) s_core_dump_sp - s_coredump_stack - bytes_free, bytes_free); /* Restore the stack pointer. */ - ESP_COREDUMP_LOGI("Restoring stack @ %p", s_core_dump_backup); - esp_core_dump_replace_sp(s_core_dump_backup); + ESP_COREDUMP_LOGI("Restoring stack @ %p", s_stack_context.sp); + esp_core_dump_restore_sp(&s_stack_context); } #else diff --git a/components/xtensa/include/xt_instr_macros.h b/components/xtensa/include/xt_instr_macros.h index efcdbd4a78c..e3a11990208 100644 --- a/components/xtensa/include/xt_instr_macros.h +++ b/components/xtensa/include/xt_instr_macros.h @@ -84,11 +84,11 @@ do { \ uint32_t sp = (uint32_t)new_sp - SAVE_AREA_OFFSET; \ *(uint32_t*)(sp - BASE_AREA_SP_OFFSET) = (uint32_t)new_sp; \ + const uint32_t mask = ~(PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK); \ uint32_t tmp1 = 0, tmp2 = 0; \ asm volatile ( \ "rsr.ps %1 \n"\ - "movi %2, ~" XTSTR( PS_WOE_MASK | PS_OWB_MASK | PS_CALLINC_MASK ) " \n"\ - "and %1, %1, %2 \n"\ + "and %1, %1, %3 \n"\ "wsr.ps %1 \n"\ "rsync \n"\ " \n"\ @@ -99,6 +99,7 @@ "wsr.windowstart %1 \n"\ "rsync \n"\ " \n"\ + "movi a0, 0\n" \ "mov sp, %0 \n"\ "rsr.ps %1 \n"\ " \n"\ @@ -107,6 +108,6 @@ "or %1, %1, %2 \n"\ "wsr.ps %1 \n"\ "rsync \n"\ - : "+r"(sp), "+r"(tmp1), "+r"(tmp2)); \ + : "+r"(sp), "+r"(tmp1), "+r"(tmp2) : "r"(mask)); \ } while (0); #endif // __ASSEMBLER__