hc
2024-11-01 2f529f9b558ca1c1bd74be7437a84e4711743404
commit | author | age
a07526 1 // SPDX-License-Identifier: GPL-2.0
H 2
3 #include <linux/compiler.h>
4 #include <linux/context_tracking.h>
2f529f 5 #include <linux/irqstage.h>
a07526 6 #include <linux/errno.h>
H 7 #include <linux/nospec.h>
8 #include <linux/ptrace.h>
9 #include <linux/syscalls.h>
10
11 #include <asm/daifflags.h>
12 #include <asm/debug-monitors.h>
13 #include <asm/fpsimd.h>
14 #include <asm/syscall.h>
15 #include <asm/thread_info.h>
16 #include <asm/unistd.h>
17
18 long compat_arm_syscall(struct pt_regs *regs, int scno);
19 long sys_ni_syscall(void);
20
21 static long do_ni_syscall(struct pt_regs *regs, int scno)
22 {
23 #ifdef CONFIG_COMPAT
24    long ret;
25    if (is_compat_task()) {
26        ret = compat_arm_syscall(regs, scno);
27        if (ret != -ENOSYS)
28            return ret;
29    }
30 #endif
31
32    return sys_ni_syscall();
33 }
34
35 static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
36 {
37    return syscall_fn(regs);
38 }
39
40 static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
41               unsigned int sc_nr,
42               const syscall_fn_t syscall_table[])
43 {
44    long ret;
45
46    if (scno < sc_nr) {
47        syscall_fn_t syscall_fn;
48        syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];
49        ret = __invoke_syscall(regs, syscall_fn);
50    } else {
51        ret = do_ni_syscall(regs, scno);
52    }
53
54    syscall_set_return_value(current, regs, 0, ret);
55 }
56
57 static inline bool has_syscall_work(unsigned long flags)
58 {
59    return unlikely(flags & _TIF_SYSCALL_WORK);
60 }
61
62 int syscall_trace_enter(struct pt_regs *regs);
63 void syscall_trace_exit(struct pt_regs *regs);
64
65 #ifdef CONFIG_ARM64_ERRATUM_1463225
66 DECLARE_PER_CPU(int, __in_cortex_a76_erratum_1463225_wa);
67
68 static void cortex_a76_erratum_1463225_svc_handler(void)
69 {
70    u32 reg, val;
71
72    if (!unlikely(test_thread_flag(TIF_SINGLESTEP)))
73        return;
74
75    if (!unlikely(this_cpu_has_cap(ARM64_WORKAROUND_1463225)))
76        return;
77
78    __this_cpu_write(__in_cortex_a76_erratum_1463225_wa, 1);
79    reg = read_sysreg(mdscr_el1);
80    val = reg | DBG_MDSCR_SS | DBG_MDSCR_KDE;
81    write_sysreg(val, mdscr_el1);
82    asm volatile("msr daifclr, #8");
83    isb();
84
85    /* We will have taken a single-step exception by this point */
86
87    write_sysreg(reg, mdscr_el1);
88    __this_cpu_write(__in_cortex_a76_erratum_1463225_wa, 0);
89 }
90 #else
91 static void cortex_a76_erratum_1463225_svc_handler(void) { }
92 #endif /* CONFIG_ARM64_ERRATUM_1463225 */
93
94 static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
95               const syscall_fn_t syscall_table[])
96 {
97    unsigned long flags = current_thread_info()->flags;
2f529f 98    int ret;
a07526 99
H 100    regs->orig_x0 = regs->regs[0];
101    regs->syscallno = scno;
102
103    /*
104     * BTI note:
105     * The architecture does not guarantee that SPSR.BTYPE is zero
106     * on taking an SVC, so we could return to userspace with a
107     * non-zero BTYPE after the syscall.
108     *
109     * This shouldn't matter except when userspace is explicitly
110     * doing something stupid, such as setting PROT_BTI on a page
111     * that lacks conforming BTI/PACIxSP instructions, falling
112     * through from one executable page to another with differing
113     * PROT_BTI, or messing with BTYPE via ptrace: in such cases,
114     * userspace should not be surprised if a SIGILL occurs on
115     * syscall return.
116     *
117     * So, don't touch regs->pstate & PSR_BTYPE_MASK here.
118     * (Similarly for HVC and SMC elsewhere.)
119     */
120
121    cortex_a76_erratum_1463225_svc_handler();
2f529f 122    WARN_ON_ONCE(dovetail_debug() &&
H 123             running_inband() && test_inband_stall());
a07526 124    local_daif_restore(DAIF_PROCCTX);
H 125
2f529f 126    ret = pipeline_syscall(scno, regs);
H 127    if (ret > 0)
128        return;
129
130    if (ret < 0)
131        goto tail_work;
132
133    if (system_supports_mte() && (flags & _TIF_MTE_ASYNC_FAULT)) {
a07526 134        /*
H 135         * Process the asynchronous tag check fault before the actual
136         * syscall. do_notify_resume() will send a signal to userspace
137         * before the syscall is restarted.
138         */
139        syscall_set_return_value(current, regs, -ERESTARTNOINTR, 0);
140        return;
141    }
142
143    if (has_syscall_work(flags)) {
144        /*
145         * The de-facto standard way to skip a system call using ptrace
146         * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
147         * suitable error code for consumption by userspace. However,
148         * this cannot be distinguished from a user-issued syscall(-1)
149         * and so we must set x0 to -ENOSYS here in case the tracer doesn't
150         * issue the skip and we fall into trace_exit with x0 preserved.
151         *
152         * This is slightly odd because it also means that if a tracer
153         * sets the system call number to -1 but does not initialise x0,
154         * then x0 will be preserved for all system calls apart from a
155         * user-issued syscall(-1). However, requesting a skip and not
156         * setting the return value is unlikely to do anything sensible
157         * anyway.
158         */
159        if (scno == NO_SYSCALL)
160            syscall_set_return_value(current, regs, -ENOSYS, 0);
161        scno = syscall_trace_enter(regs);
162        if (scno == NO_SYSCALL)
163            goto trace_exit;
164    }
165
166    invoke_syscall(regs, scno, sc_nr, syscall_table);
167
168    /*
169     * The tracing status may have changed under our feet, so we have to
170     * check again. However, if we were tracing entry, then we always trace
171     * exit regardless, as the old entry assembly did.
172     */
2f529f 173 tail_work:
a07526 174    if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) {
H 175        local_daif_mask();
2f529f 176        stall_inband();
a07526 177        flags = current_thread_info()->flags;
2f529f 178        if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP)) {
H 179            unstall_inband();
a07526 180            return;
2f529f 181        }
H 182        unstall_inband();
a07526 183        local_daif_restore(DAIF_PROCCTX);
H 184    }
185
186 trace_exit:
187    syscall_trace_exit(regs);
188 }
189
190 static inline void sve_user_discard(void)
191 {
192    if (!system_supports_sve())
193        return;
194
195    clear_thread_flag(TIF_SVE);
196
197    /*
198     * task_fpsimd_load() won't be called to update CPACR_EL1 in
199     * ret_to_user unless TIF_FOREIGN_FPSTATE is still set, which only
200     * happens if a context switch or kernel_neon_begin() or context
201     * modification (sigreturn, ptrace) intervenes.
202     * So, ensure that CPACR_EL1 is already correct for the fast-path case.
203     */
204    sve_user_disable();
205 }
206
207 void do_el0_svc(struct pt_regs *regs)
208 {
209    sve_user_discard();
210    el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);
211 }
212
213 #ifdef CONFIG_COMPAT
214 void do_el0_svc_compat(struct pt_regs *regs)
215 {
216    el0_svc_common(regs, regs->regs[7], __NR_compat_syscalls,
217               compat_sys_call_table);
218 }
219 #endif