armv8: properly passing syscall arguments to the kernel. (T300)
authorReto Achermann <reto.achermann@inf.ethz.ch>
Sat, 8 Oct 2016 08:45:12 +0000 (10:45 +0200)
committerReto Achermann <reto.achermann@inf.ethz.ch>
Sat, 8 Oct 2016 08:45:12 +0000 (10:45 +0200)
From user-space syscall took 12 arguments, only 6 of them were
passed properly to the kernel, as they were overridden
by the exception handling assembly code.

Signed-off-by: Reto Achermann <reto.achermann@inf.ethz.ch>

include/arch/aarch64/barrelfish/syscall_arch.h
kernel/arch/armv8/exceptions.S
lib/barrelfish/Hakefile
lib/barrelfish/arch/aarch64/syscall.S [deleted file]
lib/barrelfish/arch/aarch64/syscalls.c

index d680b20..3970a5a 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 /*
- * Copyright (c) 2007-2010, ETH Zurich.
+ * Copyright (c) 2007-2016, ETH Zurich.
  * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
  * All rights reserved.
  *
 
 #ifndef ARCH_AARCH64_BARRELFISH_SYSCALL_H
 #define ARCH_AARCH64_BARRELFISH_SYSCALL_H
-//
-// This is the actual system call function. Because the return
-// value is a structure with two memebers, x0 is setup point 1st 
-// member and x1 is setup to point to 2nd member of the structure.
-// The first system call argument supplied at end of
-// argument list and moved to r0 before use in syscall. This
-// simplifies the amount of swizzling involved therein as x1 =
-// arg1, x2 = arg2, x3 = arg3...x7 = arg7 remaining arguments are on 
-// the stack
-//
-extern struct sysret
-syscall(uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e,
-        uintptr_t f, uintptr_t g, uintptr_t h, uintptr_t i,
-        uintptr_t j, uintptr_t k, uintptr_t l, uintptr_t a);
 
-#define syscallx(a,b,c,d,e,f,g,h,i,j,k,l)                               \
-    syscall(a,b,c,d,e,f,g,h,i,j,k,l)
+#include <barrelfish_kpi/syscalls.h>  // for struct sysret.
+
+/**
+ * \brief the actual syscall function
+ *
+ * the arguments are left in the registers x0-x11
+ * the return value is stored in x0 and x1 when returning from the syscall
+ */
+struct sysret
+syscall(uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+        uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7,
+        uint64_t arg8, uint64_t arg9, uint64_t arg10, uint64_t arg11);
+
 
 //
 // System call argument 0 is encoded thus:
