*/
 ret_fast_syscall:
        disable_daif
-       str     x0, [sp, #S_X0]                 // returned x0
 #ifndef CONFIG_DEBUG_RSEQ
        ldr     x1, [tsk, #TSK_TI_FLAGS]        // re-check for syscall tracing
        and     x2, x1, #_TIF_SYSCALL_WORK
 
        tst     x16, #_TIF_SYSCALL_WORK         // check for syscall hooks
        b.ne    __sys_trace
-       cmp     wscno, wsc_nr                   // check upper syscall limit
-       b.hs    ni_sys
-       mask_nospec64 xscno, xsc_nr, x19        // enforce bounds for syscall number
-       ldr     x16, [stbl, xscno, lsl #3]      // address in the syscall table
-       blr     x16                             // call sys_* routine
-       b       ret_fast_syscall
-ni_sys:
        mov     x0, sp
-       bl      do_ni_syscall
+       mov     w1, wscno
+       mov     w2, wsc_nr
+       mov     x3, stbl
+       bl      invoke_syscall
        b       ret_fast_syscall
 ENDPROC(el0_svc)
 
        bl      syscall_trace_enter
        cmp     w0, #NO_SYSCALL                 // skip the syscall?
        b.eq    __sys_trace_return_skipped
-       mov     wscno, w0                       // syscall number (possibly new)
-       mov     x1, sp                          // pointer to regs
-       cmp     wscno, wsc_nr                   // check upper syscall limit
-       b.hs    __ni_sys_trace
-       ldp     x0, x1, [sp]                    // restore the syscall args
-       ldp     x2, x3, [sp, #S_X2]
-       ldp     x4, x5, [sp, #S_X4]
-       ldp     x6, x7, [sp, #S_X6]
-       ldr     x16, [stbl, xscno, lsl #3]      // address in the syscall table
-       blr     x16                             // call sys_* routine
 
-__sys_trace_return:
-       str     x0, [sp, #S_X0]                 // save returned x0
+       mov     x0, sp
+       mov     w1, wscno
+       mov     w2, wsc_nr
+       mov     x3, stbl
+       bl      invoke_syscall
+
 __sys_trace_return_skipped:
        mov     x0, sp
        bl      syscall_trace_exit
        b       ret_to_user
 
-__ni_sys_trace:
-       mov     x0, sp
-       bl      do_ni_syscall
-       b       __sys_trace_return
-
        .popsection                             // .entry.text
 
 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/errno.h>
+#include <linux/nospec.h>
+#include <linux/ptrace.h>
+#include <linux/syscalls.h>
+
+#include <asm/syscall.h>
+
+long compat_arm_syscall(struct pt_regs *regs);
+
+asmlinkage long do_ni_syscall(struct pt_regs *regs)
+{
+#ifdef CONFIG_COMPAT
+       long ret;
+       if (is_compat_task()) {
+               ret = compat_arm_syscall(regs);
+               if (ret != -ENOSYS)
+                       return ret;
+       }
+#endif
+
+       return sys_ni_syscall();
+}
+
+static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn)
+{
+       return syscall_fn(regs->regs[0], regs->regs[1], regs->regs[2],
+                         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[])
+{
+       long ret;
+
+       if (scno < sc_nr) {
+               syscall_fn_t syscall_fn;
+               syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];
+               ret = __invoke_syscall(regs, syscall_fn);
+       } else {
+               ret = do_ni_syscall(regs);
+       }
+
+       regs->regs[0] = ret;
+}
 
        do_undefinstr(regs);
 }
 
-long compat_arm_syscall(struct pt_regs *regs);
-
-asmlinkage long do_ni_syscall(struct pt_regs *regs)
-{
-#ifdef CONFIG_COMPAT
-       long ret;
-       if (is_compat_task()) {
-               ret = compat_arm_syscall(regs);
-               if (ret != -ENOSYS)
-                       return ret;
-       }
-#endif
-
-       return sys_ni_syscall();
-}
-
 static const char *esr_class_str[] = {
        [0 ... ESR_ELx_EC_MAX]          = "UNRECOGNIZED EC",
        [ESR_ELx_EC_UNKNOWN]            = "Unknown/Uncategorized",