diff --git a/arch/arm/core/cortex_a_r/swap_helper.S b/arch/arm/core/cortex_a_r/swap_helper.S index 548bb446aa3195..8508ab1cbb41eb 100644 --- a/arch/arm/core/cortex_a_r/swap_helper.S +++ b/arch/arm/core/cortex_a_r/swap_helper.S @@ -336,12 +336,14 @@ _context_switch: _oops: /* - * Pass the exception frame to z_do_kernel_oops. r0 contains the - * exception reason. + * Pass the exception frame to z_do_kernel_oops. */ cps #MODE_SYS mov r0, sp cps #MODE_SVC + /* zero callee_regs and EXC_RETURN (only used on Cortex-M) */ + mov r1, #0 + mov r2, #0 bl z_do_kernel_oops b z_arm_int_exit diff --git a/arch/arm/core/cortex_a_r/switch.S b/arch/arm/core/cortex_a_r/switch.S index 800d46bbf94ddd..259103de043137 100644 --- a/arch/arm/core/cortex_a_r/switch.S +++ b/arch/arm/core/cortex_a_r/switch.S @@ -150,10 +150,12 @@ offload: _oops: /* - * Pass the exception frame to z_do_kernel_oops. r0 contains the - * exception reason. + * Pass the exception frame to z_do_kernel_oops. */ mov r0, sp + /* zero callee_regs and EXC_RETURN (only used on Cortex-M) */ + mov r1, #0 + mov r2, #0 bl z_do_kernel_oops inv: diff --git a/arch/arm/core/cortex_m/fault.c b/arch/arm/core/cortex_m/fault.c index 78b87092976f6a..4158ff1fc908ad 100644 --- a/arch/arm/core/cortex_m/fault.c +++ b/arch/arm/core/cortex_m/fault.c @@ -1113,7 +1113,7 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return, "ESF could not be retrieved successfully. Shall never occur."); #ifdef CONFIG_DEBUG_COREDUMP - z_arm_coredump_fault_sp = POINTER_TO_UINT(esf); + z_arm_coredump_fault_sp = POINTER_TO_UINT(esf) + z_arm_get_hw_esf_size(exc_return); #endif reason = fault_handle(esf, fault, &recoverable); diff --git a/arch/arm/core/cortex_m/swap_helper.S b/arch/arm/core/cortex_m/swap_helper.S index c2cb3ef7f2fea3..536782d87e58d1 100644 --- a/arch/arm/core/cortex_m/swap_helper.S +++ b/arch/arm/core/cortex_m/swap_helper.S @@ -313,6 +313,7 @@ _oops: push {r1, r2} push {r4-r11} mov r1, sp /* pointer to _callee_saved_t */ + mov r2, lr /* EXC_RETURN */ #endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */ #endif /* CONFIG_EXTRA_EXCEPTION_INFO */ bl z_do_kernel_oops diff --git a/arch/arm/core/cortex_m/thread.c b/arch/arm/core/cortex_m/thread.c index fa500032d3cc0e..eaaae9f3c7d0dd 100644 --- a/arch/arm/core/cortex_m/thread.c +++ b/arch/arm/core/cortex_m/thread.c @@ -28,11 +28,6 @@ #define FP_GUARD_EXTRA_SIZE 0 #endif -#ifndef EXC_RETURN_FTYPE -/* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ -#define EXC_RETURN_FTYPE (0x00000010UL) -#endif - /* Default last octet of EXC_RETURN, for threads that have not run yet. * The full EXC_RETURN value will be e.g. 0xFFFFFFBC. */ diff --git a/arch/arm/core/fatal.c b/arch/arm/core/fatal.c index 4532e238f05c99..09fdf4f9469e41 100644 --- a/arch/arm/core/fatal.c +++ b/arch/arm/core/fatal.c @@ -101,11 +101,13 @@ void z_arm_fatal_error(unsigned int reason, const struct arch_esf *esf) * * @param esf exception frame * @param callee_regs Callee-saved registers (R4-R11) + * @param exc_return EXC_RETURN value stored in lr on exception entry */ -void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs) +void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs, uint32_t exc_return) { #if !(defined(CONFIG_EXTRA_EXCEPTION_INFO) && defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)) ARG_UNUSED(callee_regs); + ARG_UNUSED(exc_return); #endif /* Stacked R0 holds the exception reason. */ unsigned int reason = esf->basic.r0; @@ -127,6 +129,10 @@ void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs) #endif /* CONFIG_USERSPACE */ +#ifdef CONFIG_DEBUG_COREDUMP + z_arm_coredump_fault_sp = POINTER_TO_UINT(esf) + z_arm_get_hw_esf_size(exc_return); +#endif + #if !defined(CONFIG_EXTRA_EXCEPTION_INFO) z_arm_fatal_error(reason, esf); #else diff --git a/include/zephyr/arch/arm/cortex_m/exception.h b/include/zephyr/arch/arm/cortex_m/exception.h index 2deed9bdf832df..db00c98efb02fc 100644 --- a/include/zephyr/arch/arm/cortex_m/exception.h +++ b/include/zephyr/arch/arm/cortex_m/exception.h @@ -56,6 +56,11 @@ #define _EXC_PENDSV_PRIO 0xff #define _EXC_PENDSV_PRIO_MASK Z_EXC_PRIO(_EXC_PENDSV_PRIO) +#ifndef EXC_RETURN_FTYPE +/* bit [4] allocate stack for floating-point context: 0=done 1=skipped */ +#define EXC_RETURN_FTYPE (0x00000010UL) +#endif + #ifdef _ASMLANGUAGE GTEXT(z_arm_exc_exit); #else @@ -119,6 +124,22 @@ struct arch_esf { extern uint32_t z_arm_coredump_fault_sp; +/* Returns the size of the exception frame pushed by hardware, in bytes. */ +static inline int z_arm_get_hw_esf_size(uint32_t exc_return) +{ +#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING) + if ((exc_return & EXC_RETURN_FTYPE) == 0) { + /* Thread had used FPU instructions and Extended stack frame was pushed */ + return sizeof(struct __basic_sf) + sizeof(struct __fpu_sf); + } +#else + ARG_UNUSED(exc_return); +#endif + + /* Only Basic stack frame was pushed */ + return sizeof(struct __basic_sf); +} + extern void z_arm_exc_exit(void); #ifdef __cplusplus