From 32cf92db24ac8b38219cfd76b96b8106049331a2 Mon Sep 17 00:00:00 2001 From: "liang.huang" Date: Sat, 18 Jul 2026 11:38:40 +0800 Subject: [PATCH] arch/risc-v: qemu: don't rewind interrupt stack sp on nested trap qemu-rv's S-mode/non-SMP setintstack unconditionally reloaded sp to the top of the per-cpu interrupt stack. A trap taken while already running on that stack rewound sp back to the same address, so the nested trap's frame overwrote the still-live outer trap's frame. Port the bounds check already used by the canonical setintstack in riscv_macros.S: only move sp when it is outside the interrupt stack range. Other vendor chip.h files have the same unconditional-reload pattern and are left for a follow-up. Signed-off-by: liang.huang --- arch/risc-v/src/qemu-rv/chip.h | 85 +++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/arch/risc-v/src/qemu-rv/chip.h b/arch/risc-v/src/qemu-rv/chip.h index 8c92d861644..91cb8f93a3c 100644 --- a/arch/risc-v/src/qemu-rv/chip.h +++ b/arch/risc-v/src/qemu-rv/chip.h @@ -47,6 +47,45 @@ #ifdef __ASSEMBLY__ +#if CONFIG_ARCH_INTERRUPTSTACK > 15 + +/**************************************************************************** + * Name: setintstack_bounds + * + * Description: + * Set sp to high if sp is outside [low, high], the bounds of the + * interrupt stack for the current CPU. + * + ****************************************************************************/ + +.macro setintstack_bounds high, low + + /* Check if sp is below the low address of the interrupt stack + * (outside the interrupt stack). + */ + + blt sp, \low, 1f + + /* Check if sp is above the high address of the interrupt stack + * (outside the interrupt stack) + */ + + bgt sp, \high, 1f + + /* If sp is within the interrupt stack boundaries, no action is required */ + + j 2f + +1: + /* Set sp to the high address of the interrupt stack (start of the + * interrupt stack) + */ + + mv sp, \high + +2: +.endm + /**************************************************************************** * Name: setintstack * @@ -56,7 +95,7 @@ * ****************************************************************************/ -#if defined(CONFIG_SMP) && CONFIG_ARCH_INTERRUPTSTACK > 15 +#if defined(CONFIG_SMP) .macro setintstack tmp0, tmp1 up_cpu_index \tmp0 li \tmp1, STACKFRAME_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK) @@ -76,40 +115,24 @@ sub \tmp1, \tmp0, \tmp1 - /* Check if sp is below the low address of the interrupt stack - * (outside the interrupt stack). - */ - - blt sp, \tmp1, 1f - - /* Check if sp is above the high address of the interrupt stack - * (outside the interrupt stack) - */ - - bgt sp, \tmp0, 1f - - /* If sp is within the interrupt stack boundaries, no action is required */ - - j 2f - -1: - /* Set sp to the high address of the interrupt stack (start of the - * interrupt stack) - */ - - mv sp, \tmp0 - -2: + setintstack_bounds \tmp0, \tmp1 .endm -#endif /* CONFIG_SMP && CONFIG_ARCH_INTERRUPTSTACK > 15 */ - -#if CONFIG_ARCH_INTERRUPTSTACK > 15 -#if !defined(CONFIG_SMP) && defined(CONFIG_ARCH_USE_S_MODE) +#elif defined(CONFIG_ARCH_USE_S_MODE) .macro setintstack tmp0, tmp1 csrr \tmp0, CSR_SCRATCH - REGLOAD sp, RISCV_PERCPU_IRQSTACK(\tmp0) + REGLOAD \tmp0, RISCV_PERCPU_IRQSTACK(\tmp0) + + /* tmp0 = high address (top) of the interrupt stack for this hart */ + + li \tmp1, STACKFRAME_ALIGN_DOWN(CONFIG_ARCH_INTERRUPTSTACK) + sub \tmp1, \tmp0, \tmp1 + + /* tmp1 = low address of the interrupt stack */ + + setintstack_bounds \tmp0, \tmp1 .endm -#endif /* !defined(CONFIG_SMP) && defined(CONFIG_ARCH_USE_S_MODE) */ +#endif /* defined(CONFIG_SMP) */ + #endif /* CONFIG_ARCH_INTERRUPTSTACK > 15 */ #endif /* __ASSEMBLY__ */