mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	riscv: entry: Convert to generic entry
This patch converts riscv to use the generic entry infrastructure from kernel/entry/*. The generic entry makes maintainers' work easier and codes more elegant. Here are the changes: - More clear entry.S with handle_exception and ret_from_exception - Get rid of complex custom signal implementation - Move syscall procedure from assembly to C, which is much more readable. - Connect ret_from_fork & ret_from_kernel_thread to generic entry. - Wrap with irqentry_enter/exit and syscall_enter/exit_from_user_mode - Use the standard preemption code instead of custom Suggested-by: Huacai Chen <chenhuacai@kernel.org> Reviewed-by: Björn Töpel <bjorn@rivosinc.com> Tested-by: Yipeng Zou <zouyipeng@huawei.com> Tested-by: Jisheng Zhang <jszhang@kernel.org> Signed-off-by: Guo Ren <guoren@linux.alibaba.com> Signed-off-by: Guo Ren <guoren@kernel.org> Cc: Ben Hutchings <ben@decadent.org.uk> Link: https://lore.kernel.org/r/20230222033021.983168-5-guoren@kernel.org Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
This commit is contained in:
		
							parent
							
								
									d0db02c628
								
							
						
					
					
						commit
						f0bddf5058
					
				
					 14 changed files with 210 additions and 315 deletions
				
			
		| 
						 | 
					@ -60,6 +60,7 @@ config RISCV
 | 
				
			||||||
	select GENERIC_ATOMIC64 if !64BIT
 | 
						select GENERIC_ATOMIC64 if !64BIT
 | 
				
			||||||
	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 | 
						select GENERIC_CLOCKEVENTS_BROADCAST if SMP
 | 
				
			||||||
	select GENERIC_EARLY_IOREMAP
 | 
						select GENERIC_EARLY_IOREMAP
 | 
				
			||||||
 | 
						select GENERIC_ENTRY
 | 
				
			||||||
	select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO
 | 
						select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO
 | 
				
			||||||
	select GENERIC_IDLE_POLL_SETUP
 | 
						select GENERIC_IDLE_POLL_SETUP
 | 
				
			||||||
	select GENERIC_IOREMAP if MMU
 | 
						select GENERIC_IOREMAP if MMU
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,5 +27,7 @@ DECLARE_DO_ERROR_INFO(do_trap_break);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage unsigned long get_overflow_stack(void);
 | 
					asmlinkage unsigned long get_overflow_stack(void);
 | 
				
			||||||
asmlinkage void handle_bad_stack(struct pt_regs *regs);
 | 
					asmlinkage void handle_bad_stack(struct pt_regs *regs);
 | 
				
			||||||
 | 
					asmlinkage void do_page_fault(struct pt_regs *regs);
 | 
				
			||||||
 | 
					asmlinkage void do_irq(struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_RISCV_PROTOTYPES_H */
 | 
					#endif /* _ASM_RISCV_PROTOTYPES_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,6 @@
 | 
				
			||||||
#define SR_UXL		_AC(0x300000000, UL) /* XLEN mask for U-mode */
 | 
					#define SR_UXL		_AC(0x300000000, UL) /* XLEN mask for U-mode */
 | 
				
			||||||
#define SR_UXL_32	_AC(0x100000000, UL) /* XLEN = 32 for U-mode */
 | 
					#define SR_UXL_32	_AC(0x100000000, UL) /* XLEN = 32 for U-mode */
 | 
				
			||||||
#define SR_UXL_64	_AC(0x200000000, UL) /* XLEN = 64 for U-mode */
 | 
					#define SR_UXL_64	_AC(0x200000000, UL) /* XLEN = 64 for U-mode */
 | 
				
			||||||
#define SR_UXL_SHIFT	32
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SATP flags */
 | 
					/* SATP flags */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								arch/riscv/include/asm/entry-common.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								arch/riscv/include/asm/entry-common.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _ASM_RISCV_ENTRY_COMMON_H
 | 
				
			||||||
 | 
					#define _ASM_RISCV_ENTRY_COMMON_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/stacktrace.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void handle_page_fault(struct pt_regs *regs);
 | 
				
			||||||
 | 
					void handle_break(struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* _ASM_RISCV_ENTRY_COMMON_H */
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,9 @@ struct pt_regs {
 | 
				
			||||||
	unsigned long orig_a0;
 | 
						unsigned long orig_a0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PTRACE_SYSEMU			0x1f
 | 
				
			||||||
 | 
					#define PTRACE_SYSEMU_SINGLESTEP	0x20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_64BIT
 | 
					#ifdef CONFIG_64BIT
 | 
				
			||||||
#define REG_FMT "%016lx"
 | 
					#define REG_FMT "%016lx"
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					@ -121,8 +124,6 @@ extern unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
 | 
					void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
 | 
				
			||||||
			   unsigned long frame_pointer);
 | 
								   unsigned long frame_pointer);
 | 
				
			||||||
int do_syscall_trace_enter(struct pt_regs *regs);
 | 
					 | 
				
			||||||
void do_syscall_trace_exit(struct pt_regs *regs);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * regs_get_register() - get register value from its offset
 | 
					 * regs_get_register() - get register value from its offset
 | 
				
			||||||
