Commit e45d6a52 authored by Palmer Dabbelt's avatar Palmer Dabbelt

Merge patch series "riscv: Add GENERIC_ENTRY support"

guoren@kernel.org <guoren@kernel.org> says:

From: Guo Ren <guoren@linux.alibaba.com>

The patches convert riscv to use the generic entry infrastructure from
kernel/entry/*. Some optimization for entry.S with new .macro and merge
ret_from_kernel_thread into ret_from_fork.

* b4-shazam-merge:
  riscv: entry: Consolidate general regs saving/restoring
  riscv: entry: Consolidate ret_from_kernel_thread into ret_from_fork
  riscv: entry: Remove extra level wrappers of trace_hardirqs_{on,off}
  riscv: entry: Convert to generic entry
  riscv: entry: Add noinstr to prevent instrumentation inserted
  riscv: ptrace: Remove duplicate operation

Link: https://lore.kernel.org/r/20230222033021.983168-1-guoren@kernel.orgSigned-off-by: default avatarPalmer Dabbelt <palmer@rivosinc.com>
parents 4b740779 45b32b94
...@@ -60,6 +60,7 @@ config RISCV ...@@ -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); ...@@ -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 */
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#endif #endif
#ifdef __ASSEMBLY__ #ifdef __ASSEMBLY__
#include <asm/asm-offsets.h>
/* Common assembly source macros */ /* Common assembly source macros */
...@@ -81,6 +82,66 @@ ...@@ -81,6 +82,66 @@
.endr .endr
.endm .endm
/* save all GPs except x1 ~ x5 */
.macro save_from_x6_to_x31
REG_S x6, PT_T1(sp)
REG_S x7, PT_T2(sp)
REG_S x8, PT_S0(sp)
REG_S x9, PT_S1(sp)
REG_S x10, PT_A0(sp)
REG_S x11, PT_A1(sp)
REG_S x12, PT_A2(sp)
REG_S x13, PT_A3(sp)
REG_S x14, PT_A4(sp)
REG_S x15, PT_A5(sp)
REG_S x16, PT_A6(sp)
REG_S x17, PT_A7(sp)
REG_S x18, PT_S2(sp)
REG_S x19, PT_S3(sp)
REG_S x20, PT_S4(sp)
REG_S x21, PT_S5(sp)
REG_S x22, PT_S6(sp)
REG_S x23, PT_S7(sp)
REG_S x24, PT_S8(sp)
REG_S x25, PT_S9(sp)
REG_S x26, PT_S10(sp)
REG_S x27, PT_S11(sp)
REG_S x28, PT_T3(sp)
REG_S x29, PT_T4(sp)
REG_S x30, PT_T5(sp)
REG_S x31, PT_T6(sp)
.endm
/* restore all GPs except x1 ~ x5 */
.macro restore_from_x6_to_x31
REG_L x6, PT_T1(sp)
REG_L x7, PT_T2(sp)
REG_L x8, PT_S0(sp)
REG_L x9, PT_S1(sp)
REG_L x10, PT_A0(sp)
REG_L x11, PT_A1(sp)
REG_L x12, PT_A2(sp)
REG_L x13, PT_A3(sp)
REG_L x14, PT_A4(sp)
REG_L x15, PT_A5(sp)
REG_L x16, PT_A6(sp)
REG_L x17, PT_A7(sp)
REG_L x18, PT_S2(sp)
REG_L x19, PT_S3(sp)
REG_L x20, PT_S4(sp)
REG_L x21, PT_S5(sp)
REG_L x22, PT_S6(sp)
REG_L x23, PT_S7(sp)
REG_L x24, PT_S8(sp)
REG_L x25, PT_S9(sp)
REG_L x26, PT_S10(sp)
REG_L x27, PT_S11(sp)
REG_L x28, PT_T3(sp)
REG_L x29, PT_T4(sp)
REG_L x30, PT_T5(sp)
REG_L x31, PT_T6(sp)
.endm
#endif /* __ASSEMBLY__ */ #endif /* __ASSEMBLY__ */
#endif /* _ASM_RISCV_ASM_H */ #endif /* _ASM_RISCV_ASM_H */
...@@ -40,7 +40,6 @@ ...@@ -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 */
......
/* 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 { ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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) ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 */
...@@ -68,8 +68,6 @@ obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o ...@@ -68,8 +68,6 @@ obj-$(CONFIG_CPU_PM) += suspend_entry.o suspend.o
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o
obj-$(CONFIG_TRACE_IRQFLAGS) += trace_irq.o
obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o
obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o
obj-$(CONFIG_RISCV_SBI) += sbi.o obj-$(CONFIG_RISCV_SBI) += sbi.o
......
This diff is collapsed.
...@@ -10,7 +10,6 @@ ...@@ -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);
......
...@@ -66,66 +66,17 @@ ...@@ -66,66 +66,17 @@
REG_S x3, PT_GP(sp) REG_S x3, PT_GP(sp)
REG_S x4, PT_TP(sp) REG_S x4, PT_TP(sp)
REG_S x5, PT_T0(sp) REG_S x5, PT_T0(sp)
REG_S x6, PT_T1(sp) save_from_x6_to_x31
REG_S x7, PT_T2(sp)
REG_S x8, PT_S0(sp)
REG_S x9, PT_S1(sp)
REG_S x10, PT_A0(sp)
REG_S x11, PT_A1(sp)
REG_S x12, PT_A2(sp)
REG_S x13, PT_A3(sp)
REG_S x14, PT_A4(sp)
REG_S x15, PT_A5(sp)
REG_S x16, PT_A6(sp)
REG_S x17, PT_A7(sp)
REG_S x18, PT_S2(sp)
REG_S x19, PT_S3(sp)
REG_S x20, PT_S4(sp)
REG_S x21, PT_S5(sp)
REG_S x22, PT_S6(sp)
REG_S x23, PT_S7(sp)
REG_S x24, PT_S8(sp)
REG_S x25, PT_S9(sp)
REG_S x26, PT_S10(sp)
REG_S x27, PT_S11(sp)
REG_S x28, PT_T3(sp)
REG_S x29, PT_T4(sp)
REG_S x30, PT_T5(sp)
REG_S x31, PT_T6(sp)
.endm .endm
.macro RESTORE_ALL .macro RESTORE_ALL
REG_L t0, PT_EPC(sp)
REG_L x1, PT_RA(sp) REG_L x1, PT_RA(sp)
REG_L x2, PT_SP(sp) REG_L x2, PT_SP(sp)
REG_L x3, PT_GP(sp) REG_L x3, PT_GP(sp)
REG_L x4, PT_TP(sp) REG_L x4, PT_TP(sp)
REG_L x6, PT_T1(sp) /* Restore t0 with PT_EPC */
REG_L x7, PT_T2(sp) REG_L x5, PT_EPC(sp)
REG_L x8, PT_S0(sp) restore_from_x6_to_x31
REG_L x9, PT_S1(sp)
REG_L x10, PT_A0(sp)
REG_L x11, PT_A1(sp)
REG_L x12, PT_A2(sp)
REG_L x13, PT_A3(sp)
REG_L x14, PT_A4(sp)
REG_L x15, PT_A5(sp)
REG_L x16, PT_A6(sp)
REG_L x17, PT_A7(sp)
REG_L x18, PT_S2(sp)
REG_L x19, PT_S3(sp)
REG_L x20, PT_S4(sp)
REG_L x21, PT_S5(sp)
REG_L x22, PT_S6(sp)
REG_L x23, PT_S7(sp)
REG_L x24, PT_S8(sp)
REG_L x25, PT_S9(sp)
REG_L x26, PT_S10(sp)
REG_L x27, PT_S11(sp)
REG_L x28, PT_T3(sp)
REG_L x29, PT_T4(sp)
REG_L x30, PT_T5(sp)
REG_L x31, PT_T6(sp)
addi sp, sp, PT_SIZE_ON_STACK addi sp, sp, PT_SIZE_ON_STACK
.endm .endm
......
...@@ -34,7 +34,6 @@ EXPORT_SYMBOL(__stack_chk_guard); ...@@ -34,7 +34,6 @@ EXPORT_SYMBOL(__stack_chk_guard);
#endif #endif
extern asmlinkage void ret_from_fork(void); extern asmlinkage void ret_from_fork(void);
extern asmlinkage void ret_from_kernel_thread(void);
void arch_cpu_idle(void) void arch_cpu_idle(void)
{ {
...@@ -173,7 +172,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) ...@@ -173,7 +172,6 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
/* Supervisor/Machine, irqs on: */ /* Supervisor/Machine, irqs on: */
childregs->status = SR_PP | SR_PIE; childregs->status = SR_PP | SR_PIE;
p->thread.ra = (unsigned long)ret_from_kernel_thread;
p->thread.s[0] = (unsigned long)args->fn; p->thread.s[0] = (unsigned long)args->fn;
p->thread.s[1] = (unsigned long)args->fn_arg; p->thread.s[1] = (unsigned long)args->fn_arg;
} else { } else {
...@@ -183,8 +181,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args) ...@@ -183,8 +181,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
if (clone_flags & CLONE_SETTLS) if (clone_flags & CLONE_SETTLS)
childregs->tp = tls; childregs->tp = tls;
childregs->a0 = 0; /* Return value of fork() */ childregs->a0 = 0; /* Return value of fork() */
p->thread.ra = (unsigned long)ret_from_fork; p->thread.s[0] = 0;
} }
p->thread.ra = (unsigned long)ret_from_fork;
p->thread.sp = (unsigned long)childregs; /* kernel sp */ p->thread.sp = (unsigned long)childregs; /* kernel sp */
return 0; return 0;
} }
...@@ -19,9 +19,6 @@ ...@@ -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
...@@ -212,7 +209,6 @@ unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n) ...@@ -212,7 +209,6 @@ unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
void ptrace_disable(struct task_struct *child) void ptrace_disable(struct task_struct *child)
{ {
clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
} }
long arch_ptrace(struct task_struct *child, long request, long arch_ptrace(struct task_struct *child, long request,
...@@ -229,46 +225,6 @@ long arch_ptrace(struct task_struct *child, long request, ...@@ -229,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 @@ ...@@ -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) ...@@ -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) ...@@ -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);
}
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2022 Changbin Du <changbin.du@gmail.com>
*/
#include <linux/irqflags.h>
#include <linux/kprobes.h>
#include "trace_irq.h"
/*
* trace_hardirqs_on/off require the caller to setup frame pointer properly.
* Otherwise, CALLER_ADDR1 might trigger an pagging exception in kernel.
* Here we add one extra level so they can be safely called by low
* level entry code which $fp is used for other purpose.
*/
void __trace_hardirqs_on(void)
{
trace_hardirqs_on();
}
NOKPROBE_SYMBOL(__trace_hardirqs_on);
void __trace_hardirqs_off(void)
{
trace_hardirqs_off();
}
NOKPROBE_SYMBOL(__trace_hardirqs_off);
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 Changbin Du <changbin.du@gmail.com>
*/
#ifndef __TRACE_IRQ_H
#define __TRACE_IRQ_H
void __trace_hardirqs_on(void);
void __trace_hardirqs_off(void);
#endif /* __TRACE_IRQ_H */
...@@ -17,12 +17,14 @@ ...@@ -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;
...@@ -119,14 +121,22 @@ static void do_trap_error(struct pt_regs *regs, int signo, int code, ...@@ -119,14 +121,22 @@ static void do_trap_error(struct pt_regs *regs, int signo, int code,
} }
#if defined(CONFIG_XIP_KERNEL) && defined(CONFIG_RISCV_ALTERNATIVE) #if defined(CONFIG_XIP_KERNEL) && defined(CONFIG_RISCV_ALTERNATIVE)
#define __trap_section __section(".xip.traps") #define __trap_section __noinstr_section(".xip.traps")
#else #else
#define __trap_section #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, ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -356,4 +357,3 @@ asmlinkage void do_page_fault(struct pt_regs *regs)
} }
return; return;
} }
NOKPROBE_SYMBOL(do_page_fault);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment