]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
riscv: Fix 32-bit call_on_irq_stack() frame pointer ABI
authorSamuel Holland <samuel.holland@sifive.com>
Wed, 24 Jun 2026 11:31:48 +0000 (19:31 +0800)
committerPaul Walmsley <pjw@kernel.org>
Thu, 25 Jun 2026 19:44:27 +0000 (13:44 -0600)
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>
arch/riscv/kernel/asm-offsets.c
arch/riscv/kernel/entry.S

index af827448a609e699d222f5fa7534fb6b5e8d9254..a75f0cfea1e9faee51708fd5627cf9888c052ad7 100644 (file)
@@ -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
index c6988983cdf7d70315b7a900f11b9765d3e85a02..08df724e13b9dbcfb5f429fe07515039fc2e5900 100644 (file)
@@ -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