| .. | .. |
|---|
| 50 | 50 | ret = do_ni_syscall(regs, scno); |
|---|
| 51 | 51 | } |
|---|
| 52 | 52 | |
|---|
| 53 | | - if (is_compat_task()) |
|---|
| 54 | | - ret = lower_32_bits(ret); |
|---|
| 55 | | - |
|---|
| 56 | | - regs->regs[0] = ret; |
|---|
| 53 | + syscall_set_return_value(current, regs, 0, ret); |
|---|
| 57 | 54 | } |
|---|
| 58 | 55 | |
|---|
| 59 | 56 | static inline bool has_syscall_work(unsigned long flags) |
|---|
| .. | .. |
|---|
| 101 | 98 | regs->orig_x0 = regs->regs[0]; |
|---|
| 102 | 99 | regs->syscallno = scno; |
|---|
| 103 | 100 | |
|---|
| 101 | + /* |
|---|
| 102 | + * BTI note: |
|---|
| 103 | + * The architecture does not guarantee that SPSR.BTYPE is zero |
|---|
| 104 | + * on taking an SVC, so we could return to userspace with a |
|---|
| 105 | + * non-zero BTYPE after the syscall. |
|---|
| 106 | + * |
|---|
| 107 | + * This shouldn't matter except when userspace is explicitly |
|---|
| 108 | + * doing something stupid, such as setting PROT_BTI on a page |
|---|
| 109 | + * that lacks conforming BTI/PACIxSP instructions, falling |
|---|
| 110 | + * through from one executable page to another with differing |
|---|
| 111 | + * PROT_BTI, or messing with BTYPE via ptrace: in such cases, |
|---|
| 112 | + * userspace should not be surprised if a SIGILL occurs on |
|---|
| 113 | + * syscall return. |
|---|
| 114 | + * |
|---|
| 115 | + * So, don't touch regs->pstate & PSR_BTYPE_MASK here. |
|---|
| 116 | + * (Similarly for HVC and SMC elsewhere.) |
|---|
| 117 | + */ |
|---|
| 118 | + |
|---|
| 104 | 119 | cortex_a76_erratum_1463225_svc_handler(); |
|---|
| 105 | | - user_exit_irqoff(); |
|---|
| 106 | 120 | local_daif_restore(DAIF_PROCCTX); |
|---|
| 107 | 121 | |
|---|
| 122 | + if (flags & _TIF_MTE_ASYNC_FAULT) { |
|---|
| 123 | + /* |
|---|
| 124 | + * Process the asynchronous tag check fault before the actual |
|---|
| 125 | + * syscall. do_notify_resume() will send a signal to userspace |
|---|
| 126 | + * before the syscall is restarted. |
|---|
| 127 | + */ |
|---|
| 128 | + syscall_set_return_value(current, regs, -ERESTARTNOINTR, 0); |
|---|
| 129 | + return; |
|---|
| 130 | + } |
|---|
| 131 | + |
|---|
| 108 | 132 | if (has_syscall_work(flags)) { |
|---|
| 109 | | - /* set default errno for user-issued syscall(-1) */ |
|---|
| 133 | + /* |
|---|
| 134 | + * The de-facto standard way to skip a system call using ptrace |
|---|
| 135 | + * is to set the system call to -1 (NO_SYSCALL) and set x0 to a |
|---|
| 136 | + * suitable error code for consumption by userspace. However, |
|---|
| 137 | + * this cannot be distinguished from a user-issued syscall(-1) |
|---|
| 138 | + * and so we must set x0 to -ENOSYS here in case the tracer doesn't |
|---|
| 139 | + * issue the skip and we fall into trace_exit with x0 preserved. |
|---|
| 140 | + * |
|---|
| 141 | + * This is slightly odd because it also means that if a tracer |
|---|
| 142 | + * sets the system call number to -1 but does not initialise x0, |
|---|
| 143 | + * then x0 will be preserved for all system calls apart from a |
|---|
| 144 | + * user-issued syscall(-1). However, requesting a skip and not |
|---|
| 145 | + * setting the return value is unlikely to do anything sensible |
|---|
| 146 | + * anyway. |
|---|
| 147 | + */ |
|---|
| 110 | 148 | if (scno == NO_SYSCALL) |
|---|
| 111 | | - regs->regs[0] = -ENOSYS; |
|---|
| 149 | + syscall_set_return_value(current, regs, -ENOSYS, 0); |
|---|
| 112 | 150 | scno = syscall_trace_enter(regs); |
|---|
| 113 | 151 | if (scno == NO_SYSCALL) |
|---|
| 114 | 152 | goto trace_exit; |
|---|
| .. | .. |
|---|
| 124 | 162 | if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) { |
|---|
| 125 | 163 | local_daif_mask(); |
|---|
| 126 | 164 | flags = current_thread_info()->flags; |
|---|
| 127 | | - if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP)) { |
|---|
| 128 | | - /* |
|---|
| 129 | | - * We're off to userspace, where interrupts are |
|---|
| 130 | | - * always enabled after we restore the flags from |
|---|
| 131 | | - * the SPSR. |
|---|
| 132 | | - */ |
|---|
| 133 | | - trace_hardirqs_on(); |
|---|
| 165 | + if (!has_syscall_work(flags) && !(flags & _TIF_SINGLESTEP)) |
|---|
| 134 | 166 | return; |
|---|
| 135 | | - } |
|---|
| 136 | 167 | local_daif_restore(DAIF_PROCCTX); |
|---|
| 137 | 168 | } |
|---|
| 138 | 169 | |
|---|
| .. | .. |
|---|
| 157 | 188 | sve_user_disable(); |
|---|
| 158 | 189 | } |
|---|
| 159 | 190 | |
|---|
| 160 | | -asmlinkage void el0_svc_handler(struct pt_regs *regs) |
|---|
| 191 | +void do_el0_svc(struct pt_regs *regs) |
|---|
| 161 | 192 | { |
|---|
| 162 | 193 | sve_user_discard(); |
|---|
| 163 | 194 | el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table); |
|---|
| 164 | 195 | } |
|---|
| 165 | 196 | |
|---|
| 166 | 197 | #ifdef CONFIG_COMPAT |
|---|
| 167 | | -asmlinkage void el0_svc_compat_handler(struct pt_regs *regs) |
|---|
| 198 | +void do_el0_svc_compat(struct pt_regs *regs) |
|---|
| 168 | 199 | { |
|---|
| 169 | 200 | el0_svc_common(regs, regs->regs[7], __NR_compat_syscalls, |
|---|
| 170 | 201 | compat_sys_call_table); |
|---|