| 
						 | 
					@ -172,6 +173,11 @@ static inline unsigned long regs_get_kernel_argument(struct pt_regs *regs,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int regs_irqs_disabled(struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return !(regs->status & SR_PIE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __ASSEMBLY__ */
 | 
					#endif /* __ASSEMBLY__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_RISCV_PTRACE_H */
 | 
					#endif /* _ASM_RISCV_PTRACE_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,4 +16,9 @@ extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *re
 | 
				
			||||||
extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
 | 
					extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
 | 
				
			||||||
			   const char *loglvl);
 | 
								   const char *loglvl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool on_thread_stack(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_RISCV_STACKTRACE_H */
 | 
					#endif /* _ASM_RISCV_STACKTRACE_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,5 +74,26 @@ static inline int syscall_get_arch(struct task_struct *task)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef long (*syscall_t)(ulong, ulong, ulong, ulong, ulong, ulong, ulong);
 | 
				
			||||||
 | 
					static inline void syscall_handler(struct pt_regs *regs, ulong syscall)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						syscall_t fn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						if ((regs->status & SR_UXL) == SR_UXL_32)
 | 
				
			||||||
 | 
							fn = compat_sys_call_table[syscall];
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							fn = sys_call_table[syscall];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						regs->a0 = fn(regs->orig_a0, regs->a1, regs->a2,
 | 
				
			||||||
 | 
							      regs->a3, regs->a4, regs->a5, regs->a6);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t);
 | 
					asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t);
 | 
				
			||||||
#endif	/* _ASM_RISCV_SYSCALL_H */
 | 
					#endif	/* _ASM_RISCV_SYSCALL_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,6 +67,7 @@ struct thread_info {
 | 
				
			||||||
	long			kernel_sp;	/* Kernel stack pointer */
 | 
						long			kernel_sp;	/* Kernel stack pointer */
 | 
				
			||||||
	long			user_sp;	/* User stack pointer */
 | 
						long			user_sp;	/* User stack pointer */
 | 
				
			||||||
	int			cpu;
 | 
						int			cpu;
 | 
				
			||||||
 | 
						unsigned long		syscall_work;	/* SYSCALL_WORK_ flags */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -89,26 +90,18 @@ struct thread_info {
 | 
				
			||||||
 * - pending work-to-be-done flags are in lowest half-word
 | 
					 * - pending work-to-be-done flags are in lowest half-word
 | 
				
			||||||
 * - other flags in upper half-word(s)
 | 
					 * - other flags in upper half-word(s)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define TIF_SYSCALL_TRACE	0	/* syscall trace active */
 | 
					 | 
				
			||||||
#define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 | 
					#define TIF_NOTIFY_RESUME	1	/* callback before returning to user */
 | 
				
			||||||
#define TIF_SIGPENDING		2	/* signal pending */
 | 
					#define TIF_SIGPENDING		2	/* signal pending */
 | 
				
			||||||
#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 | 
					#define TIF_NEED_RESCHED	3	/* rescheduling necessary */
 | 
				
			||||||
#define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
 | 
					#define TIF_RESTORE_SIGMASK	4	/* restore signal mask in do_signal() */
 | 
				
			||||||
#define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 | 
					#define TIF_MEMDIE		5	/* is terminating due to OOM killer */
 | 
				
			||||||
#define TIF_SYSCALL_TRACEPOINT  6       /* syscall tracepoint instrumentation */
 | 
					 | 
				
			||||||
#define TIF_SYSCALL_AUDIT	7	/* syscall auditing */
 | 
					 | 
				
			||||||
#define TIF_SECCOMP		8	/* syscall secure computing */
 | 
					 | 
				
			||||||
#define TIF_NOTIFY_SIGNAL	9	/* signal notifications exist */
 | 
					#define TIF_NOTIFY_SIGNAL	9	/* signal notifications exist */
 | 
				
			||||||
#define TIF_UPROBE		10	/* uprobe breakpoint or singlestep */
 | 
					#define TIF_UPROBE		10	/* uprobe breakpoint or singlestep */
 | 
				
			||||||
#define TIF_32BIT		11	/* compat-mode 32bit process */
 | 
					#define TIF_32BIT		11	/* compat-mode 32bit process */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define _TIF_SYSCALL_TRACE	(1 << TIF_SYSCALL_TRACE)
 | 
					 | 
				
			||||||
#define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 | 
					#define _TIF_NOTIFY_RESUME	(1 << TIF_NOTIFY_RESUME)
 | 
				
			||||||
#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 | 
					#define _TIF_SIGPENDING		(1 << TIF_SIGPENDING)
 | 
				
			||||||
#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 | 
					#define _TIF_NEED_RESCHED	(1 << TIF_NEED_RESCHED)
 | 
				
			||||||
#define _TIF_SYSCALL_TRACEPOINT	(1 << TIF_SYSCALL_TRACEPOINT)
 | 
					 | 
				
			||||||
#define _TIF_SYSCALL_AUDIT	(1 << TIF_SYSCALL_AUDIT)
 | 
					 | 
				
			||||||
#define _TIF_SECCOMP		(1 << TIF_SECCOMP)
 | 
					 | 
				
			||||||
#define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 | 
					#define _TIF_NOTIFY_SIGNAL	(1 << TIF_NOTIFY_SIGNAL)
 | 
				
			||||||
#define _TIF_UPROBE		(1 << TIF_UPROBE)
 | 
					#define _TIF_UPROBE		(1 << TIF_UPROBE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -116,8 +109,4 @@ struct thread_info {
 | 
				
			||||||
	(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \
 | 
						(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | _TIF_NEED_RESCHED | \
 | 
				
			||||||
	 _TIF_NOTIFY_SIGNAL | _TIF_UPROBE)
 | 
						 _TIF_NOTIFY_SIGNAL | _TIF_UPROBE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define _TIF_SYSCALL_WORK \
 | 
					 | 
				
			||||||
	(_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT | \
 | 
					 | 
				
			||||||
	 _TIF_SECCOMP)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* _ASM_RISCV_THREAD_INFO_H */
 | 
					#endif /* _ASM_RISCV_THREAD_INFO_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,11 +14,7 @@
 | 
				
			||||||
#include <asm/asm-offsets.h>
 | 
					#include <asm/asm-offsets.h>
 | 
				
			||||||
#include <asm/errata_list.h>
 | 
					#include <asm/errata_list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if !IS_ENABLED(CONFIG_PREEMPTION)
 | 
					SYM_CODE_START(handle_exception)
 | 
				
			||||||
.set resume_kernel, restore_all
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ENTRY(handle_exception)
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If coming from userspace, preserve the user thread pointer and load
 | 
						 * If coming from userspace, preserve the user thread pointer and load
 | 
				
			||||||
	 * the kernel thread pointer.  If we came from the kernel, the scratch
 | 
						 * the kernel thread pointer.  If we came from the kernel, the scratch
 | 
				
			||||||
| 
						 | 
					@ -106,19 +102,8 @@ _save_context:
 | 
				
			||||||
.option norelax
 | 
					.option norelax
 | 
				
			||||||
	la gp, __global_pointer$
 | 
						la gp, __global_pointer$
 | 
				
			||||||
.option pop
 | 
					.option pop
 | 
				
			||||||
 | 
						move a0, sp /* pt_regs */
 | 
				
			||||||
#ifdef CONFIG_TRACE_IRQFLAGS
 | 
						la ra, ret_from_exception
 | 
				
			||||||
	call __trace_hardirqs_off
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_CONTEXT_TRACKING_USER
 | 
					 | 
				
			||||||
	/* If previous state is in user mode, call user_exit_callable(). */
 | 
					 | 
				
			||||||
	li   a0, SR_PP
 | 
					 | 
				
			||||||
	and a0, s1, a0
 | 
					 | 
				
			||||||
	bnez a0, skip_context_tracking
 | 
					 | 
				
			||||||
	call user_exit_callable
 | 
					 | 
				
			||||||
skip_context_tracking:
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * MSB of cause differentiates between
 | 
						 * MSB of cause differentiates between
 | 
				
			||||||
| 
						 | 
					@ -126,38 +111,13 @@ skip_context_tracking:
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	bge s4, zero, 1f
 | 
						bge s4, zero, 1f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	la ra, ret_from_exception
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Handle interrupts */
 | 
						/* Handle interrupts */
 | 
				
			||||||
	move a0, sp /* pt_regs */
 | 
						tail do_irq
 | 
				
			||||||
	la a1, generic_handle_arch_irq
 | 
					 | 
				
			||||||
	jr a1
 | 
					 | 
				
			||||||
1:
 | 
					1:
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Exceptions run with interrupts enabled or disabled depending on the
 | 
					 | 
				
			||||||
	 * state of SR_PIE in m/sstatus.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	andi t0, s1, SR_PIE
 | 
					 | 
				
			||||||
	beqz t0, 1f
 | 
					 | 
				
			||||||
	/* kprobes, entered via ebreak, must have interrupts disabled. */
 | 
					 | 
				
			||||||
	li t0, EXC_BREAKPOINT
 | 
					 | 
				
			||||||
	beq s4, t0, 1f
 | 
					 | 
				
			||||||
#ifdef CONFIG_TRACE_IRQFLAGS
 | 
					 | 
				
			||||||
	call __trace_hardirqs_on
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	csrs CSR_STATUS, SR_IE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1:
 | 
					 | 
				
			||||||
	la ra, ret_from_exception
 | 
					 | 
				
			||||||
	/* Handle syscalls */
 | 
					 | 
				
			||||||
	li t0, EXC_SYSCALL
 | 
					 | 
				
			||||||
	beq s4, t0, handle_syscall
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Handle other exceptions */
 | 
						/* Handle other exceptions */
 | 
				
			||||||
	slli t0, s4, RISCV_LGPTR
 | 
						slli t0, s4, RISCV_LGPTR
 | 
				
			||||||
	la t1, excp_vect_table
 | 
						la t1, excp_vect_table
 | 
				
			||||||
	la t2, excp_vect_table_end
 | 
						la t2, excp_vect_table_end
 | 
				
			||||||
	move a0, sp /* pt_regs */
 | 
					 | 
				
			||||||
	add t0, t1, t0
 | 
						add t0, t1, t0
 | 
				
			||||||
	/* Check if exception code lies within bounds */
 | 
						/* Check if exception code lies within bounds */
 | 
				
			||||||
	bgeu t0, t2, 1f
 | 
						bgeu t0, t2, 1f
 | 
				
			||||||
| 
						 | 
					@ -165,95 +125,17 @@ skip_context_tracking:
 | 
				
			||||||
	jr t0
 | 
						jr t0
 | 
				
			||||||
1:
 | 
					1:
 | 
				
			||||||
	tail do_trap_unknown
 | 
						tail do_trap_unknown
 | 
				
			||||||
 | 
					SYM_CODE_END(handle_exception)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
handle_syscall:
 | 
					/*
 | 
				
			||||||
#ifdef CONFIG_RISCV_M_MODE
 | 
					 * The ret_from_exception must be called with interrupt disabled. Here is the
 | 
				
			||||||
	/*
 | 
					 * caller list:
 | 
				
			||||||
	 * When running is M-Mode (no MMU config), MPIE does not get set.
 | 
					 *  - handle_exception
 | 
				
			||||||
	 * As a result, we need to force enable interrupts here because
 | 
					 *  - ret_from_fork
 | 
				
			||||||
	 * handle_exception did not do set SR_IE as it always sees SR_PIE
 | 
					 *  - ret_from_kernel_thread
 | 
				
			||||||
	 * being cleared.
 | 
					 */
 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	csrs CSR_STATUS, SR_IE
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING_USER)
 | 
					 | 
				
			||||||
	/* Recover a0 - a7 for system calls */
 | 
					 | 
				
			||||||
	REG_L a0, PT_A0(sp)
 | 
					 | 
				
			||||||
	REG_L a1, PT_A1(sp)
 | 
					 | 
				
			||||||
	REG_L a2, PT_A2(sp)
 | 
					 | 
				
			||||||
	REG_L a3, PT_A3(sp)
 | 
					 | 
				
			||||||
	REG_L a4, PT_A4(sp)
 | 
					 | 
				
			||||||
	REG_L a5, PT_A5(sp)
 | 
					 | 
				
			||||||
	REG_L a6, PT_A6(sp)
 | 
					 | 
				
			||||||
	REG_L a7, PT_A7(sp)
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	 /* save the initial A0 value (needed in signal handlers) */
 | 
					 | 
				
			||||||
	REG_S a0, PT_ORIG_A0(sp)
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Advance SEPC to avoid executing the original
 | 
					 | 
				
			||||||
	 * scall instruction on sret
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	addi s2, s2, 0x4
 | 
					 | 
				
			||||||
	REG_S s2, PT_EPC(sp)
 | 
					 | 
				
			||||||
	/* Trace syscalls, but only if requested by the user. */
 | 
					 | 
				
			||||||
	REG_L t0, TASK_TI_FLAGS(tp)
 | 
					 | 
				
			||||||
	andi t0, t0, _TIF_SYSCALL_WORK
 | 
					 | 
				
			||||||
	bnez t0, handle_syscall_trace_enter
 | 
					 | 
				
			||||||
check_syscall_nr:
 | 
					 | 
				
			||||||
	/* Check to make sure we don't jump to a bogus syscall number. */
 | 
					 | 
				
			||||||
	li t0, __NR_syscalls
 | 
					 | 
				
			||||||
	la s0, sys_ni_syscall
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Syscall number held in a7.
 | 
					 | 
				
			||||||
	 * If syscall number is above allowed value, redirect to ni_syscall.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	bgeu a7, t0, 3f
 | 
					 | 
				
			||||||
#ifdef CONFIG_COMPAT
 | 
					 | 
				
			||||||
	REG_L s0, PT_STATUS(sp)
 | 
					 | 
				
			||||||
	srli s0, s0, SR_UXL_SHIFT
 | 
					 | 
				
			||||||
	andi s0, s0, (SR_UXL >> SR_UXL_SHIFT)
 | 
					 | 
				
			||||||
	li t0, (SR_UXL_32 >> SR_UXL_SHIFT)
 | 
					 | 
				
			||||||
	sub t0, s0, t0
 | 
					 | 
				
			||||||
	bnez t0, 1f
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Call compat_syscall */
 | 
					 | 
				
			||||||
	la s0, compat_sys_call_table
 | 
					 | 
				
			||||||
	j 2f
 | 
					 | 
				
			||||||
1:
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	/* Call syscall */
 | 
					 | 
				
			||||||
	la s0, sys_call_table
 | 
					 | 
				
			||||||
2:
 | 
					 | 
				
			||||||
	slli t0, a7, RISCV_LGPTR
 | 
					 | 
				
			||||||
	add s0, s0, t0
 | 
					 | 
				
			||||||
	REG_L s0, 0(s0)
 | 
					 | 
				
			||||||
3:
 | 
					 | 
				
			||||||
	jalr s0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ret_from_syscall:
 | 
					 | 
				
			||||||
	/* Set user a0 to kernel a0 */
 | 
					 | 
				
			||||||
	REG_S a0, PT_A0(sp)
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * We didn't execute the actual syscall.
 | 
					 | 
				
			||||||
	 * Seccomp already set return value for the current task pt_regs.
 | 
					 | 
				
			||||||
	 * (If it was configured with SECCOMP_RET_ERRNO/TRACE)
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
ret_from_syscall_rejected:
 | 
					 | 
				
			||||||
#ifdef CONFIG_DEBUG_RSEQ
 | 
					 | 
				
			||||||
	move a0, sp
 | 
					 | 
				
			||||||
	call rseq_syscall
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	/* Trace syscalls, but only if requested by the user. */
 | 
					 | 
				
			||||||
	REG_L t0, TASK_TI_FLAGS(tp)
 | 
					 | 
				
			||||||
	andi t0, t0, _TIF_SYSCALL_WORK
 | 
					 | 
				
			||||||
	bnez t0, handle_syscall_trace_exit
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SYM_CODE_START_NOALIGN(ret_from_exception)
 | 
					SYM_CODE_START_NOALIGN(ret_from_exception)
 | 
				
			||||||
	REG_L s0, PT_STATUS(sp)
 | 
						REG_L s0, PT_STATUS(sp)
 | 
				
			||||||
	csrc CSR_STATUS, SR_IE
 | 
					 | 
				
			||||||
#ifdef CONFIG_TRACE_IRQFLAGS
 | 
					 | 
				
			||||||
	call __trace_hardirqs_off
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_RISCV_M_MODE
 | 
					#ifdef CONFIG_RISCV_M_MODE
 | 
				
			||||||
	/* the MPP value is too large to be used as an immediate arg for addi */
 | 
						/* the MPP value is too large to be used as an immediate arg for addi */
 | 
				
			||||||
	li t0, SR_MPP
 | 
						li t0, SR_MPP
 | 
				
			||||||
| 
						 | 
					@ -261,17 +143,7 @@ SYM_CODE_START_NOALIGN(ret_from_exception)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	andi s0, s0, SR_SPP
 | 
						andi s0, s0, SR_SPP
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	bnez s0, resume_kernel
 | 
						bnez s0, 1f
 | 
				
			||||||
SYM_CODE_END(ret_from_exception)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Interrupts must be disabled here so flags are checked atomically */
 | 
					 | 
				
			||||||
	REG_L s0, TASK_TI_FLAGS(tp) /* current_thread_info->flags */
 | 
					 | 
				
			||||||
	andi s1, s0, _TIF_WORK_MASK
 | 
					 | 
				
			||||||
	bnez s1, resume_userspace_slow
 | 
					 | 
				
			||||||
resume_userspace:
 | 
					 | 
				
			||||||
#ifdef CONFIG_CONTEXT_TRACKING_USER
 | 
					 | 
				
			||||||
	call user_enter_callable
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Save unwound kernel stack pointer in thread_info */
 | 
						/* Save unwound kernel stack pointer in thread_info */
 | 
				
			||||||
	addi s0, sp, PT_SIZE_ON_STACK
 | 
						addi s0, sp, PT_SIZE_ON_STACK
 | 
				
			||||||
| 
						 | 
					@ -282,18 +154,7 @@ resume_userspace:
 | 
				
			||||||
	 * structures again.
 | 
						 * structures again.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	csrw CSR_SCRATCH, tp
 | 
						csrw CSR_SCRATCH, tp
 | 
				
			||||||
 | 
					 | 
				
			||||||
restore_all:
 | 
					 | 
				
			||||||
#ifdef CONFIG_TRACE_IRQFLAGS
 | 
					 | 
				
			||||||
	REG_L s1, PT_STATUS(sp)
 | 
					 | 
				
			||||||
	andi t0, s1, SR_PIE
 | 
					 | 
				
			||||||
	beqz t0, 1f
 | 
					 | 
				
			||||||
	call __trace_hardirqs_on
 | 
					 | 
				
			||||||
	j 2f
 | 
					 | 
				
			||||||
1:
 | 
					1:
 | 
				
			||||||
	call __trace_hardirqs_off
 | 
					 | 
				
			||||||
2:
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	REG_L a0, PT_STATUS(sp)
 | 
						REG_L a0, PT_STATUS(sp)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The current load reservation is effectively part of the processor's
 | 
						 * The current load reservation is effectively part of the processor's
 | 
				
			||||||
| 
						 | 
					@ -356,47 +217,10 @@ restore_all:
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	sret
 | 
						sret
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					SYM_CODE_END(ret_from_exception)
 | 
				
			||||||
#if IS_ENABLED(CONFIG_PREEMPTION)
 | 
					 | 
				
			||||||
resume_kernel:
 | 
					 | 
				
			||||||
	REG_L s0, TASK_TI_PREEMPT_COUNT(tp)
 | 
					 | 
				
			||||||
	bnez s0, restore_all
 | 
					 | 
				
			||||||
	REG_L s0, TASK_TI_FLAGS(tp)
 | 
					 | 
				
			||||||
	andi s0, s0, _TIF_NEED_RESCHED
 | 
					 | 
				
			||||||
	beqz s0, restore_all
 | 
					 | 
				
			||||||
	call preempt_schedule_irq
 | 
					 | 
				
			||||||
	j restore_all
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
resume_userspace_slow:
 | 
					 | 
				
			||||||
	/* Enter slow path for supplementary processing */
 | 
					 | 
				
			||||||
	move a0, sp /* pt_regs */
 | 
					 | 
				
			||||||
	move a1, s0 /* current_thread_info->flags */
 | 
					 | 
				
			||||||
	call do_work_pending
 | 
					 | 
				
			||||||
	j resume_userspace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Slow paths for ptrace. */
 | 
					 | 
				
			||||||
handle_syscall_trace_enter:
 | 
					 | 
				
			||||||
	move a0, sp
 | 
					 | 
				
			||||||
	call do_syscall_trace_enter
 | 
					 | 
				
			||||||
	move t0, a0
 | 
					 | 
				
			||||||
	REG_L a0, PT_A0(sp)
 | 
					 | 
				
			||||||
	REG_L a1, PT_A1(sp)
 | 
					 | 
				
			||||||
	REG_L a2, PT_A2(sp)
 | 
					 | 
				
			||||||
	REG_L a3, PT_A3(sp)
 | 
					 | 
				
			||||||
	REG_L a4, PT_A4(sp)
 | 
					 | 
				
			||||||
	REG_L a5, PT_A5(sp)
 | 
					 | 
				
			||||||
	REG_L a6, PT_A6(sp)
 | 
					 | 
				
			||||||
	REG_L a7, PT_A7(sp)
 | 
					 | 
				
			||||||
	bnez t0, ret_from_syscall_rejected
 | 
					 | 
				
			||||||
	j check_syscall_nr
 | 
					 | 
				
			||||||
handle_syscall_trace_exit:
 | 
					 | 
				
			||||||
	move a0, sp
 | 
					 | 
				
			||||||
	call do_syscall_trace_exit
 | 
					 | 
				
			||||||
	j ret_from_exception
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_VMAP_STACK
 | 
					#ifdef CONFIG_VMAP_STACK
 | 
				
			||||||
handle_kernel_stack_overflow:
 | 
					SYM_CODE_START_LOCAL(handle_kernel_stack_overflow)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Takes the psuedo-spinlock for the shadow stack, in case multiple
 | 
						 * Takes the psuedo-spinlock for the shadow stack, in case multiple
 | 
				
			||||||
	 * harts are concurrently overflowing their kernel stacks.  We could
 | 
						 * harts are concurrently overflowing their kernel stacks.  We could
 | 
				
			||||||
| 
						 | 
					@ -505,23 +329,25 @@ restore_caller_reg:
 | 
				
			||||||
	REG_S s5, PT_TP(sp)
 | 
						REG_S s5, PT_TP(sp)
 | 
				
			||||||
	move a0, sp
 | 
						move a0, sp
 | 
				
			||||||
	tail handle_bad_stack
 | 
						tail handle_bad_stack
 | 
				
			||||||
 | 
					SYM_CODE_END(handle_kernel_stack_overflow)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
END(handle_exception)
 | 
					SYM_CODE_START(ret_from_fork)
 | 
				
			||||||
 | 
						call schedule_tail
 | 
				
			||||||
ENTRY(ret_from_fork)
 | 
						move a0, sp /* pt_regs */
 | 
				
			||||||
	la ra, ret_from_exception
 | 
						la ra, ret_from_exception
 | 
				
			||||||
	tail schedule_tail
 | 
						tail syscall_exit_to_user_mode
 | 
				
			||||||
ENDPROC(ret_from_fork)
 | 
					SYM_CODE_END(ret_from_fork)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENTRY(ret_from_kernel_thread)
 | 
					SYM_CODE_START(ret_from_kernel_thread)
 | 
				
			||||||
	call schedule_tail
 | 
						call schedule_tail
 | 
				
			||||||
	/* Call fn(arg) */
 | 
						/* Call fn(arg) */
 | 
				
			||||||
	la ra, ret_from_exception
 | 
					 | 
				
			||||||
	move a0, s1
 | 
						move a0, s1
 | 
				
			||||||
	jr s0
 | 
						jalr s0
 | 
				
			||||||
ENDPROC(ret_from_kernel_thread)
 | 
						move a0, sp /* pt_regs */
 | 
				
			||||||
 | 
						la ra, ret_from_exception
 | 
				
			||||||
 | 
						tail syscall_exit_to_user_mode
 | 
				
			||||||
 | 
					SYM_CODE_END(ret_from_kernel_thread)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Integer register context switch
 | 
					 * Integer register context switch
 | 
				
			||||||
| 
						 | 
					@ -533,7 +359,7 @@ ENDPROC(ret_from_kernel_thread)
 | 
				
			||||||
 * The value of a0 and a1 must be preserved by this function, as that's how
 | 
					 * The value of a0 and a1 must be preserved by this function, as that's how
 | 
				
			||||||
 * arguments are passed to schedule_tail.
 | 
					 * arguments are passed to schedule_tail.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
ENTRY(__switch_to)
 | 
					SYM_FUNC_START(__switch_to)
 | 
				
			||||||
	/* Save context into prev->thread */
 | 
						/* Save context into prev->thread */
 | 
				
			||||||
	li    a4,  TASK_THREAD_RA
 | 
						li    a4,  TASK_THREAD_RA
 | 
				
			||||||
	add   a3, a0, a4
 | 
						add   a3, a0, a4
 | 
				
			||||||
| 
						 | 
					@ -570,7 +396,7 @@ ENTRY(__switch_to)
 | 
				
			||||||
	/* The offset of thread_info in task_struct is zero. */
 | 
						/* The offset of thread_info in task_struct is zero. */
 | 
				
			||||||
	move tp, a1
 | 
						move tp, a1
 | 
				
			||||||
	ret
 | 
						ret
 | 
				
			||||||
ENDPROC(__switch_to)
 | 
					SYM_FUNC_END(__switch_to)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CONFIG_MMU
 | 
					#ifndef CONFIG_MMU
 | 
				
			||||||
#define do_page_fault do_trap_unknown
 | 
					#define do_page_fault do_trap_unknown
 | 
				
			||||||
| 
						 | 
					@ -579,7 +405,7 @@ ENDPROC(__switch_to)
 | 
				
			||||||
	.section ".rodata"
 | 
						.section ".rodata"
 | 
				
			||||||
	.align LGREG
 | 
						.align LGREG
 | 
				
			||||||
	/* Exception vector table */
 | 
						/* Exception vector table */
 | 
				
			||||||
ENTRY(excp_vect_table)
 | 
					SYM_CODE_START(excp_vect_table)
 | 
				
			||||||
	RISCV_PTR do_trap_insn_misaligned
 | 
						RISCV_PTR do_trap_insn_misaligned
 | 
				
			||||||
	ALT_INSN_FAULT(RISCV_PTR do_trap_insn_fault)
 | 
						ALT_INSN_FAULT(RISCV_PTR do_trap_insn_fault)
 | 
				
			||||||
	RISCV_PTR do_trap_insn_illegal
 | 
						RISCV_PTR do_trap_insn_illegal
 | 
				
			||||||
| 
						 | 
					@ -588,7 +414,7 @@ ENTRY(excp_vect_table)
 | 
				
			||||||
	RISCV_PTR do_trap_load_fault
 | 
						RISCV_PTR do_trap_load_fault
 | 
				
			||||||
	RISCV_PTR do_trap_store_misaligned
 | 
						RISCV_PTR do_trap_store_misaligned
 | 
				
			||||||
	RISCV_PTR do_trap_store_fault
 | 
						RISCV_PTR do_trap_store_fault
 | 
				
			||||||
	RISCV_PTR do_trap_ecall_u /* system call, gets intercepted */
 | 
						RISCV_PTR do_trap_ecall_u /* system call */
 | 
				
			||||||
	RISCV_PTR do_trap_ecall_s
 | 
						RISCV_PTR do_trap_ecall_s
 | 
				
			||||||
	RISCV_PTR do_trap_unknown
 | 
						RISCV_PTR do_trap_unknown
 | 
				
			||||||
	RISCV_PTR do_trap_ecall_m
 | 
						RISCV_PTR do_trap_ecall_m
 | 
				
			||||||
| 
						 | 
					@ -598,11 +424,11 @@ ENTRY(excp_vect_table)
 | 
				
			||||||
	RISCV_PTR do_trap_unknown
 | 
						RISCV_PTR do_trap_unknown
 | 
				
			||||||
	RISCV_PTR do_page_fault   /* store page fault */
 | 
						RISCV_PTR do_page_fault   /* store page fault */
 | 
				
			||||||
excp_vect_table_end:
 | 
					excp_vect_table_end:
 | 
				
			||||||
END(excp_vect_table)
 | 
					SYM_CODE_END(excp_vect_table)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CONFIG_MMU
 | 
					#ifndef CONFIG_MMU
 | 
				
			||||||
ENTRY(__user_rt_sigreturn)
 | 
					SYM_CODE_START(__user_rt_sigreturn)
 | 
				
			||||||
	li a7, __NR_rt_sigreturn
 | 
						li a7, __NR_rt_sigreturn
 | 
				
			||||||
	scall
 | 
						scall
 | 
				
			||||||
END(__user_rt_sigreturn)
 | 
					SYM_CODE_END(__user_rt_sigreturn)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern atomic_t hart_lottery;
 | 
					extern atomic_t hart_lottery;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage void do_page_fault(struct pt_regs *regs);
 | 
					 | 
				
			||||||
asmlinkage void __init setup_vm(uintptr_t dtb_pa);
 | 
					asmlinkage void __init setup_vm(uintptr_t dtb_pa);
 | 
				
			||||||
#ifdef CONFIG_XIP_KERNEL
 | 
					#ifdef CONFIG_XIP_KERNEL
 | 
				
			||||||
asmlinkage void __init __copy_data(void);
 | 
					asmlinkage void __init __copy_data(void);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,9 +19,6 @@
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
#include <linux/sched/task_stack.h>
 | 
					#include <linux/sched/task_stack.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CREATE_TRACE_POINTS
 | 
					 | 
				
			||||||
#include <trace/events/syscalls.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum riscv_regset {
 | 
					enum riscv_regset {
 | 
				
			||||||
	REGSET_X,
 | 
						REGSET_X,
 | 
				
			||||||
#ifdef CONFIG_FPU
 | 
					#ifdef CONFIG_FPU
 | 
				
			||||||
| 
						 | 
					@ -228,46 +225,6 @@ long arch_ptrace(struct task_struct *child, long request,
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Allows PTRACE_SYSCALL to work.  These are called from entry.S in
 | 
					 | 
				
			||||||
 * {handle,ret_from}_syscall.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
__visible int do_syscall_trace_enter(struct pt_regs *regs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (test_thread_flag(TIF_SYSCALL_TRACE))
 | 
					 | 
				
			||||||
		if (ptrace_report_syscall_entry(regs))
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Do the secure computing after ptrace; failures should be fast.
 | 
					 | 
				
			||||||
	 * If this fails we might have return value in a0 from seccomp
 | 
					 | 
				
			||||||
	 * (via SECCOMP_RET_ERRNO/TRACE).
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (secure_computing() == -1)
 | 
					 | 
				
			||||||
		return -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 | 
					 | 
				
			||||||
	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 | 
					 | 
				
			||||||
		trace_sys_enter(regs, syscall_get_nr(current, regs));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	audit_syscall_entry(regs->a7, regs->a0, regs->a1, regs->a2, regs->a3);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
__visible void do_syscall_trace_exit(struct pt_regs *regs)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	audit_syscall_exit(regs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (test_thread_flag(TIF_SYSCALL_TRACE))
 | 
					 | 
				
			||||||
		ptrace_report_syscall_exit(regs, 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
 | 
					 | 
				
			||||||
	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 | 
					 | 
				
			||||||
		trace_sys_exit(regs, regs_return_value(regs));
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_COMPAT
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
static int compat_riscv_gpr_get(struct task_struct *target,
 | 
					static int compat_riscv_gpr_get(struct task_struct *target,
 | 
				
			||||||
				const struct user_regset *regset,
 | 
									const struct user_regset *regset,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <linux/syscalls.h>
 | 
					#include <linux/syscalls.h>
 | 
				
			||||||
#include <linux/resume_user_mode.h>
 | 
					#include <linux/resume_user_mode.h>
 | 
				
			||||||
#include <linux/linkage.h>
 | 
					#include <linux/linkage.h>
 | 
				
			||||||
 | 
					#include <linux/entry-common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/ucontext.h>
 | 
					#include <asm/ucontext.h>
 | 
				
			||||||
#include <asm/vdso.h>
 | 
					#include <asm/vdso.h>
 | 
				
			||||||
| 
						 | 
					@ -274,7 +275,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 | 
				
			||||||
	signal_setup_done(ret, ksig, 0);
 | 
						signal_setup_done(ret, ksig, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void do_signal(struct pt_regs *regs)
 | 
					void arch_do_signal_or_restart(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ksignal ksig;
 | 
						struct ksignal ksig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -311,29 +312,3 @@ static void do_signal(struct pt_regs *regs)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	restore_saved_sigmask();
 | 
						restore_saved_sigmask();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Handle any pending work on the resume-to-userspace path, as indicated by
 | 
					 | 
				
			||||||
 * _TIF_WORK_MASK. Entered from assembly with IRQs off.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
asmlinkage __visible void do_work_pending(struct pt_regs *regs,
 | 
					 | 
				
			||||||
					  unsigned long thread_info_flags)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	do {
 | 
					 | 
				
			||||||
		if (thread_info_flags & _TIF_NEED_RESCHED) {
 | 
					 | 
				
			||||||
			schedule();
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			local_irq_enable();
 | 
					 | 
				
			||||||
			if (thread_info_flags & _TIF_UPROBE)
 | 
					 | 
				
			||||||
				uprobe_notify_resume(regs);
 | 
					 | 
				
			||||||
			/* Handle pending signal delivery */
 | 
					 | 
				
			||||||
			if (thread_info_flags & (_TIF_SIGPENDING |
 | 
					 | 
				
			||||||
						 _TIF_NOTIFY_SIGNAL))
 | 
					 | 
				
			||||||
				do_signal(regs);
 | 
					 | 
				
			||||||
			if (thread_info_flags & _TIF_NOTIFY_RESUME)
 | 
					 | 
				
			||||||
				resume_user_mode_work(regs);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		local_irq_disable();
 | 
					 | 
				
			||||||
		thread_info_flags = read_thread_flags();
 | 
					 | 
				
			||||||
	} while (thread_info_flags & _TIF_WORK_MASK);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,12 +17,14 @@
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
#include <linux/irq.h>
 | 
					#include <linux/irq.h>
 | 
				
			||||||
#include <linux/kexec.h>
 | 
					#include <linux/kexec.h>
 | 
				
			||||||
 | 
					#include <linux/entry-common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/asm-prototypes.h>
 | 
					#include <asm/asm-prototypes.h>
 | 
				
			||||||
#include <asm/bug.h>
 | 
					#include <asm/bug.h>
 | 
				
			||||||
#include <asm/csr.h>
 | 
					#include <asm/csr.h>
 | 
				
			||||||
#include <asm/processor.h>
 | 
					#include <asm/processor.h>
 | 
				
			||||||
#include <asm/ptrace.h>
 | 
					#include <asm/ptrace.h>
 | 
				
			||||||
 | 
					#include <asm/syscall.h>
 | 
				
			||||||
#include <asm/thread_info.h>
 | 
					#include <asm/thread_info.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int show_unhandled_signals = 1;
 | 
					int show_unhandled_signals = 1;
 | 
				
			||||||
| 
						 | 
					@ -123,10 +125,18 @@ static void do_trap_error(struct pt_regs *regs, int signo, int code,
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define __trap_section noinstr
 | 
					#define __trap_section noinstr
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#define DO_ERROR_INFO(name, signo, code, str)				\
 | 
					#define DO_ERROR_INFO(name, signo, code, str)					\
 | 
				
			||||||
asmlinkage __visible __trap_section void name(struct pt_regs *regs)	\
 | 
					asmlinkage __visible __trap_section void name(struct pt_regs *regs)		\
 | 
				
			||||||
{									\
 | 
					{										\
 | 
				
			||||||
	do_trap_error(regs, signo, code, regs->epc, "Oops - " str);	\
 | 
						if (user_mode(regs)) {							\
 | 
				
			||||||
 | 
							irqentry_enter_from_user_mode(regs);				\
 | 
				
			||||||
 | 
							do_trap_error(regs, signo, code, regs->epc, "Oops - " str);	\
 | 
				
			||||||
 | 
							irqentry_exit_to_user_mode(regs);				\
 | 
				
			||||||
 | 
						} else {								\
 | 
				
			||||||
 | 
							irqentry_state_t state = irqentry_nmi_enter(regs);		\
 | 
				
			||||||
 | 
							do_trap_error(regs, signo, code, regs->epc, "Oops - " str);	\
 | 
				
			||||||
 | 
							irqentry_nmi_exit(regs, state);					\
 | 
				
			||||||
 | 
						}									\
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DO_ERROR_INFO(do_trap_unknown,
 | 
					DO_ERROR_INFO(do_trap_unknown,
 | 
				
			||||||
| 
						 | 
					@ -148,26 +158,50 @@ DO_ERROR_INFO(do_trap_store_misaligned,
 | 
				
			||||||
int handle_misaligned_load(struct pt_regs *regs);
 | 
					int handle_misaligned_load(struct pt_regs *regs);
 | 
				
			||||||
int handle_misaligned_store(struct pt_regs *regs);
 | 
					int handle_misaligned_store(struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage void __trap_section do_trap_load_misaligned(struct pt_regs *regs)
 | 
					asmlinkage __visible __trap_section void do_trap_load_misaligned(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!handle_misaligned_load(regs))
 | 
						if (user_mode(regs)) {
 | 
				
			||||||
		return;
 | 
							irqentry_enter_from_user_mode(regs);
 | 
				
			||||||
	do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
 | 
					
 | 
				
			||||||
		      "Oops - load address misaligned");
 | 
							if (handle_misaligned_load(regs))
 | 
				
			||||||
 | 
								do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
 | 
				
			||||||
 | 
								      "Oops - load address misaligned");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_exit_to_user_mode(regs);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							irqentry_state_t state = irqentry_nmi_enter(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (handle_misaligned_load(regs))
 | 
				
			||||||
 | 
								do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
 | 
				
			||||||
 | 
								      "Oops - load address misaligned");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_nmi_exit(regs, state);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage void __trap_section do_trap_store_misaligned(struct pt_regs *regs)
 | 
					asmlinkage __visible __trap_section void do_trap_store_misaligned(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!handle_misaligned_store(regs))
 | 
						if (user_mode(regs)) {
 | 
				
			||||||
		return;
 | 
							irqentry_enter_from_user_mode(regs);
 | 
				
			||||||
	do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
 | 
					
 | 
				
			||||||
		      "Oops - store (or AMO) address misaligned");
 | 
							if (handle_misaligned_store(regs))
 | 
				
			||||||
 | 
								do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
 | 
				
			||||||
 | 
									"Oops - store (or AMO) address misaligned");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_exit_to_user_mode(regs);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							irqentry_state_t state = irqentry_nmi_enter(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (handle_misaligned_store(regs))
 | 
				
			||||||
 | 
								do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->epc,
 | 
				
			||||||
 | 
									"Oops - store (or AMO) address misaligned");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_nmi_exit(regs, state);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
DO_ERROR_INFO(do_trap_store_fault,
 | 
					DO_ERROR_INFO(do_trap_store_fault,
 | 
				
			||||||
	SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
 | 
						SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault");
 | 
				
			||||||
DO_ERROR_INFO(do_trap_ecall_u,
 | 
					 | 
				
			||||||
	SIGILL, ILL_ILLTRP, "environment call from U-mode");
 | 
					 | 
				
			||||||
DO_ERROR_INFO(do_trap_ecall_s,
 | 
					DO_ERROR_INFO(do_trap_ecall_s,
 | 
				
			||||||
	SIGILL, ILL_ILLTRP, "environment call from S-mode");
 | 
						SIGILL, ILL_ILLTRP, "environment call from S-mode");
 | 
				
			||||||
DO_ERROR_INFO(do_trap_ecall_m,
 | 
					DO_ERROR_INFO(do_trap_ecall_m,
 | 
				
			||||||
| 
						 | 
					@ -183,7 +217,7 @@ static inline unsigned long get_break_insn_length(unsigned long pc)
 | 
				
			||||||
	return GET_INSN_LENGTH(insn);
 | 
						return GET_INSN_LENGTH(insn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
 | 
					void handle_break(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_KPROBES
 | 
					#ifdef CONFIG_KPROBES
 | 
				
			||||||
	if (kprobe_single_step_handler(regs))
 | 
						if (kprobe_single_step_handler(regs))
 | 
				
			||||||
| 
						 | 
					@ -213,7 +247,77 @@ asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		die(regs, "Kernel BUG");
 | 
							die(regs, "Kernel BUG");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
NOKPROBE_SYMBOL(do_trap_break);
 | 
					
 | 
				
			||||||
 | 
					asmlinkage __visible __trap_section void do_trap_break(struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (user_mode(regs)) {
 | 
				
			||||||
 | 
							irqentry_enter_from_user_mode(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							handle_break(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_exit_to_user_mode(regs);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							irqentry_state_t state = irqentry_nmi_enter(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							handle_break(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_nmi_exit(regs, state);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					asmlinkage __visible __trap_section void do_trap_ecall_u(struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (user_mode(regs)) {
 | 
				
			||||||
 | 
							ulong syscall = regs->a7;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							syscall = syscall_enter_from_user_mode(regs, syscall);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							regs->epc += 4;
 | 
				
			||||||
 | 
							regs->orig_a0 = regs->a0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (syscall < NR_syscalls)
 | 
				
			||||||
 | 
								syscall_handler(regs, syscall);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								regs->a0 = -ENOSYS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							syscall_exit_to_user_mode(regs);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							irqentry_state_t state = irqentry_nmi_enter(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->epc,
 | 
				
			||||||
 | 
								"Oops - environment call from U-mode");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							irqentry_nmi_exit(regs, state);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MMU
 | 
				
			||||||
 | 
					asmlinkage __visible noinstr void do_page_fault(struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						irqentry_state_t state = irqentry_enter(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						handle_page_fault(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						local_irq_disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irqentry_exit(regs, state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					asmlinkage __visible noinstr void do_irq(struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pt_regs *old_regs;
 | 
				
			||||||
 | 
						irqentry_state_t state = irqentry_enter(regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irq_enter_rcu();
 | 
				
			||||||
 | 
						old_regs = set_irq_regs(regs);
 | 
				
			||||||
 | 
						handle_arch_irq(regs);
 | 
				
			||||||
 | 
						set_irq_regs(old_regs);
 | 
				
			||||||
 | 
						irq_exit_rcu();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						irqentry_exit(regs, state);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_GENERIC_BUG
 | 
					#ifdef CONFIG_GENERIC_BUG
 | 
				
			||||||
int is_valid_bugaddr(unsigned long pc)
 | 
					int is_valid_bugaddr(unsigned long pc)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,7 @@
 | 
				
			||||||
#include <linux/uaccess.h>
 | 
					#include <linux/uaccess.h>
 | 
				
			||||||
#include <linux/kprobes.h>
 | 
					#include <linux/kprobes.h>
 | 
				
			||||||
#include <linux/kfence.h>
 | 
					#include <linux/kfence.h>
 | 
				
			||||||
 | 
					#include <linux/entry-common.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/ptrace.h>
 | 
					#include <asm/ptrace.h>
 | 
				
			||||||
#include <asm/tlbflush.h>
 | 
					#include <asm/tlbflush.h>
 | 
				
			||||||
| 
						 | 
					@ -204,7 +205,7 @@ static inline bool access_error(unsigned long cause, struct vm_area_struct *vma)
 | 
				
			||||||
 * This routine handles page faults.  It determines the address and the
 | 
					 * This routine handles page faults.  It determines the address and the
 | 
				
			||||||
 * problem, and then passes it off to one of the appropriate routines.
 | 
					 * problem, and then passes it off to one of the appropriate routines.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
asmlinkage void do_page_fault(struct pt_regs *regs)
 | 
					void handle_page_fault(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *tsk;
 | 
						struct task_struct *tsk;
 | 
				
			||||||
	struct vm_area_struct *vma;
 | 
						struct vm_area_struct *vma;
 | 
				
			||||||
| 
						 | 
					@ -251,7 +252,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	/* Enable interrupts if they were enabled in the parent context. */
 | 
						/* Enable interrupts if they were enabled in the parent context. */
 | 
				
			||||||
	if (likely(regs->status & SR_PIE))
 | 
						if (!regs_irqs_disabled(regs))
 | 
				
			||||||
		local_irq_enable();
 | 
							local_irq_enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -356,4 +357,3 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
NOKPROBE_SYMBOL(do_page_fault);
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue