]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/arm64/kernel/entry.S
arm64: enable context tracking
[karo-tx-linux.git] / arch / arm64 / kernel / entry.S
1 /*
2  * Low-level exception handling code
3  *
4  * Copyright (C) 2012 ARM Ltd.
5  * Authors:     Catalin Marinas <catalin.marinas@arm.com>
6  *              Will Deacon <will.deacon@arm.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <linux/init.h>
22 #include <linux/linkage.h>
23
24 #include <asm/assembler.h>
25 #include <asm/asm-offsets.h>
26 #include <asm/errno.h>
27 #include <asm/esr.h>
28 #include <asm/thread_info.h>
29 #include <asm/unistd.h>
30 #include <asm/unistd32.h>
31
32 /*
33  * Context tracking subsystem.  Used to instrument transitions
34  * between user and kernel mode.
35  */
36         .macro ct_user_exit, syscall = 0
37 #ifdef CONFIG_CONTEXT_TRACKING
38         bl      context_tracking_user_exit
39         .if \syscall == 1
40         /*
41          * Save/restore needed during syscalls.  Restore syscall arguments from
42          * the values already saved on stack during kernel_entry.
43          */
44         ldp     x0, x1, [sp]
45         ldp     x2, x3, [sp, #S_X2]
46         ldp     x4, x5, [sp, #S_X4]
47         ldp     x6, x7, [sp, #S_X6]
48         .endif
49 #endif
50         .endm
51
52         .macro ct_user_enter
53 #ifdef CONFIG_CONTEXT_TRACKING
54         bl      context_tracking_user_enter
55 #endif
56         .endm
57
58 /*
59  * Bad Abort numbers
60  *-----------------
61  */
62 #define BAD_SYNC        0
63 #define BAD_IRQ         1
64 #define BAD_FIQ         2
65 #define BAD_ERROR       3
66
67         .macro  kernel_entry, el, regsize = 64
68         sub     sp, sp, #S_FRAME_SIZE - S_LR    // room for LR, SP, SPSR, ELR
69         .if     \regsize == 32
70         mov     w0, w0                          // zero upper 32 bits of x0
71         .endif
72         push    x28, x29
73         push    x26, x27
74         push    x24, x25
75         push    x22, x23
76         push    x20, x21
77         push    x18, x19
78         push    x16, x17
79         push    x14, x15
80         push    x12, x13
81         push    x10, x11
82         push    x8, x9
83         push    x6, x7
84         push    x4, x5
85         push    x2, x3
86         push    x0, x1
87         .if     \el == 0
88         mrs     x21, sp_el0
89         get_thread_info tsk                     // Ensure MDSCR_EL1.SS is clear,
90         ldr     x19, [tsk, #TI_FLAGS]           // since we can unmask debug
91         disable_step_tsk x19, x20               // exceptions when scheduling.
92         .else
93         add     x21, sp, #S_FRAME_SIZE
94         .endif
95         mrs     x22, elr_el1
96         mrs     x23, spsr_el1
97         stp     lr, x21, [sp, #S_LR]
98         stp     x22, x23, [sp, #S_PC]
99
100         /*
101          * Set syscallno to -1 by default (overridden later if real syscall).
102          */
103         .if     \el == 0
104         mvn     x21, xzr
105         str     x21, [sp, #S_SYSCALLNO]
106         .endif
107
108         /*
109          * Registers that may be useful after this macro is invoked:
110          *
111          * x21 - aborted SP
112          * x22 - aborted PC
113          * x23 - aborted PSTATE
114         */
115         .endm
116
117         .macro  kernel_exit, el, ret = 0
118         ldp     x21, x22, [sp, #S_PC]           // load ELR, SPSR
119         .if     \el == 0
120         ct_user_enter
121         ldr     x23, [sp, #S_SP]                // load return stack pointer
122         .endif
123         .if     \ret
124         ldr     x1, [sp, #S_X1]                 // preserve x0 (syscall return)
125         add     sp, sp, S_X2
126         .else
127         pop     x0, x1
128         .endif
129         pop     x2, x3                          // load the rest of the registers
130         pop     x4, x5
131         pop     x6, x7
132         pop     x8, x9
133         msr     elr_el1, x21                    // set up the return data
134         msr     spsr_el1, x22
135         .if     \el == 0
136         msr     sp_el0, x23
137         .endif
138         pop     x10, x11
139         pop     x12, x13
140         pop     x14, x15
141         pop     x16, x17
142         pop     x18, x19
143         pop     x20, x21
144         pop     x22, x23
145         pop     x24, x25
146         pop     x26, x27
147         pop     x28, x29
148         ldr     lr, [sp], #S_FRAME_SIZE - S_LR  // load LR and restore SP
149         eret                                    // return to kernel
150         .endm
151
152         .macro  get_thread_info, rd
153         mov     \rd, sp
154         and     \rd, \rd, #~(THREAD_SIZE - 1)   // top of stack
155         .endm
156
157 /*
158  * These are the registers used in the syscall handler, and allow us to
159  * have in theory up to 7 arguments to a function - x0 to x6.
160  *
161  * x7 is reserved for the system call number in 32-bit mode.
162  */
163 sc_nr   .req    x25             // number of system calls
164 scno    .req    x26             // syscall number
165 stbl    .req    x27             // syscall table pointer
166 tsk     .req    x28             // current thread_info
167
168 /*
169  * Interrupt handling.
170  */
171         .macro  irq_handler
172         ldr     x1, handle_arch_irq
173         mov     x0, sp
174         blr     x1
175         .endm
176
177         .text
178
179 /*
180  * Exception vectors.
181  */
182
183         .align  11
184 ENTRY(vectors)
185         ventry  el1_sync_invalid                // Synchronous EL1t
186         ventry  el1_irq_invalid                 // IRQ EL1t
187         ventry  el1_fiq_invalid                 // FIQ EL1t
188         ventry  el1_error_invalid               // Error EL1t
189
190         ventry  el1_sync                        // Synchronous EL1h
191         ventry  el1_irq                         // IRQ EL1h
192         ventry  el1_fiq_invalid                 // FIQ EL1h
193         ventry  el1_error_invalid               // Error EL1h
194
195         ventry  el0_sync                        // Synchronous 64-bit EL0
196         ventry  el0_irq                         // IRQ 64-bit EL0
197         ventry  el0_fiq_invalid                 // FIQ 64-bit EL0
198         ventry  el0_error_invalid               // Error 64-bit EL0
199
200 #ifdef CONFIG_COMPAT
201         ventry  el0_sync_compat                 // Synchronous 32-bit EL0
202         ventry  el0_irq_compat                  // IRQ 32-bit EL0
203         ventry  el0_fiq_invalid_compat          // FIQ 32-bit EL0
204         ventry  el0_error_invalid_compat        // Error 32-bit EL0
205 #else
206         ventry  el0_sync_invalid                // Synchronous 32-bit EL0
207         ventry  el0_irq_invalid                 // IRQ 32-bit EL0
208         ventry  el0_fiq_invalid                 // FIQ 32-bit EL0
209         ventry  el0_error_invalid               // Error 32-bit EL0
210 #endif
211 END(vectors)
212
213 /*
214  * Invalid mode handlers
215  */
216         .macro  inv_entry, el, reason, regsize = 64
217         kernel_entry el, \regsize
218         mov     x0, sp
219         mov     x1, #\reason
220         mrs     x2, esr_el1
221         b       bad_mode
222         .endm
223
224 el0_sync_invalid:
225         inv_entry 0, BAD_SYNC
226 ENDPROC(el0_sync_invalid)
227
228 el0_irq_invalid:
229         inv_entry 0, BAD_IRQ
230 ENDPROC(el0_irq_invalid)
231
232 el0_fiq_invalid:
233         inv_entry 0, BAD_FIQ
234 ENDPROC(el0_fiq_invalid)
235
236 el0_error_invalid:
237         inv_entry 0, BAD_ERROR
238 ENDPROC(el0_error_invalid)
239
240 #ifdef CONFIG_COMPAT
241 el0_fiq_invalid_compat:
242         inv_entry 0, BAD_FIQ, 32
243 ENDPROC(el0_fiq_invalid_compat)
244
245 el0_error_invalid_compat:
246         inv_entry 0, BAD_ERROR, 32
247 ENDPROC(el0_error_invalid_compat)
248 #endif
249
250 el1_sync_invalid:
251         inv_entry 1, BAD_SYNC
252 ENDPROC(el1_sync_invalid)
253
254 el1_irq_invalid:
255         inv_entry 1, BAD_IRQ
256 ENDPROC(el1_irq_invalid)
257
258 el1_fiq_invalid:
259         inv_entry 1, BAD_FIQ
260 ENDPROC(el1_fiq_invalid)
261
262 el1_error_invalid:
263         inv_entry 1, BAD_ERROR
264 ENDPROC(el1_error_invalid)
265
266 /*
267  * EL1 mode handlers.
268  */
269         .align  6
270 el1_sync:
271         kernel_entry 1
272         mrs     x1, esr_el1                     // read the syndrome register
273         lsr     x24, x1, #ESR_EL1_EC_SHIFT      // exception class
274         cmp     x24, #ESR_EL1_EC_DABT_EL1       // data abort in EL1
275         b.eq    el1_da
276         cmp     x24, #ESR_EL1_EC_SYS64          // configurable trap
277         b.eq    el1_undef
278         cmp     x24, #ESR_EL1_EC_SP_ALIGN       // stack alignment exception
279         b.eq    el1_sp_pc
280         cmp     x24, #ESR_EL1_EC_PC_ALIGN       // pc alignment exception
281         b.eq    el1_sp_pc
282         cmp     x24, #ESR_EL1_EC_UNKNOWN        // unknown exception in EL1
283         b.eq    el1_undef
284         cmp     x24, #ESR_EL1_EC_BREAKPT_EL1    // debug exception in EL1
285         b.ge    el1_dbg
286         b       el1_inv
287 el1_da:
288         /*
289          * Data abort handling
290          */
291         mrs     x0, far_el1
292         enable_dbg
293         // re-enable interrupts if they were enabled in the aborted context
294         tbnz    x23, #7, 1f                     // PSR_I_BIT
295         enable_irq
296 1:
297         mov     x2, sp                          // struct pt_regs
298         bl      do_mem_abort
299
300         // disable interrupts before pulling preserved data off the stack
301         disable_irq
302         kernel_exit 1
303 el1_sp_pc:
304         /*
305          * Stack or PC alignment exception handling
306          */
307         mrs     x0, far_el1
308         enable_dbg
309         mov     x2, sp
310         b       do_sp_pc_abort
311 el1_undef:
312         /*
313          * Undefined instruction
314          */
315         enable_dbg
316         mov     x0, sp
317         b       do_undefinstr
318 el1_dbg:
319         /*
320          * Debug exception handling
321          */
322         cmp     x24, #ESR_EL1_EC_BRK64          // if BRK64
323         cinc    x24, x24, eq                    // set bit '0'
324         tbz     x24, #0, el1_inv                // EL1 only
325         mrs     x0, far_el1
326         mov     x2, sp                          // struct pt_regs
327         bl      do_debug_exception
328         enable_dbg
329         kernel_exit 1
330 el1_inv:
331         // TODO: add support for undefined instructions in kernel mode
332         enable_dbg
333         mov     x0, sp
334         mov     x1, #BAD_SYNC
335         mrs     x2, esr_el1
336         b       bad_mode
337 ENDPROC(el1_sync)
338
339         .align  6
340 el1_irq:
341         kernel_entry 1
342         enable_dbg
343 #ifdef CONFIG_TRACE_IRQFLAGS
344         bl      trace_hardirqs_off
345 #endif
346
347         irq_handler
348
349 #ifdef CONFIG_PREEMPT
350         get_thread_info tsk
351         ldr     w24, [tsk, #TI_PREEMPT]         // get preempt count
352         cbnz    w24, 1f                         // preempt count != 0
353         ldr     x0, [tsk, #TI_FLAGS]            // get flags
354         tbz     x0, #TIF_NEED_RESCHED, 1f       // needs rescheduling?
355         bl      el1_preempt
356 1:
357 #endif
358 #ifdef CONFIG_TRACE_IRQFLAGS
359         bl      trace_hardirqs_on
360 #endif
361         kernel_exit 1
362 ENDPROC(el1_irq)
363
364 #ifdef CONFIG_PREEMPT
365 el1_preempt:
366         mov     x24, lr
367 1:      bl      preempt_schedule_irq            // irq en/disable is done inside
368         ldr     x0, [tsk, #TI_FLAGS]            // get new tasks TI_FLAGS
369         tbnz    x0, #TIF_NEED_RESCHED, 1b       // needs rescheduling?
370         ret     x24
371 #endif
372
373 /*
374  * EL0 mode handlers.
375  */
376         .align  6
377 el0_sync:
378         kernel_entry 0
379         mrs     x25, esr_el1                    // read the syndrome register
380         lsr     x24, x25, #ESR_EL1_EC_SHIFT     // exception class
381         cmp     x24, #ESR_EL1_EC_SVC64          // SVC in 64-bit state
382         b.eq    el0_svc
383         cmp     x24, #ESR_EL1_EC_DABT_EL0       // data abort in EL0
384         b.eq    el0_da
385         cmp     x24, #ESR_EL1_EC_IABT_EL0       // instruction abort in EL0
386         b.eq    el0_ia
387         cmp     x24, #ESR_EL1_EC_FP_ASIMD       // FP/ASIMD access
388         b.eq    el0_fpsimd_acc
389         cmp     x24, #ESR_EL1_EC_FP_EXC64       // FP/ASIMD exception
390         b.eq    el0_fpsimd_exc
391         cmp     x24, #ESR_EL1_EC_SYS64          // configurable trap
392         b.eq    el0_undef
393         cmp     x24, #ESR_EL1_EC_SP_ALIGN       // stack alignment exception
394         b.eq    el0_sp_pc
395         cmp     x24, #ESR_EL1_EC_PC_ALIGN       // pc alignment exception
396         b.eq    el0_sp_pc
397         cmp     x24, #ESR_EL1_EC_UNKNOWN        // unknown exception in EL0
398         b.eq    el0_undef
399         cmp     x24, #ESR_EL1_EC_BREAKPT_EL0    // debug exception in EL0
400         b.ge    el0_dbg
401         b       el0_inv
402
403 #ifdef CONFIG_COMPAT
404         .align  6
405 el0_sync_compat:
406         kernel_entry 0, 32
407         mrs     x25, esr_el1                    // read the syndrome register
408         lsr     x24, x25, #ESR_EL1_EC_SHIFT     // exception class
409         cmp     x24, #ESR_EL1_EC_SVC32          // SVC in 32-bit state
410         b.eq    el0_svc_compat
411         cmp     x24, #ESR_EL1_EC_DABT_EL0       // data abort in EL0
412         b.eq    el0_da
413         cmp     x24, #ESR_EL1_EC_IABT_EL0       // instruction abort in EL0
414         b.eq    el0_ia
415         cmp     x24, #ESR_EL1_EC_FP_ASIMD       // FP/ASIMD access
416         b.eq    el0_fpsimd_acc
417         cmp     x24, #ESR_EL1_EC_FP_EXC32       // FP/ASIMD exception
418         b.eq    el0_fpsimd_exc
419         cmp     x24, #ESR_EL1_EC_UNKNOWN        // unknown exception in EL0
420         b.eq    el0_undef
421         cmp     x24, #ESR_EL1_EC_CP15_32        // CP15 MRC/MCR trap
422         b.eq    el0_undef
423         cmp     x24, #ESR_EL1_EC_CP15_64        // CP15 MRRC/MCRR trap
424         b.eq    el0_undef
425         cmp     x24, #ESR_EL1_EC_CP14_MR        // CP14 MRC/MCR trap
426         b.eq    el0_undef
427         cmp     x24, #ESR_EL1_EC_CP14_LS        // CP14 LDC/STC trap
428         b.eq    el0_undef
429         cmp     x24, #ESR_EL1_EC_CP14_64        // CP14 MRRC/MCRR trap
430         b.eq    el0_undef
431         cmp     x24, #ESR_EL1_EC_BREAKPT_EL0    // debug exception in EL0
432         b.ge    el0_dbg
433         b       el0_inv
434 el0_svc_compat:
435         /*
436          * AArch32 syscall handling
437          */
438         adr     stbl, compat_sys_call_table     // load compat syscall table pointer
439         uxtw    scno, w7                        // syscall number in w7 (r7)
440         mov     sc_nr, #__NR_compat_syscalls
441         b       el0_svc_naked
442
443         .align  6
444 el0_irq_compat:
445         kernel_entry 0, 32
446         b       el0_irq_naked
447 #endif
448
449 el0_da:
450         /*
451          * Data abort handling
452          */
453         mrs     x26, far_el1
454         // enable interrupts before calling the main handler
455         enable_dbg_and_irq
456         ct_user_exit
457         bic     x0, x26, #(0xff << 56)
458         mov     x1, x25
459         mov     x2, sp
460         adr     lr, ret_to_user
461         b       do_mem_abort
462 el0_ia:
463         /*
464          * Instruction abort handling
465          */
466         mrs     x26, far_el1
467         // enable interrupts before calling the main handler
468         enable_dbg_and_irq
469         ct_user_exit
470         mov     x0, x26
471         orr     x1, x25, #1 << 24               // use reserved ISS bit for instruction aborts
472         mov     x2, sp
473         adr     lr, ret_to_user
474         b       do_mem_abort
475 el0_fpsimd_acc:
476         /*
477          * Floating Point or Advanced SIMD access
478          */
479         enable_dbg
480         ct_user_exit
481         mov     x0, x25
482         mov     x1, sp
483         adr     lr, ret_to_user
484         b       do_fpsimd_acc
485 el0_fpsimd_exc:
486         /*
487          * Floating Point or Advanced SIMD exception
488          */
489         enable_dbg
490         ct_user_exit
491         mov     x0, x25
492         mov     x1, sp
493         adr     lr, ret_to_user
494         b       do_fpsimd_exc
495 el0_sp_pc:
496         /*
497          * Stack or PC alignment exception handling
498          */
499         mrs     x26, far_el1
500         // enable interrupts before calling the main handler
501         enable_dbg_and_irq
502         mov     x0, x26
503         mov     x1, x25
504         mov     x2, sp
505         adr     lr, ret_to_user
506         b       do_sp_pc_abort
507 el0_undef:
508         /*
509          * Undefined instruction
510          */
511         // enable interrupts before calling the main handler
512         enable_dbg_and_irq
513         ct_user_exit
514         mov     x0, sp
515         adr     lr, ret_to_user
516         b       do_undefinstr
517 el0_dbg:
518         /*
519          * Debug exception handling
520          */
521         tbnz    x24, #0, el0_inv                // EL0 only
522         mrs     x0, far_el1
523         mov     x1, x25
524         mov     x2, sp
525         bl      do_debug_exception
526         enable_dbg
527         ct_user_exit
528         b       ret_to_user
529 el0_inv:
530         enable_dbg
531         ct_user_exit
532         mov     x0, sp
533         mov     x1, #BAD_SYNC
534         mrs     x2, esr_el1
535         adr     lr, ret_to_user
536         b       bad_mode
537 ENDPROC(el0_sync)
538
539         .align  6
540 el0_irq:
541         kernel_entry 0
542 el0_irq_naked:
543         enable_dbg
544 #ifdef CONFIG_TRACE_IRQFLAGS
545         bl      trace_hardirqs_off
546 #endif
547
548         ct_user_exit
549         irq_handler
550
551 #ifdef CONFIG_TRACE_IRQFLAGS
552         bl      trace_hardirqs_on
553 #endif
554         b       ret_to_user
555 ENDPROC(el0_irq)
556
557 /*
558  * Register switch for AArch64. The callee-saved registers need to be saved
559  * and restored. On entry:
560  *   x0 = previous task_struct (must be preserved across the switch)
561  *   x1 = next task_struct
562  * Previous and next are guaranteed not to be the same.
563  *
564  */
565 ENTRY(cpu_switch_to)
566         add     x8, x0, #THREAD_CPU_CONTEXT
567         mov     x9, sp
568         stp     x19, x20, [x8], #16             // store callee-saved registers
569         stp     x21, x22, [x8], #16
570         stp     x23, x24, [x8], #16
571         stp     x25, x26, [x8], #16
572         stp     x27, x28, [x8], #16
573         stp     x29, x9, [x8], #16
574         str     lr, [x8]
575         add     x8, x1, #THREAD_CPU_CONTEXT
576         ldp     x19, x20, [x8], #16             // restore callee-saved registers
577         ldp     x21, x22, [x8], #16
578         ldp     x23, x24, [x8], #16
579         ldp     x25, x26, [x8], #16
580         ldp     x27, x28, [x8], #16
581         ldp     x29, x9, [x8], #16
582         ldr     lr, [x8]
583         mov     sp, x9
584         ret
585 ENDPROC(cpu_switch_to)
586
587 /*
588  * This is the fast syscall return path.  We do as little as possible here,
589  * and this includes saving x0 back into the kernel stack.
590  */
591 ret_fast_syscall:
592         disable_irq                             // disable interrupts
593         ldr     x1, [tsk, #TI_FLAGS]
594         and     x2, x1, #_TIF_WORK_MASK
595         cbnz    x2, fast_work_pending
596         enable_step_tsk x1, x2
597         kernel_exit 0, ret = 1
598
599 /*
600  * Ok, we need to do extra processing, enter the slow path.
601  */
602 fast_work_pending:
603         str     x0, [sp, #S_X0]                 // returned x0
604 work_pending:
605         tbnz    x1, #TIF_NEED_RESCHED, work_resched
606         /* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */
607         ldr     x2, [sp, #S_PSTATE]
608         mov     x0, sp                          // 'regs'
609         tst     x2, #PSR_MODE_MASK              // user mode regs?
610         b.ne    no_work_pending                 // returning to kernel
611         enable_irq                              // enable interrupts for do_notify_resume()
612         bl      do_notify_resume
613         b       ret_to_user
614 work_resched:
615         bl      schedule
616
617 /*
618  * "slow" syscall return path.
619  */
620 ret_to_user:
621         disable_irq                             // disable interrupts
622         ldr     x1, [tsk, #TI_FLAGS]
623         and     x2, x1, #_TIF_WORK_MASK
624         cbnz    x2, work_pending
625         enable_step_tsk x1, x2
626 no_work_pending:
627         kernel_exit 0, ret = 0
628 ENDPROC(ret_to_user)
629
630 /*
631  * This is how we return from a fork.
632  */
633 ENTRY(ret_from_fork)
634         bl      schedule_tail
635         cbz     x19, 1f                         // not a kernel thread
636         mov     x0, x20
637         blr     x19
638 1:      get_thread_info tsk
639         b       ret_to_user
640 ENDPROC(ret_from_fork)
641
642 /*
643  * SVC handler.
644  */
645         .align  6
646 el0_svc:
647         adrp    stbl, sys_call_table            // load syscall table pointer
648         uxtw    scno, w8                        // syscall number in w8
649         mov     sc_nr, #__NR_syscalls
650 el0_svc_naked:                                  // compat entry point
651         stp     x0, scno, [sp, #S_ORIG_X0]      // save the original x0 and syscall number
652         enable_dbg_and_irq
653         ct_user_exit 1
654
655         ldr     x16, [tsk, #TI_FLAGS]           // check for syscall hooks
656         tst     x16, #_TIF_SYSCALL_WORK
657         b.ne    __sys_trace
658         adr     lr, ret_fast_syscall            // return address
659         cmp     scno, sc_nr                     // check upper syscall limit
660         b.hs    ni_sys
661         ldr     x16, [stbl, scno, lsl #3]       // address in the syscall table
662         br      x16                             // call sys_* routine
663 ni_sys:
664         mov     x0, sp
665         b       do_ni_syscall
666 ENDPROC(el0_svc)
667
668         /*
669          * This is the really slow path.  We're going to be doing context
670          * switches, and waiting for our parent to respond.
671          */
672 __sys_trace:
673         mov     x0, sp
674         bl      syscall_trace_enter
675         adr     lr, __sys_trace_return          // return address
676         uxtw    scno, w0                        // syscall number (possibly new)
677         mov     x1, sp                          // pointer to regs
678         cmp     scno, sc_nr                     // check upper syscall limit
679         b.hs    ni_sys
680         ldp     x0, x1, [sp]                    // restore the syscall args
681         ldp     x2, x3, [sp, #S_X2]
682         ldp     x4, x5, [sp, #S_X4]
683         ldp     x6, x7, [sp, #S_X6]
684         ldr     x16, [stbl, scno, lsl #3]       // address in the syscall table
685         br      x16                             // call sys_* routine
686
687 __sys_trace_return:
688         str     x0, [sp]                        // save returned x0
689         mov     x0, sp
690         bl      syscall_trace_exit
691         b       ret_to_user
692
693 /*
694  * Special system call wrappers.
695  */
696 ENTRY(sys_rt_sigreturn_wrapper)
697         mov     x0, sp
698         b       sys_rt_sigreturn
699 ENDPROC(sys_rt_sigreturn_wrapper)
700
701 ENTRY(handle_arch_irq)
702         .quad   0