|
@@ -1,11 +1,15 @@
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
|
|
+#include <linux/compiler.h>
|
|
|
+#include <linux/context_tracking.h>
|
|
|
#include <linux/errno.h>
|
|
|
#include <linux/nospec.h>
|
|
|
#include <linux/ptrace.h>
|
|
|
#include <linux/syscalls.h>
|
|
|
|
|
|
+#include <asm/daifflags.h>
|
|
|
#include <asm/syscall.h>
|
|
|
+#include <asm/thread_info.h>
|
|
|
|
|
|
long compat_arm_syscall(struct pt_regs *regs);
|
|
|
|
|
@@ -29,9 +33,9 @@ static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
|
|
|
regs->regs[3], regs->regs[4], regs->regs[5]);
|
|
|
}
|
|
|
|
|
|
-asmlinkage void invoke_syscall(struct pt_regs *regs, unsigned int scno,
|
|
|
- unsigned int sc_nr,
|
|
|
- const syscall_fn_t syscall_table[])
|
|
|
+static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
|
|
|
+ unsigned int sc_nr,
|
|
|
+ const syscall_fn_t syscall_table[])
|
|
|
{
|
|
|
long ret;
|
|
|
|
|
@@ -45,3 +49,50 @@ asmlinkage void invoke_syscall(struct pt_regs *regs, unsigned int scno,
|
|
|
|
|
|
regs->regs[0] = ret;
|
|
|
}
|
|
|
+
|
|
|
+static inline bool has_syscall_work(unsigned long flags)
|
|
|
+{
|
|
|
+ return unlikely(flags & _TIF_SYSCALL_WORK);
|
|
|
+}
|
|
|
+
|
|
|
+int syscall_trace_enter(struct pt_regs *regs);
|
|
|
+void syscall_trace_exit(struct pt_regs *regs);
|
|
|
+
|
|
|
+asmlinkage void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
|
|
|
+ const syscall_fn_t syscall_table[])
|
|
|
+{
|
|
|
+ unsigned long flags = current_thread_info()->flags;
|
|
|
+
|
|
|
+ regs->orig_x0 = regs->regs[0];
|
|
|
+ regs->syscallno = scno;
|
|
|
+
|
|
|
+ local_daif_restore(DAIF_PROCCTX);
|
|
|
+ user_exit();
|
|
|
+
|
|
|
+ if (has_syscall_work(flags)) {
|
|
|
+ /* set default errno for user-issued syscall(-1) */
|
|
|
+ if (scno == NO_SYSCALL)
|
|
|
+ regs->regs[0] = -ENOSYS;
|
|
|
+ scno = syscall_trace_enter(regs);
|
|
|
+ if (scno == NO_SYSCALL)
|
|
|
+ goto trace_exit;
|
|
|
+ }
|
|
|
+
|
|
|
+ invoke_syscall(regs, scno, sc_nr, syscall_table);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The tracing status may have changed under our feet, so we have to
|
|
|
+ * check again. However, if we were tracing entry, then we always trace
|
|
|
+ * exit regardless, as the old entry assembly did.
|
|
|
+ */
|
|
|
+ if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
|
|
|
+ local_daif_mask();
|
|
|
+ flags = current_thread_info()->flags;
|
|
|
+ if (!has_syscall_work(flags))
|
|
|
+ return;
|
|
|
+ local_daif_restore(DAIF_PROCCTX);
|
|
|
+ }
|
|
|
+
|
|
|
+trace_exit:
|
|
|
+ syscall_trace_exit(regs);
|
|
|
+}
|