@@ -47,39 +44,39 @@ syscall(uintptr_t b, uintptr_t c, uintptr_t d, uintptr_t e,
 // The following macros add the argument count to arg0
 
 #define syscall12(a,b,c,d,e,f,g,h,i,j,k,l)                              \
-    syscallx(sysord(a,12),(b),(c),(d),(e),(f),(g),(h),(i),(j),(k),(l))
+    syscall(sysord(a,12),(b),(c),(d),(e),(f),(g),(h),(i),(j),(k),(l))
 
 #define syscall11(a,b,c,d,e,f,g,h,i,j,k)                                \
-    syscallx(sysord(a,11),(b),(c),(d),(e),(f),(g),(h),(i),(j),(k),0)
+    syscall(sysord(a,11),(b),(c),(d),(e),(f),(g),(h),(i),(j),(k),0)
 
 #define syscall10(a,b,c,d,e,f,g,h,i,j)                                  \
-    syscallx(sysord(a,10),(b),(c),(d),(e),(f),(g),(h),(i),(j),0,0)
+    syscall(sysord(a,10),(b),(c),(d),(e),(f),(g),(h),(i),(j),0,0)
 
 #define syscall9(a,b,c,d,e,f,g,h,i)                                     \
-    syscallx(sysord(a,9),(b),(c),(d),(e),(f),(g),(h),(i),0,0,0)
+    syscall(sysord(a,9),(b),(c),(d),(e),(f),(g),(h),(i),0,0,0)
 
 #define syscall8(a,b,c,d,e,f,g,h)                                       \
-    syscallx(sysord(a,8),(b),(c),(d),(e),(f),(g),(h),0,0,0,0)
+    syscall(sysord(a,8),(b),(c),(d),(e),(f),(g),(h),0,0,0,0)
 
 #define syscall7(a,b,c,d,e,f,g)                                         \
-    syscallx(sysord(a,7),(b),(c),(d),(e),(f),(g),0,0,0,0,0)
+    syscall(sysord(a,7),(b),(c),(d),(e),(f),(g),0,0,0,0,0)
 
 #define syscall6(a,b,c,d,e,f)                                           \
-    syscallx(sysord(a,6),(b),(c),(d),(e),(f),0,0,0,0,0,0)
+    syscall(sysord(a,6),(b),(c),(d),(e),(f),0,0,0,0,0,0)
 
 #define syscall5(a,b,c,d,e)                                             \
-    syscallx(sysord(a,5),(b),(c),(d),(e),0,0,0,0,0,0,0)
+    syscall(sysord(a,5),(b),(c),(d),(e),0,0,0,0,0,0,0)
 
 #define syscall4(a,b,c,d)                                               \
-    syscallx(sysord(a,4),(b),(c),(d),0,0,0,0,0,0,0,0)
+    syscall(sysord(a,4),(b),(c),(d),0,0,0,0,0,0,0,0)
 
 #define syscall3(a,b,c)                                                 \
-    syscallx(sysord(a,3),(b),(c),0,0,0,0,0,0,0,0,0)
+    syscall(sysord(a,3),(b),(c),0,0,0,0,0,0,0,0,0)
 
 #define syscall2(a,b)                                                   \
-    syscallx(sysord(a,2),(b),0,0,0,0,0,0,0,0,0,0)
+    syscall(sysord(a,2),(b),0,0,0,0,0,0,0,0,0,0)
 
 #define syscall1(a)                                                     \
-    syscallx(sysord(a,1),0,0,0,0,0,0,0,0,0,0,0)
+    syscall(sysord(a,1),0,0,0,0,0,0,0,0,0,0,0)
 
 #endif
index c9b5da8..01af037 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, ETH Zurich.
+ * Copyright (c) 2015,2016 ETH Zurich.
  * All rights reserved.
  *
  * This file is distributed under the terms in the attached LICENSE file.
@@ -99,44 +99,51 @@ el1_serror:
  * exceptions, the stack pointer is SP_EL1, which is left at the top of
  * 'kernel_stack'. */
  .align 7 /* 0x400 */
-/* Synchronous exceptions from a lower execution level using AArch64: SVC
- * (syscall), data abort, prefetch abort and undefined instruction. */
+/*
+ * Synchronous exceptions from a lower execution level using AArch64: SVC
+ * (syscall), data abort, prefetch abort and undefined instruction.
+ *
+ * Assumption:
+ * when coming from a syscall (SVC) the arguments are in registers x0-x11
+ */
 el0_aarch64_sync:
     /* Reenable breakpoints and aborts.  Interrupts remain disabled. */
     msr daifset, #3 /* IRQ and FIQ masked, Debug and Abort enabled. */
 
-    /* Spill a few working registers.  We use x9-, as these won't need to be
-     * restored if we're doing a syscall; they're caller-saved.  We preserve
-     * x0-x7 in registers unless we branch to the abort path, so that they're
-     * immediately available to the syscall handler, sys_syscall. */
-    stp x11, x12, [sp, #-(2 * 8)]!
-    stp x9,  x10, [sp, #-(2 * 8)]!
+    /* Spill a few working registers.
+     * Registers x0-x11 contain the syscall arguments. We use x12-, as these won't
+     * need to be restored if we're doing a syscall; they're caller-saved.  We
+     * preserve x0-x6 in registers unless we branch to the abort path, so that they're
+     * immediately available to the syscall handler, sys_syscall.
+     */
+    stp x14, x15, [sp, #-(2 * 8)]!
+    stp x12, x13, [sp, #-(2 * 8)]!
 
     /* The EL1 thread ID register holds the address of the currently-running
      * dispatcher's shared control block. */
-    mrs x10, tpidr_el1
+    mrs x13, tpidr_el1
 
-    /* x10 = dispatcher_shared_aarch64 */
+    /* x13 = dispatcher_shared_aarch64 */
 
     /* Exception PC */
-    mrs x9, elr_el1
+    mrs x12, elr_el1
 
-    /* x9 = EPC, x10 = dispatcher_shared_aarch64 */
+    /* x12 = EPC, x13 = dispatcher_shared_aarch64 */
 
     /* Check whether the current dispatcher is disabled.  See el0_aarch64_irq
      * for a description of this test. */
-    ldp x11, x12, [x10, #OFFSETOF_DISP_CRIT_PC_LOW]
-    cmp x11, x9
-    ccmp x12, x9, #0, ls
-    ldr w11, [x10, #OFFSETOF_DISP_DISABLED]
-    ccmp x11, xzr, #0, ls
+    ldp x14, x15, [x13, #OFFSETOF_DISP_CRIT_PC_LOW]
+    cmp x14, x12
+    ccmp x15, x12, #0, ls
+    ldr w14, [x13, #OFFSETOF_DISP_DISABLED]
+    ccmp x14, xzr, #0, ls
     /* NE <-> (low <= PC && PC < high) || disabled != 0 */
 
     /* Figure out what sort of exception we've got.  All paths need this. */
-    mrs x11, esr_el1  /* Exception Syndrome Register */
-    lsr x11, x11, #26 /* Exception Class field is bits [31:26] */
+    mrs x14, esr_el1  /* Exception Syndrome Register */
+    lsr x14, x14, #26 /* Exception Class field is bits [31:26] */
 
-    /* x9 = EPC, x11 = EC, x10 = dispatcher_shared_aarch64 */
+    /* x12 = EPC, x14 = EC, x13 = dispatcher_shared_aarch64 */
 
     /* Faults while disabled should be rare, if the critical section is short,
      * and will always be within the dispatcher code.  Therefore we branch out
@@ -146,52 +153,14 @@ el0_aarch64_sync:
     /* 13 instructions to here. */
 
     /* All exceptions use the 'enabled' area if the dispatcher is enabled. */
-    add x10, x10, #OFFSETOF_DISP_ENABLED_AREA
-
-    /* x9 = EPC, x10 = base of save area, x11 = EC */
-
-save_syscall_context:
-    /* We need to save r7 & r19+ no matter what, so get on with it. */
-    /* We need to pass the address of the trap frame to the handler without
-     * spilling to the stace, which means a7 needs to go into the trap frame.
-     * */
-    str x7,       [x10, #(7 * 8)]
-
-    /* Callee-saved registers */
-    stp x19, x20, [x10, #(19 * 8)]
-    stp x21, x22, [x10, #(21 * 8)]
-    stp x23, x24, [x10, #(23 * 8)]
-    stp x25, x26, [x10, #(25 * 8)]
-    stp x27, x28, [x10, #(27 * 8)]
-    stp x29, x30, [x10, #(29 * 8)] /* FP & LR */
-
-    /* High registers are now available. */
-
-    /* User SP and PC */
-    mrs x20, sp_el0
-    stp x20, x9, [x10, #(31 * 8)]
+    add x13, x13, #OFFSETOF_DISP_ENABLED_AREA
 
-    /* SPSR */
-    mrs x19, spsr_el1
-    str x19, [x10, #(33 * 8)]
+    /* x12 = EPC, x13 = base of save area, x14 = EC */
 
-    /* Is this a syscall? */
-    cmp x11, #0x15 /* SVC or HVC from AArch64 EL0 */
-    b.ne el0_abort_enabled
-
-    /* 27 instructions to here. */
-
-    /* If we're here, this is a syscall and we don't need to restore the
-     * scratch registers. Just throw the stack frame away. */
-    add sp, sp, #(4 * 8)
-
-    /* Pass the address of the trap frame as argument 8. */
-    mov x7, x10
-
-    /* Jump to the common (C) syscall handler. */
-    b sys_syscall
+    /* now we branch off as we are running out of space */
+    b save_syscall_context
 
-    /* 30 instructions to here */
+    /* 15 instructions to here. */
 
 .align 7 /* 0x480 */
 /* An interrupt at user level */
@@ -313,45 +282,104 @@ el0_aarch32_serror:
 /*** End of exception vectors ***/
 /********************************/
 
+/* The tail of the user syscall handler doesn't fit in the table. */
+save_syscall_context:
+    /* x12 = EPC, x13 = base of save area, x14 = EC */
+
+    /*
+     * We need to save callee save registers r19-30 no matter what, so get on with it.
+     */
+
+    /* Callee-saved registers */
+    stp x19, x20, [x13, #(19 * 8)]
+    stp x21, x22, [x13, #(21 * 8)]
+    stp x23, x24, [x13, #(23 * 8)]
+    stp x25, x26, [x13, #(25 * 8)]
+    stp x27, x28, [x13, #(27 * 8)]
+    stp x29, x30, [x13, #(29 * 8)] /* FP & LR */
+
+    /* 9 instructions to here */
+
+    /* High registers are now available. */
+
+    /* User SP and PC */
+    mrs x20, sp_el0
+    stp x20, x12, [x13, #(31 * 8)]
+
+    /* SPSR */
+    mrs x19, spsr_el1
+    str x19, [x13, #(33 * 8)]
+
+    /* Is this a syscall? */
+    cmp x14, #0x15 /* SVC or HVC from AArch64 EL0 */
+    b.ne el0_abort_enabled
+
+    /*
+     * we need to save r7-r11 as those are the syscall arguments which are passed
+     * on the stack on a function call, so we need to move them to the trap frame
+     */
+    stp x7, x8,     [x13, #(7 * 8)]
+    stp x9, x10,    [x13, #(9 * 8)]
+    str x11,        [x13, #(11 * 8)]
+
+    /* 15 instructions to here. */
+
+    /* If we're here, this is a syscall and we don't need to restore the
+     * scratch registers. Just throw the stack frame away. */
+    add sp, sp, #(4 * 8)
+
+    /* Pass the address of the trap frame as argument 8. */
+    mov x7, x13
+
+    /* Jump to the common (C) syscall handler. */
+    b sys_syscall
+
+
 /* The tail of the user abort handler doesn't fit in the table. */
 el0_abort_enabled:
-    /* x9 = EPC, x10 = base of save area, x11 = EC */
-
-    /* Spill the argument registers and x8. x7 has already been saved. */
-    stp x0,  x1,  [x10]
-    stp x2,  x3,  [x10, #( 2 * 8)]
-    stp x4,  x5,  [x10, #( 4 * 8)]
-    str x6,       [x10, #( 6 * 8)]
-    str x8,       [x10, #( 8 * 8)]
-
-    /* We saved x9-x12 in our stack frame. Copy them. */
-    ldp x0,  x1,  [sp], #16 /* x9,  x10 */
-    ldp x2,  x3,  [sp], #16 /* x11, x12 */
-    stp x0,  x1,  [x10, #( 9 * 8)]
-    stp x2,  x3,  [x10, #(11 * 8)]
-
-    /* Now spill the rest of the caller-saved registers. */
-    stp x13, x14, [x10, #(13 * 8)]
-    stp x15, x16, [x10, #(15 * 8)]
-    stp x17, x18, [x10, #(17 * 8)]
+    /* x12 = EPC, x13 = base of save area, x14 = EC */
+
+    /*
+     * we need to save the caller-saved registers. As it is an
+     * abort, those weren't saved by prior to the call.
+     */
+
+
+    /* We saved x12-x15 in our stack frame. We load them from
+     * memory so we can store them we use x20-23 as they where
+     * saved in the common path */
+    ldp x20,  x21,  [sp], #16 /* x12, x13 */
+    ldp x22,  x23,  [sp], #16 /* x14, x15 */
+
+    /* now we can store the caller-saved registers in the trap frame */
+    stp x0,   x1,  [x13]
+    stp x2,   x3,  [x13, #(  2 * 8)]
+    stp x4,   x5,  [x13, #(  4 * 8)]
+    stp x6,   x7,  [x13, #(  6 * 8)]
+    stp x8,   x9,  [x13, #(  8 * 8)]
+    stp x10, x11,  [x13, #( 10 * 8)]
+    stp x20, x21,  [x13, #(12 * 8)]
+    stp x22, x23,  [x13, #(14 * 8)]
+    stp x16, x17,  [x13, #(16 * 8)]
+    str x18,       [x13, #(18 * 8)]
 
     /* x19-x30, SP, SPSR and ELR were saved in the common path. */
 
-    /* x9 = EPC, x10 = base of save area, x11 = EC */
+    /* x12 = EPC, x13 = base of save area, x14 = EC */
 
     /* All registers are now available. */
 
     /* Pass the EPC and the save area address to the handler. */
-    mov x0, x9
-    mov x1, x10
+    mov x0, x12
+    mov x1, x13
 
     /* XXX - this should be handled differently on AArch64 - the C code can
      * switch on the Exception Context itself, or just pass it through to the
      * handler. */
     /* Now we can jump to the appropriate handler. */
-    cmp x11, #0x24 /* Data Abort */
+    cmp x14, #0x24 /* Data Abort */
     b.eq handle_user_page_fault
-    cmp x11, #0x20 /* Prefetch Abort */
+    cmp x14, #0x20 /* Prefetch Abort */
     b.eq handle_user_page_fault
     /* Unknown Trap/Undefined Instruction */
     b handle_user_undef
@@ -360,14 +388,14 @@ el0_abort_enabled:
  * slowpath.  In fact, libbarrelfish currently (2015) just refuses to continue
  * if this ever happens. */
 el0_sync_disabled:
-    /* x9 = EPC, x11 = EC, x10 = dispatcher_shared_aarch64 */
+    /* x12 = EPC, x14 = EC, x13 = dispatcher_shared_aarch64 */
 
     /* Filter out aborts. */
-    cmp x11, #0x15 /* SVC or HVC from AArch64 EL0 */
+    cmp x14, #0x15 /* SVC or HVC from AArch64 EL0 */
     b.ne el0_abort_disabled
 
     /* Use the 'disabled' area. */
-    add x10, x10, #OFFSETOF_DISP_DISABLED_AREA
+    add x13, x13, #OFFSETOF_DISP_DISABLED_AREA
 
     /* Jump back into the syscall path. */
     b save_syscall_context
@@ -376,28 +404,33 @@ el0_sync_disabled:
  * critical section.  It's (relatively) slow, and libbarrelfish doesn't
  * actually handle it at present (2015). */
 el0_abort_disabled:
+
+    /* x12 = EPC, x13 = base of save area, x14 = EC */
+
     /* x11 = EC,
        x13 = dispatcher_shared_aarch64 */
 
     /* Use the 'trap' area. */
-    add x10, x10, #OFFSETOF_DISP_TRAP_AREA
+    add x13, x13, #OFFSETOF_DISP_TRAP_AREA
 
     /* Save the reduced context. */
     /* Callee-saved registers */
-    stp x19, x20, [x10, #(19 * 8)]
-    stp x21, x22, [x10, #(21 * 8)]
-    stp x23, x24, [x10, #(23 * 8)]
-    stp x25, x26, [x10, #(25 * 8)]
-    stp x27, x28, [x10, #(27 * 8)]
-    stp x29, x30, [x10, #(29 * 8)] /* FP & LR */
+    stp x19, x20, [x13, #(19 * 8)]
+    stp x21, x22, [x13, #(21 * 8)]
+    stp x23, x24, [x13, #(23 * 8)]
+    stp x25, x26, [x13, #(25 * 8)]
+    stp x27, x28, [x13, #(27 * 8)]
+    stp x29, x30, [x13, #(29 * 8)] /* FP & LR */
 
     /* SPSR */
     mrs x19, spsr_el1
-    str x19, [x10, #(31 * 8)]
+    str x19, [x13, #(31 * 8)]
 
     /* User PC and SP */
     mrs x20, sp_el0
-    stp x20, x9, [x10, #(32 * 8)]
+    stp x20, x9, [x13, #(32 * 8)]
+
+    /* x12 = EPC, x13 = base of save area, x14 = EC */
 
     /* Now reuse the 'enabled' abort handler. */
     b el0_abort_enabled
index 4a4f3b2..cf987e6 100644 (file)
@@ -99,10 +99,10 @@ in
       arch_assembly "x86_64"  = [ "arch/x86_64/entry.S" ]
       arch_assembly "k1om"    = [ "arch/x86_64/entry.S" ]
       arch_assembly "arm"     = [ "arch/arm/entry.S", "arch/arm/syscall.S" ]
-      arch_assembly "aarch64" = [ "arch/aarch64/entry.S", "arch/aarch64/syscall.S" ]
+      arch_assembly "aarch64" = [ "arch/aarch64/entry.S" ]
       arch_assembly _         = []
-      
-      arch_include "k1om"     = "include/arch/x86_64" 
+
+      arch_include "k1om"     = "include/arch/x86_64"
       arch_include _          = ""
 
   in
@@ -184,10 +184,10 @@ in
       arch_assembly "x86_32"  = [ "arch/x86_32/entry.S" ]
       arch_assembly "x86_64"  = [ "arch/x86_64/entry.S" ]
       arch_assembly "arm"     = [ "arch/arm/entry.S", "arch/arm/syscall.S" ]
-      arch_assembly "aarch64"     = [ "arch/aarch64/entry.S", "arch/aarch64/syscall.S" ]
+      arch_assembly "aarch64" = [ "arch/aarch64/entry.S" ]
       arch_assembly _         = []
-      
-      arch_include "k1om"     = "include/arch/x86_64" 
+
+      arch_include "k1om"     = "include/arch/x86_64"
       arch_include _          =  ""
 
   in
diff --git a/lib/barrelfish/arch/aarch64/syscall.S b/lib/barrelfish/arch/aarch64/syscall.S
deleted file mode 100644 (file)
index 76195b6..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2007-2009, ETH Zurich.
- * Copyright (c) 2015, Hewlett Packard Enterprise Development LP.
- * All rights reserved.
- *
- * This file is distributed under the terms in the attached LICENSE file.
- * If you do not find this file, copies can be found by writing to:
- * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group.
- */
-        .text
-        .globl syscall
-
-syscall:
-        // Save pointer to return structure (r0), callee-save
-        // registers (x19-r28) that are cloberred.
-        // x13 is used as temporary register
-
-        mov     x13, sp
-
-        sub     sp, sp, #128
-        stp     x19, x20, [sp, #16 * 0]
-        stp     x21, x22, [sp, #16 * 1]
-        stp     x23, x24, [sp, #16 * 2]
-        stp     x25, x26, [sp, #16 * 3]
-        stp     x27, x28, [sp, #16 * 4]
-        stp     x29, x30, [sp, #16 * 5]
-        stp     x8,  x9,  [sp, #16 * 6]
-        stp     x10, x11, [sp, #16 * 7]
-
-        ldp     x8,  x9,  [x13], #16
-        ldp     x10, x11, [x13], #16
-
-        ldr     x30, =swi_done
-        svc     #0
-
-swi_done:
-        // This is where we end up executing after the system call?
-        // This accesses the stack, which was restored in do_resume
-        ldp     x19, x20, [sp], #16
-        ldp     x21, x22, [sp], #16
-        ldp     x23, x24, [sp], #16
-        ldp     x25, x26, [sp], #16
-        ldp     x27, x28, [sp], #16
-        ldp     x29, x30, [sp], #16
-        ldp     x8,  x9,  [sp], #16
-        ldp     x10, x11, [sp], #16
-
-        RET // return
-
-        nop
-        nop
-        nop
-        nop
index f9feef1..db023a1 100644 (file)
@@ -20,6 +20,34 @@ STATIC_ASSERT_OFFSETOF(struct sysret, error, 0 * sizeof(uintptr_t));
 STATIC_ASSERT_OFFSETOF(struct sysret, value, 1 * sizeof(uintptr_t));
 STATIC_ASSERT(SYSCALL_REG == 0, "Bad register for system call argument.");
 
+struct sysret
+syscall(uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+        uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7,
+        uint64_t arg8, uint64_t arg9, uint64_t arg10, uint64_t arg11)
+{
+    register uint64_t ret1 __asm("x0")  = num;
+    register uint64_t ret2 __asm("x1")  = arg1;
+    register uint64_t a2   __asm("x2")  = arg2;
+    register uint64_t a3   __asm("x3")  = arg3;
+    register uint64_t a4   __asm("x4")  = arg4;
+    register uint64_t a5   __asm("x5")  = arg5;
+    register uint64_t a6   __asm("x6")  = arg6;
+    register uint64_t a7   __asm("x7")  = arg7;
+    register uint64_t a8   __asm("x8")  = arg8;
+    register uint64_t a9   __asm("x9")  = arg9;
+    register uint64_t a10  __asm("x10") = arg10;
+    register uint64_t a11  __asm("x11") = arg11;
+
+    __asm volatile (
+        "svc #0                         \n\t"
+        :  "=r" (ret1), "=r" (ret2)
+        : "r" (ret1), "r" (ret2), "r" (a2), "r" (a3), "r" (a4), "r" (a5), \
+          "r" (a6), "r" (a7), "r" (a8), "r" (a9), "r" (a10), "r" (a11)
+    );
+
+    return (struct sysret){/*error*/ ret1, /*value*/ ret2};
+}
+
 //
 // System call wrappers
 //