summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Holland <samuel.holland@sifive.com>2026-06-24 19:31:48 +0800
committerPaul Walmsley <pjw@kernel.org>2026-06-25 13:44:27 -0600
commitc4c7756a81b5baef286bf9be1ea404f3e4dd7a3c (patch)
treeb93f139c874fe87f08e64b190a07a2d9df091ce3
parent57ad674d032baf5426a38b0d6b2ddd60cbd3913f (diff)
riscv: Fix 32-bit call_on_irq_stack() frame pointer ABI
call_on_irq_stack() uses struct member offsets to set up its link in the frame record list. On riscv32, struct stackframe is the wrong size to maintain stack pointer alignment, so STACKFRAME_SIZE_ON_STACK includes padding. However, the ABI requires the frame record to be placed immediately below the address stored in s0, so the padding must come before the struct members. Fix the layout by making STACKFRAME_FP and STACKFRAME_RA the negative offsets from s0, instead of the positive offsets from sp. Fixes: 82982fdd5133 ("riscv: Deduplicate IRQ stack switching") Signed-off-by: Samuel Holland <samuel.holland@sifive.com> Reviewed-by: Matthew Bystrin <dev.mbstr@gmail.com> Signed-off-by: Rui Qi <qirui.001@bytedance.com> Link: https://lore.kernel.org/all/20240530001733.1407654-2-samuel.holland@sifive.com/ Reviewed-by: Nam Cao <namcao@linutronix.de> Link: https://patch.msgid.link/20260624113148.3723541-1-qirui.001@bytedance.com [pjw@kernel.org: cleaned up the patch tags and added Matthew's Reviewed-by] Signed-off-by: Paul Walmsley <pjw@kernel.org>
-rw-r--r--arch/riscv/kernel/asm-offsets.c4
-rw-r--r--arch/riscv/kernel/entry.S8
2 files changed, 6 insertions, 6 deletions
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index af827448a609..a75f0cfea1e9 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -501,8 +501,8 @@ void asm_offsets(void)
OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr);
DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN));
- OFFSET(STACKFRAME_FP, stackframe, fp);
- OFFSET(STACKFRAME_RA, stackframe, ra);
+ DEFINE(STACKFRAME_FP, offsetof(struct stackframe, fp) - sizeof(struct stackframe));
+ DEFINE(STACKFRAME_RA, offsetof(struct stackframe, ra) - sizeof(struct stackframe));
#ifdef CONFIG_FUNCTION_TRACER
DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func));
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index c6988983cdf7..08df724e13b9 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -386,8 +386,8 @@ SYM_CODE_END(ret_from_fork_user_asm)
SYM_FUNC_START(call_on_irq_stack)
/* Create a frame record to save ra and s0 (fp) */
addi sp, sp, -STACKFRAME_SIZE_ON_STACK
- REG_S ra, STACKFRAME_RA(sp)
- REG_S s0, STACKFRAME_FP(sp)
+ REG_S ra, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_RA)(sp)
+ REG_S s0, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_FP)(sp)
addi s0, sp, STACKFRAME_SIZE_ON_STACK
/* Switch to the per-CPU shadow call stack */
@@ -405,8 +405,8 @@ SYM_FUNC_START(call_on_irq_stack)
/* Switch back to the thread stack and restore ra and s0 */
addi sp, s0, -STACKFRAME_SIZE_ON_STACK
- REG_L ra, STACKFRAME_RA(sp)
- REG_L s0, STACKFRAME_FP(sp)
+ REG_L ra, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_RA)(sp)
+ REG_L s0, (STACKFRAME_SIZE_ON_STACK + STACKFRAME_FP)(sp)
addi sp, sp, STACKFRAME_SIZE_ON_STACK
ret