@@ -66,6 +66,7 @@ config ARM
select GENERIC_CPU_AUTOPROBE
select GENERIC_CPU_DEVICES
select GENERIC_EARLY_IOREMAP
+ select GENERIC_ENTRY
select GENERIC_IDLE_POLL_SETUP
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_PROBE
new file mode 100644
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _ASM_ARM_ENTRY_COMMON_H
+#define _ASM_ARM_ENTRY_COMMON_H
+
+#include <linux/thread_info.h>
+
+#include <asm/stacktrace.h>
+
+enum ptrace_syscall_dir {
+ PTRACE_SYSCALL_ENTER = 0,
+ PTRACE_SYSCALL_EXIT,
+};
+
+static inline unsigned long
+arch_prepare_report_syscall_entry(struct pt_regs *regs)
+{
+ unsigned long ip;
+
+ /*
+ * IP is used to denote syscall entry/exit:
+ * IP = 0 -> entry
+ */
+ ip = regs->ARM_ip;
+ regs->ARM_ip = PTRACE_SYSCALL_ENTER;
+
+ return ip;
+}
+#define arch_prepare_report_syscall_entry arch_prepare_report_syscall_entry
+
+static inline void
+arch_post_report_syscall_entry(struct pt_regs *regs,
+ unsigned long saved_reg, long ret)
+{
+ regs->ARM_ip = saved_reg;
+}
+#define arch_post_report_syscall_entry arch_post_report_syscall_entry
+
+
+static inline unsigned long
+arch_prepare_report_syscall_exit(struct pt_regs *regs,
+ unsigned long work)
+{
+ unsigned long ip;
+
+ /*
+ * IP is used to denote syscall entry/exit:
+ * IP = 1 -> exit
+ */
+ ip = regs->ARM_ip;
+ regs->ARM_ip = PTRACE_SYSCALL_EXIT;
+
+ return ip;
+}
+#define arch_prepare_report_syscall_exit arch_prepare_report_syscall_exit
+
+static inline void
+arch_post_report_syscall_exit(struct pt_regs *regs,
+ unsigned long saved_reg,
+ unsigned long work)
+{
+ regs->ARM_ip = saved_reg;
+}
+#define arch_post_report_syscall_exit arch_post_report_syscall_exit
+
+#endif /* _ASM_ARM_ENTRY_COMMON_H */
@@ -4,15 +4,8 @@
struct pt_regs;
-/*
- * These are copies of generic entry headers so we can transition
- * to generic entry once they are semantically equivalent.
- */
-long syscall_enter_from_user_mode(struct pt_regs *regs, long);
-void syscall_exit_to_user_mode(struct pt_regs *regs);
-void irqentry_enter_from_user_mode(struct pt_regs *regs);
-void irqentry_exit_to_user_mode(struct pt_regs *regs);
-void irqentry_enter_from_kernel_mode(struct pt_regs *regs);
-void irqentry_exit_to_kernel_mode(struct pt_regs *regs);
+void arm_irq_handler(struct pt_regs *regs, int mode);
+void arm_fiq_handler(struct pt_regs *regs);
+void arm_exit_to_user_mode(struct pt_regs *regs);
#endif /* __ASM_ENTRY_H__ */
@@ -200,8 +200,5 @@ static inline unsigned long it_advance(unsigned long cpsr)
return cpsr;
}
-int syscall_trace_enter(struct pt_regs *regs);
-void syscall_trace_exit(struct pt_regs *regs);
-
#endif /* __ASSEMBLY__ */
#endif
@@ -23,6 +23,4 @@ typedef struct {
#include <asm/sigcontext.h>
-void do_work_pending(struct pt_regs *regs, unsigned int thread_flags);
-
#endif
@@ -19,7 +19,12 @@
extern const unsigned long sys_call_table[];
-int invoke_syscall(void *table, struct pt_regs *regs, int scno);
+void invoke_syscall(void *table, struct pt_regs *regs, int scno);
+
+static inline bool arch_syscall_is_vdso_sigreturn(struct pt_regs *regs)
+{
+ return false;
+}
static inline int syscall_get_nr(struct task_struct *task,
struct pt_regs *regs)
@@ -74,6 +74,7 @@ struct thread_info {
#ifdef CONFIG_ARM_THUMBEE
unsigned long thumbee_state; /* ThumbEE Handler Base register */
#endif
+ unsigned long syscall_work; /* SYSCALL_WORK_ flags */
};
#define INIT_THREAD_INFO(tsk) \
@@ -149,30 +150,14 @@ extern int vfp_restore_user_hwstate(struct user_vfp *,
#define TIF_USING_IWMMXT 17
#define TIF_MEMDIE 18 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 19
-#define TIF_SYSCALL_TRACE 20 /* syscall trace active */
-#define TIF_SYSCALL_AUDIT 21 /* syscall auditing active */
-#define TIF_SYSCALL_TRACEPOINT 22 /* syscall tracepoint instrumentation */
-#define TIF_SECCOMP 23 /* seccomp syscall filtering active */
-
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_UPROBE (1 << TIF_UPROBE)
-#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
-#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
-#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL)
#define _TIF_USING_IWMMXT (1 << TIF_USING_IWMMXT)
-/* Checks for any syscall work in entry-common.S */
-#define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \
- _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP)
-
-/*
- * Change these and you break ASM code in entry-common.S
- */
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \
_TIF_NOTIFY_RESUME | _TIF_UPROBE | \
_TIF_NOTIFY_SIGNAL)
@@ -38,7 +38,6 @@ extern void *vectors_page;
asmlinkage void dump_backtrace_stm(u32 *stack, u32 instruction, const char *loglvl);
asmlinkage void do_undefinstr(struct pt_regs *regs);
-asmlinkage void handle_fiq_as_nmi(struct pt_regs *regs);
asmlinkage void bad_mode(struct pt_regs *regs, int reason);
int arm_syscall(int no, struct pt_regs *regs);
asmlinkage void baddataabort(int code, unsigned long instr, struct pt_regs *regs);
@@ -33,6 +33,8 @@
#define PTRACE_GETHBPREGS 29
#define PTRACE_SETHBPREGS 30
#define PTRACE_GETFDPIC 31
+#define PTRACE_SYSEMU 32
+#define PTRACE_SYSEMU_SINGLESTEP 33
#define PTRACE_GETFDPIC_EXEC 0
#define PTRACE_GETFDPIC_INTERP 1
@@ -36,35 +36,6 @@
#define RELOC_TEXT_NONE
#endif
-/*
- * Interrupt handling.
- */
- .macro irq_handler, from_user:req
- mov r1, sp
- ldr_this_cpu r2, irq_stack_ptr, r2, r3
- .if \from_user == 0
- @
- @ If we took the interrupt while running in the kernel, we may already
- @ be using the IRQ stack, so revert to the original value in that case.
- @
- subs r3, r2, r1 @ SP above bottom of IRQ stack?
- rsbscs r3, r3, #THREAD_SIZE @ ... and below the top?
-#ifdef CONFIG_VMAP_STACK
- ldr_va r3, high_memory, cc @ End of the linear region
- cmpcc r3, r1 @ Stack pointer was below it?
-#endif
- bcc 0f @ If not, switch to the IRQ stack
- mov r0, r1
- bl generic_handle_arch_irq
- b 1f
-0:
- .endif
-
- mov_l r0, generic_handle_arch_irq
- bl call_with_stack
-1:
- .endm
-
.macro pabt_helper
@ PABORT handler takes pt_regs in r2, fault address in r4 and psr in r5
#ifdef MULTI_PABORT
@@ -205,9 +176,6 @@ ENDPROC(__und_invalid)
get_thread_info tsk
uaccess_entry tsk, r0, r1, r2, \uaccess
- mov r0, sp @ 'regs'
- bl irqentry_enter_from_kernel_mode
-
.endm
.align 5
@@ -223,7 +191,9 @@ ENDPROC(__dabt_svc)
.align 5
__irq_svc:
svc_entry
- irq_handler from_user=0
+ mov r0, sp @ regs
+ mov r1, #0 @ from kernel mode
+ bl arm_irq_handler
#ifdef CONFIG_PREEMPTION
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
@@ -300,7 +270,7 @@ ENDPROC(__pabt_svc)
__fiq_svc:
svc_entry
mov r0, sp @ struct pt_regs *regs
- bl handle_fiq_as_nmi
+ bl arm_fiq_handler
svc_exit_via_fiq
UNWIND(.fnend )
ENDPROC(__fiq_svc)
@@ -329,7 +299,7 @@ __fiq_abt:
stmfd sp!, {r1 - r2}
add r0, sp, #8 @ struct pt_regs *regs
- bl handle_fiq_as_nmi
+ bl arm_fiq_handler
ldmfd sp!, {r1 - r2}
ARM( msr cpsr_c, #ABT_MODE | PSR_I_BIT | PSR_F_BIT )
@@ -420,7 +390,6 @@ ENDPROC(__fiq_abt)
.align 5
__dabt_usr:
usr_entry uaccess=0
- asm_irqentry_enter_from_user_mode
kuser_cmpxchg_check
mov r2, sp
dabt_helper
@@ -431,9 +400,10 @@ ENDPROC(__dabt_usr)
.align 5
__irq_usr:
usr_entry
- asm_irqentry_enter_from_user_mode
kuser_cmpxchg_check
- irq_handler from_user=1
+ mov r0, sp @ regs
+ mov r1, #1 @ from user mode
+ bl arm_irq_handler
get_thread_info tsk
mov why, #0
b ret_to_user_from_irq
@@ -445,7 +415,6 @@ ENDPROC(__irq_usr)
.align 5
__und_usr:
usr_entry uaccess=0
- asm_irqentry_enter_from_user_mode
@ IRQs must be enabled before attempting to read the instruction from
@ user space since that could cause a page/translation fault if the
@@ -470,7 +439,6 @@ ENDPROC(__und_usr)
.align 5
__pabt_usr:
usr_entry
- asm_irqentry_enter_from_user_mode
mov r2, sp @ regs
pabt_helper
UNWIND(.fnend )
@@ -493,7 +461,7 @@ __fiq_usr:
usr_entry
kuser_cmpxchg_check
mov r0, sp @ struct pt_regs *regs
- bl handle_fiq_as_nmi
+ bl arm_fiq_handler
get_thread_info tsk
restore_user_regs
UNWIND(.fnend )
@@ -39,10 +39,6 @@ ret_fast_syscall:
UNWIND(.fnstart )
UNWIND(.cantunwind )
add sp, sp, #(S_R0 + S_OFF)
- /* do_rseq_syscall needs interrupts enabled. */
- mov r0, sp @ 'regs'
- bl syscall_exit_to_user_mode
-
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
bl stackleak_erase_on_task_stack
#endif
@@ -60,7 +56,7 @@ ENTRY(ret_to_user)
/* do_rseq_syscall needs interrupts enabled. */
enable_irq_notrace @ enable interrupts
mov r0, sp @ 'regs'
- bl syscall_exit_to_user_mode
+ bl arm_exit_to_user_mode
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
bl stackleak_erase_on_task_stack
@@ -69,8 +65,6 @@ ENTRY(ret_to_user)
ENDPROC(ret_to_user)
ENTRY(ret_to_user_from_irq)
- asm_irqentry_exit_to_user_mode
-
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
bl stackleak_erase_on_task_stack
#endif
@@ -92,9 +86,10 @@ SYM_TYPED_FUNC_START(ret_from_fork_asm)
mov r2, r5
mov r3, r4
bl ret_from_fork
- mov r0, #0
-1: get_thread_info tsk
- b ret_to_user
+#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
+ bl stackleak_erase_on_task_stack
+#endif
+ restore_user_regs
SYM_FUNC_END(ret_from_fork_asm)
/*=============================================================================
@@ -210,29 +205,12 @@ ENTRY(vector_swi)
#else
str scno, [tsk, #TI_ABI_SYSCALL]
#endif
-
- /*
- * Calling out to C to be careful to save and restore registers.
- * This call could modify the syscall number. scno is r7 so we
- * do not save and restore r7.
- */
- mov r0, sp @ regs
- mov r1, scno
- push {r4 - r6, r8 - r10, lr}
- bl syscall_enter_from_user_mode
- pop {r4 - r6, r8 - r10, lr}
- mov scno, r0
-
mov r1, sp @ put regs into r1
stmdb sp!, {r4, r5} @ push fifth and sixth args
mov r0, tbl
mov r2, scno @ syscall number from r7
bl invoke_syscall
- cmp r0, #0
- beq ret_fast_syscall
- /* This path taken when tracing */
- add sp, sp, #(S_R0 + S_OFF)
- b ret_to_user
+ b ret_fast_syscall
#if defined(CONFIG_OABI_COMPAT) || !defined(CONFIG_AEABI)
/*
@@ -203,10 +203,6 @@
@ IRQs off again before pulling preserved data off the stack
disable_irq_notrace
-
- mov r0, sp @ 'regs'
- bl irqentry_exit_to_kernel_mode
-
uaccess_exit tsk, r0, r1
#ifndef CONFIG_THUMB2_KERNEL
@@ -340,20 +336,6 @@ ALT_UP_B(.L1_\@)
#endif /* !CONFIG_THUMB2_KERNEL */
.endm
-/*
- * Context tracking and other mode transitions. Used to instrument transitions
- * between user and kernel mode.
-*/
- .macro asm_irqentry_enter_from_user_mode
- mov r0, sp @ regs
- bl irqentry_enter_from_user_mode
- .endm
-
- .macro asm_irqentry_exit_to_user_mode
- mov r0, sp @ regs
- bl irqentry_exit_to_user_mode
- .endm
-
/*
* These are the registers used in the syscall handler, and allow us to
* have in theory up to 7 arguments to a function - r0 to r6.
@@ -1,71 +1,68 @@
// SPDX-License-Identifier: GPL-2.0
#include <asm/entry.h>
-#include <asm/ptrace.h>
-#include <asm/signal.h>
#include <linux/context_tracking.h>
+#include <linux/entry-common.h>
+#include <linux/hardirq.h>
+#include <linux/irq.h>
#include <linux/irqflags.h>
+#include <linux/percpu.h>
#include <linux/rseq.h>
-long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
-{
- trace_hardirqs_on();
- local_irq_enable();
- /* This context tracking call has inverse naming */
- user_exit_callable();
-
- /* This will optionally be modified later */
- return syscall;
-}
+#include "irq.h"
-void syscall_exit_to_user_mode(struct pt_regs *regs)
+static void noinstr handle_arm_irq(void *data)
{
- unsigned long flags = read_thread_flags();
+ struct pt_regs *regs = data;
+ struct pt_regs *old_regs;
- rseq_syscall(regs);
- local_irq_disable();
- /*
- * It really matters that we check for flags != 0 and not
- * just for pending work here!
- */
- if (flags)
- do_work_pending(regs, flags);
+ irq_enter_rcu();
+ old_regs = set_irq_regs(regs);
- trace_hardirqs_on();
- /* This context tracking call has inverse naming */
- user_enter_callable();
-}
+ handle_arch_irq(regs);
-noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
-{
- trace_hardirqs_off();
- /* This context tracking call has inverse naming */
- user_exit_callable();
+ set_irq_regs(old_regs);
+ irq_exit_rcu();
}
-noinstr void irqentry_exit_to_user_mode(struct pt_regs *regs)
+noinstr void arm_irq_handler(struct pt_regs *regs, int mode)
{
- unsigned long flags = read_thread_flags();
+ irqentry_state_t state = irqentry_enter(regs);
/*
- * It really matters that we check for flags != 0 and not
- * just for pending work here!
+ * If we are executing in kernel context and we are already on
+ * the IRQ stack (i.e. we get interrupted in interrupt context)
+ * then just handle the IRQ, else switch to the IRQ stack and
+ * handle the interrupt using the IRQ stack.
*/
- if (flags)
- do_work_pending(regs, flags);
- trace_hardirqs_on();
- /* This context tracking call has inverse naming */
- user_enter_callable();
+ if ((mode == 0) && on_irq_stack(regs))
+ handle_arm_irq(regs);
+ else
+ call_on_irq_stack(handle_arm_irq, regs);
+
+ irqentry_exit(regs, state);
}
-noinstr void irqentry_enter_from_kernel_mode(struct pt_regs *regs)
+/*
+ * Handle FIQ similarly to NMI on x86 systems.
+ *
+ * The runtime environment for NMIs is extremely restrictive
+ * (NMIs can pre-empt critical sections meaning almost all locking is
+ * forbidden) meaning this default FIQ handling must only be used in
+ * circumstances where non-maskability improves robustness, such as
+ * watchdog or debug logic.
+ *
+ * This handler is not appropriate for general purpose use in drivers
+ * platform code and can be overrideen using set_fiq_handler.
+ */
+noinstr void arm_fiq_handler(struct pt_regs *regs)
{
- trace_hardirqs_off();
+ irqentry_state_t state = irqentry_nmi_enter(regs);
+
+ irqentry_nmi_exit(regs, state);
}
-noinstr void irqentry_exit_to_kernel_mode(struct pt_regs *regs)
+asmlinkage void arm_exit_to_user_mode(struct pt_regs *regs)
{
- if (interrupts_enabled(regs))
- trace_hardirqs_on();
- else
- trace_hardirqs_off();
+ local_irq_disable();
+ irqentry_exit_to_user_mode(regs);
}
@@ -25,6 +25,7 @@
#include <linux/random.h>
#include <linux/hw_breakpoint.h>
#include <linux/leds.h>
+#include <linux/entry-common.h>
#include <asm/processor.h>
#include <asm/thread_notify.h>
@@ -248,8 +249,8 @@ __visible void ret_from_fork(struct task_struct *prev, struct pt_regs *regs,
* execve() syscall.
*/
}
-
- /* syscall_exit_to_user_mode(regs); here once we switch to generic entry */
+ local_irq_enable();
+ syscall_exit_to_user_mode(regs);
}
int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
@@ -27,9 +27,6 @@
#include <asm/syscall.h>
#include <asm/traps.h>
-#define CREATE_TRACE_POINTS
-#include <trace/events/syscalls.h>
-
#define REG_PC 15
#define REG_PSR 16
/*
@@ -821,90 +818,3 @@ long arch_ptrace(struct task_struct *child, long request,
return ret;
}
-
-enum ptrace_syscall_dir {
- PTRACE_SYSCALL_ENTER = 0,
- PTRACE_SYSCALL_EXIT,
-};
-
-static void report_syscall_enter(struct pt_regs *regs)
-{
- unsigned long ip;
-
- /*
- * IP is used to denote syscall entry/exit:
- * IP = 0 -> entry
- */
- ip = regs->ARM_ip;
- regs->ARM_ip = PTRACE_SYSCALL_ENTER;
-
- if (ptrace_report_syscall_entry(regs))
- current_thread_info()->abi_syscall = -1;
-
- regs->ARM_ip = ip;
-}
-
-static void report_syscall_exit(struct pt_regs *regs)
-{
- unsigned long ip;
-
- /*
- * IP is used to denote syscall entry/exit:
- * IP = 1 -> exit
- */
- ip = regs->ARM_ip;
- regs->ARM_ip = PTRACE_SYSCALL_EXIT;
-
- ptrace_report_syscall_exit(regs, 0);
-
- regs->ARM_ip = ip;
-}
-
-asmlinkage int syscall_trace_enter(struct pt_regs *regs)
-{
- int scno;
-
- if (test_thread_flag(TIF_SYSCALL_TRACE))
- report_syscall_enter(regs);
-
- /* Do seccomp after ptrace; syscall may have changed. */
-#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER
- if (secure_computing() == -1)
- return -1;
-#else
- /* XXX: remove this once OABI gets fixed */
- secure_computing_strict(syscall_get_nr(current, regs));
-#endif
-
- /* Tracer or seccomp may have changed syscall. */
- scno = syscall_get_nr(current, regs);
-
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_enter(regs, scno);
-
- audit_syscall_entry(scno, regs->ARM_r0, regs->ARM_r1, regs->ARM_r2,
- regs->ARM_r3);
-
- return scno;
-}
-
-void syscall_trace_exit(struct pt_regs *regs)
-{
- /*
- * Audit the syscall before anything else, as a debugger may
- * come in and change the current registers.
- */
- audit_syscall_exit(regs);
-
- /*
- * Note that we haven't updated the ->syscall field for the
- * current thread. This isn't a problem because it will have
- * been set on syscall entry and there hasn't been an opportunity
- * for a PTRACE_SET_SYSCALL since then.
- */
- if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
- trace_sys_exit(regs, regs_return_value(regs));
-
- if (test_thread_flag(TIF_SYSCALL_TRACE))
- report_syscall_exit(regs);
-}
@@ -4,6 +4,7 @@
*
* Copyright (C) 1995-2009 Russell King
*/
+#include <linux/entry-common.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/signal.h>
@@ -535,7 +536,7 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-static void arch_do_signal_or_restart(struct pt_regs *regs)
+void arch_do_signal_or_restart(struct pt_regs *regs)
{
unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
bool syscall = (syscall_get_nr(current, regs) != -1);
@@ -598,34 +599,6 @@ static void arch_do_signal_or_restart(struct pt_regs *regs)
return;
}
-void do_work_pending(struct pt_regs *regs, unsigned int thread_flags)
-{
- /*
- * The assembly code enters us with IRQs off, but it hasn't
- * informed the tracing code of that for efficiency reasons.
- * Update the trace code with the current status.
- */
- trace_hardirqs_off();
- do {
- if (likely(thread_flags & _TIF_NEED_RESCHED)) {
- schedule();
- } else {
- if (unlikely(!user_mode(regs)))
- return;
- local_irq_enable();
- if (thread_flags & (_TIF_SIGPENDING | _TIF_NOTIFY_SIGNAL)) {
- arch_do_signal_or_restart(regs);
- } else if (thread_flags & _TIF_UPROBE) {
- uprobe_notify_resume(regs);
- } else {
- resume_user_mode_work(regs);
- }
- }
- local_irq_disable();
- thread_flags = read_thread_flags();
- } while (thread_flags & _TIF_WORK_MASK);
-}
-
struct page *get_signal_page(void)
{
unsigned long ptr;
@@ -1,26 +1,17 @@
// SPDX-License-Identifier: GPL-2.0
+#include <linux/entry-common.h>
#include <linux/syscalls.h>
#include <asm/syscall.h>
-static inline bool has_syscall_work(unsigned long flags)
-{
- return unlikely(flags & _TIF_SYSCALL_WORK);
-}
-
int invoke_syscall_asm(void *table, struct pt_regs *regs, int scno);
__ADDRESSABLE(invoke_syscall_asm);
-__visible int invoke_syscall(void *table, struct pt_regs *regs, int scno)
+__visible void invoke_syscall(void *table, struct pt_regs *regs, int scno)
{
- unsigned long flags = read_thread_flags();
int ret;
- if (has_syscall_work(flags)) {
- scno = syscall_trace_enter(regs);
- if (scno == -1)
- goto trace_exit_nosave;
- }
+ scno = syscall_enter_from_user_mode(regs, scno);
if (scno < NR_syscalls) {
ret = invoke_syscall_asm(table, regs, scno);
@@ -35,13 +26,7 @@ __visible int invoke_syscall(void *table, struct pt_regs *regs, int scno)
ret = sys_ni_syscall();
exit_save:
- /* Save return value from syscall */
- regs->ARM_r0 = ret;
- if (!has_syscall_work(flags))
- return 0;
-
-trace_exit_nosave:
- local_irq_enable();
- syscall_trace_exit(regs);
- return 1;
+ syscall_set_return_value(current, regs, 0, ret);
+
+ syscall_exit_to_user_mode(regs);
}
@@ -502,31 +502,6 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
}
NOKPROBE_SYMBOL(do_undefinstr)
-/*
- * Handle FIQ similarly to NMI on x86 systems.
- *
- * The runtime environment for NMIs is extremely restrictive
- * (NMIs can pre-empt critical sections meaning almost all locking is
- * forbidden) meaning this default FIQ handling must only be used in
- * circumstances where non-maskability improves robustness, such as
- * watchdog or debug logic.
- *
- * This handler is not appropriate for general purpose use in drivers
- * platform code and can be overrideen using set_fiq_handler.
- */
-asmlinkage void __exception_irq_entry handle_fiq_as_nmi(struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
-
- nmi_enter();
-
- /* nop. FIQ handlers for special arch/arm features can be added here. */
-
- nmi_exit();
-
- set_irq_regs(old_regs);
-}
-
/*
* bad_mode handles the impossible case in the vectors. If you see one of
* these, then it's extremely serious, and could mean you have buggy hardware.
This rewrites ARM to use the generic entry. All of the irqentry_* callbacks are collapsed and made to call into the generic entry code that handle the interrupts storing regs context before entry and restoring it after. The syscall_enter_from_user_mode(), syscall_exit_to_user_mode(), do_work_pending() constructs are replaced with generic code. The syscall invocation now enables syscall tracing "work" using the generic callbacks and no extra actions are needed to enable/disable syscall tracing. The old context tracking with user_exit_callable() user_enter_callable() is no longer used. Only CSKY and Xtensa use this deprecated mechanism now. handle_fiq_as_nmi() is retired as the generic entry provides the same functionality in irqentry_nmi_enter() and irqentry_nmi_exit(). Like with the ARM64 proposed patch for generic entry, it is necessary to create a small call "arm_exit_to_user_mode()" that is used for things such as ret_from_fork, i.e. when we create a completely new execution context with a botched return from interrupt. The elaborate checking and switching to IRQ stack in the irq_handler macro was reimplemented in C for this exercise: this was easiest and there was already code making use of the IRQ stack from C for soft interrupts. I have dropped the context tracking (i.e. calling irqentry_enter() and looking for trace conditions) on dabt/pabt i.e. do_DataAbort and do_PrefetchAbort code paths. These are addressed in a separate patch for development/review reasons. Open questions: - I had to add defines for PTRACE_SYSEMU and PTRACE_SYSEMU_SINGLESTEP and I have no idea what those are or why they are required. Sorry for my ignorance, I need help to figure out how we deal with this. Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- arch/arm/Kconfig | 1 + arch/arm/include/asm/entry-common.h | 66 +++++++++++++++++++++++++++ arch/arm/include/asm/entry.h | 13 ++---- arch/arm/include/asm/ptrace.h | 3 -- arch/arm/include/asm/signal.h | 2 - arch/arm/include/asm/syscall.h | 7 ++- arch/arm/include/asm/thread_info.h | 17 +------ arch/arm/include/asm/traps.h | 1 - arch/arm/include/uapi/asm/ptrace.h | 2 + arch/arm/kernel/entry-armv.S | 50 ++++---------------- arch/arm/kernel/entry-common.S | 34 +++----------- arch/arm/kernel/entry-header.S | 18 -------- arch/arm/kernel/entry.c | 91 ++++++++++++++++++------------------- arch/arm/kernel/process.c | 5 +- arch/arm/kernel/ptrace.c | 90 ------------------------------------ arch/arm/kernel/signal.c | 31 +------------ arch/arm/kernel/syscall.c | 27 +++-------- arch/arm/kernel/traps.c | 25 ---------- 18 files changed, 149 insertions(+), 334 deletions(-)