summaryrefslogtreecommitdiff
path: root/arch/arm64/kernel/syscall.c
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2018-07-11 14:56:45 +0100
committerWill Deacon <will.deacon@arm.com>2018-07-12 14:49:47 +0100
commit3b7142752e4bee153df6db4a76ca104ef0d7c0b4 (patch)
tree3f51bae1958091a7fe9d395f9c998dc9365b276f /arch/arm64/kernel/syscall.c
parentf37099b6992a0b818c7b51b899e435f4006a9f90 (diff)
arm64: convert native/compat syscall entry to C
Now that the syscall invocation logic is in C, we can migrate the rest of the syscall entry logic over, so that the entry assembly needn't look at the register values at all. The SVE reset across syscall logic now unconditionally clears TIF_SVE, but sve_user_disable() will only write back to CPACR_EL1 when SVE is actually enabled. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Reviewed-by: Dave Martin <dave.martin@arm.com> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm64/kernel/syscall.c')
-rw-r--r--arch/arm64/kernel/syscall.c37
1 files changed, 35 insertions, 2 deletions
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 82098e6f6aa3..7ff2d7b9f517 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c
@@ -8,8 +8,10 @@
#include <linux/syscalls.h>
#include <asm/daifflags.h>
+#include <asm/fpsimd.h>
#include <asm/syscall.h>
#include <asm/thread_info.h>
+#include <asm/unistd.h>
long compat_arm_syscall(struct pt_regs *regs);
@@ -58,8 +60,8 @@ static inline bool has_syscall_work(unsigned long flags)
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[])
+static 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;
@@ -96,3 +98,34 @@ asmlinkage void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
trace_exit:
syscall_trace_exit(regs);
}
+
+static inline void sve_user_discard(void)
+{
+ if (!system_supports_sve())
+ return;
+
+ clear_thread_flag(TIF_SVE);
+
+ /*
+ * task_fpsimd_load() won't be called to update CPACR_EL1 in
+ * ret_to_user unless TIF_FOREIGN_FPSTATE is still set, which only
+ * happens if a context switch or kernel_neon_begin() or context
+ * modification (sigreturn, ptrace) intervenes.
+ * So, ensure that CPACR_EL1 is already correct for the fast-path case.
+ */
+ sve_user_disable();
+}
+
+asmlinkage void el0_svc_handler(struct pt_regs *regs)
+{
+ sve_user_discard();
+ el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
+}
+
+#ifdef CONFIG_COMPAT
+asmlinkage void el0_svc_compat_handler(struct pt_regs *regs)
+{
+ el0_svc_common(regs, regs->regs[7], __NR_compat_syscalls,
+ compat_sys_call_table);
+}
+#endif