[PATCH 4/4] riscv: entry: Save a frame record for exceptions

Samuel Holland samuel.holland at sifive.com
Wed May 29 17:15:59 PDT 2024


This follows the frame pointer ABI and allows stack traces to cross
exception boundaries without a special case in the stack walking code.

Signed-off-by: Samuel Holland <samuel.holland at sifive.com>
---

 arch/riscv/include/asm/processor.h  |  9 +++++++--
 arch/riscv/include/asm/ptrace.h     |  5 +++++
 arch/riscv/include/asm/stacktrace.h |  5 -----
 arch/riscv/kernel/asm-offsets.c     |  6 +++---
 arch/riscv/kernel/entry.S           | 16 ++++++++++------
 arch/riscv/kernel/head.S            |  6 ++----
 arch/riscv/kernel/stacktrace.c      |  9 ---------
 7 files changed, 27 insertions(+), 29 deletions(-)

diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 68c3432dc6ea..ccbb1e363c7f 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -144,9 +144,14 @@ static inline void arch_thread_struct_whitelist(unsigned long *offset,
 	.align_ctl = PR_UNALIGN_NOPRINT,		\
 }
 
+#ifdef CONFIG_FRAME_POINTER
+#define EXCEPTION_FRAME_SIZE ALIGN(sizeof(struct pt_regs) + sizeof(struct stackframe), STACK_ALIGN)
+#else
+#define EXCEPTION_FRAME_SIZE ALIGN(sizeof(struct pt_regs), STACK_ALIGN)
+#endif
+
 #define task_pt_regs(tsk)						\
-	((struct pt_regs *)(task_stack_page(tsk) + THREAD_SIZE		\
-			    - ALIGN(sizeof(struct pt_regs), STACK_ALIGN)))
+	((struct pt_regs *)(task_stack_page(tsk) + THREAD_SIZE - EXCEPTION_FRAME_SIZE))
 
 #define KSTK_EIP(tsk)		(task_pt_regs(tsk)->epc)
 #define KSTK_ESP(tsk)		(task_pt_regs(tsk)->sp)
diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h
index b5b0adcc85c1..f475f6acec49 100644
--- a/arch/riscv/include/asm/ptrace.h
+++ b/arch/riscv/include/asm/ptrace.h
@@ -12,6 +12,11 @@
 
 #ifndef __ASSEMBLY__
 
+struct stackframe {
+	unsigned long fp;
+	unsigned long ra;
+};
+
 struct pt_regs {
 	unsigned long epc;
 	unsigned long ra;
diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h
index b1495a7e06ce..3019558f747c 100644
--- a/arch/riscv/include/asm/stacktrace.h
+++ b/arch/riscv/include/asm/stacktrace.h
@@ -6,11 +6,6 @@
 #include <linux/sched.h>
 #include <asm/ptrace.h>
 
-struct stackframe {
-	unsigned long fp;
-	unsigned long ra;
-};
-
 extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
 				    bool (*fn)(void *, unsigned long), void *arg);
 extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index 84c056f5ee09..582b52713e93 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -477,10 +477,10 @@ void asm_offsets(void)
 	);
 
 	/*
-	 * We allocate a pt_regs on the stack when entering the kernel.  This
-	 * ensures the alignment is sane.
+	 * We allocate a pt_regs and possibly a stackframe on the stack when
+	 * entering the kernel. This ensures the alignment is sane.
 	 */
-	DEFINE(PT_SIZE_ON_STACK, ALIGN(sizeof(struct pt_regs), STACK_ALIGN));
+	DEFINE(EXCEPTION_FRAME_SIZE, EXCEPTION_FRAME_SIZE);
 
 	OFFSET(KERNEL_MAP_VIRT_ADDR, kernel_mapping, virt_addr);
 	OFFSET(SBI_HART_BOOT_TASK_PTR_OFFSET, sbi_hart_boot_data, task_ptr);
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index bd1c5621df45..cdb58ce32cbb 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -33,7 +33,7 @@ SYM_CODE_START(handle_exception)
 	REG_S sp, TASK_TI_KERNEL_SP(tp)
 
 #ifdef CONFIG_VMAP_STACK
-	addi sp, sp, -(PT_SIZE_ON_STACK)
+	addi sp, sp, -EXCEPTION_FRAME_SIZE
 	srli sp, sp, THREAD_SHIFT
 	andi sp, sp, 0x1
 	bnez sp, handle_kernel_stack_overflow
@@ -43,7 +43,7 @@ SYM_CODE_START(handle_exception)
 .Lsave_context:
 	REG_S sp, TASK_TI_USER_SP(tp)
 	REG_L sp, TASK_TI_KERNEL_SP(tp)
-	addi sp, sp, -(PT_SIZE_ON_STACK)
+	addi sp, sp, -EXCEPTION_FRAME_SIZE
 	REG_S x1,  PT_RA(sp)
 	REG_S x3,  PT_GP(sp)
 	REG_S x5,  PT_T0(sp)
@@ -83,6 +83,12 @@ SYM_CODE_START(handle_exception)
 	/* Load the kernel shadow call stack pointer if coming from userspace */
 	scs_load_current_if_task_changed s5
 
+#ifdef CONFIG_FRAME_POINTER
+	REG_S	ra, (EXCEPTION_FRAME_SIZE + STACKFRAME_RA)(sp)
+	REG_S	s0, (EXCEPTION_FRAME_SIZE + STACKFRAME_FP)(sp)
+	addi	s0, sp, EXCEPTION_FRAME_SIZE
+#endif
+
 #ifdef CONFIG_RISCV_ISA_V_PREEMPTIVE
 	move a0, sp
 	call riscv_v_context_nesting_start
@@ -136,7 +142,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception)
 	bnez t0, 1f
 
 	/* Save unwound kernel stack pointer in thread_info */
-	addi t0, sp, PT_SIZE_ON_STACK
+	addi t0, sp, EXCEPTION_FRAME_SIZE
 	REG_S t0, TASK_TI_KERNEL_SP(tp)
 
 	/* Save the kernel shadow call stack pointer */
@@ -192,14 +198,12 @@ SYM_CODE_START_LOCAL(handle_kernel_stack_overflow)
 	/* we reach here from kernel context, sscratch must be 0 */
 	csrrw x31, CSR_SCRATCH, x31
 	asm_per_cpu sp, overflow_stack, x31
-	li x31, OVERFLOW_STACK_SIZE
+	li x31, OVERFLOW_STACK_SIZE - EXCEPTION_FRAME_SIZE
 	add sp, sp, x31
 	/* zero out x31 again and restore x31 */
 	xor x31, x31, x31
 	csrrw x31, CSR_SCRATCH, x31
 
-	addi sp, sp, -(PT_SIZE_ON_STACK)
-
 	//save context to overflow stack
 	REG_S x1,  PT_RA(sp)
 	REG_S x3,  PT_GP(sp)
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 4236a69c35cb..09ee5e6c2a98 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -290,9 +290,8 @@ SYM_CODE_START(_start_kernel)
 
 	/* Initialize page tables and relocate to virtual addresses */
 	la tp, init_task
-	la sp, init_thread_union + THREAD_SIZE
+	la sp, init_thread_union + THREAD_SIZE - EXCEPTION_FRAME_SIZE
 	XIP_FIXUP_OFFSET sp
-	addi sp, sp, -PT_SIZE_ON_STACK
 	scs_load_init_stack
 #ifdef CONFIG_BUILTIN_DTB
 	la a0, __dtb_start
@@ -310,8 +309,7 @@ SYM_CODE_START(_start_kernel)
 	call .Lsetup_trap_vector
 	/* Restore C environment */
 	la tp, init_task
-	la sp, init_thread_union + THREAD_SIZE
-	addi sp, sp, -PT_SIZE_ON_STACK
+	la sp, init_thread_union + THREAD_SIZE - EXCEPTION_FRAME_SIZE
 	scs_load_current
 
 #ifdef CONFIG_KASAN
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 528ec7cc9a62..6be8f8942f6b 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -16,8 +16,6 @@
 
 #ifdef CONFIG_FRAME_POINTER
 
-extern asmlinkage void ret_from_exception(void);
-
 static inline int fp_is_valid(unsigned long fp, unsigned long sp)
 {
 	unsigned long low, high;
@@ -70,13 +68,6 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
 			fp = frame->fp;
 			pc = ftrace_graph_ret_addr(current, NULL, frame->ra,
 						   &frame->ra);
-			if (pc == (unsigned long)ret_from_exception) {
-				if (unlikely(!__kernel_text_address(pc) || !fn(arg, pc)))
-					break;
-
-				pc = ((struct pt_regs *)sp)->epc;
-				fp = ((struct pt_regs *)sp)->s0;
-			}
 		}
 
 	}
-- 
2.44.1




More information about the linux-riscv mailing list