From: Waldemar Kozaczuk <[email protected]>
Committer: Waldemar Kozaczuk <[email protected]>
Branch: master

aarch64: handle system calls

This patch enhances the aarch64 port to support handling system
call instruction - SVC.

On aarch64 the system calls are handled as synchronous exceptions
triggered by executing the SVC instruction. Per syscall specification
described in https://man7.org/linux/man-pages/man2/syscall.2.html,
the caller needs to pass arguments using the x0-x5 registers, set the
syscall number in x8 register and finally execute svc instruction.

To handle this on OSv side, this patch enhances existing synchronous
exception handler in entry.S to detect if the exception class set in ESR
register matches the one for SVC (0x15) and then retrieve the arguments
from the registers x0-x5 and syscall number from x8 and invoke the
syscall_wrapper function in linux.cc. We also need to enable exceptions
before calling syscall_wrapper so that functions called downstream
may sleep which is similar to what we do for page faults.

Please note the resulting enhancements are enough to make
tst-syscall.so pass.

Fixes #1156

Signed-off-by: Waldemar Kozaczuk <[email protected]>

---
diff --git a/arch/aarch64/entry.S b/arch/aarch64/entry.S
--- a/arch/aarch64/entry.S
+++ b/arch/aarch64/entry.S
@@ -120,6 +120,7 @@ thread_main:
 .equ ESR_EC_END,31          // Exception Class field end in ESR
 .equ ESR_EC_DATA_ABORT,0x25 // Exception Class Data Abort value
 .equ ESR_EC_INSN_ABORT,0x21 // Exception Class Instruction Abort value
+.equ ESR_EC_SVC64,0x15      // Exception Class for SVC (System Call) in 64-bit 
state
 
 .equ ESR_ISS_BEG,0          // Instruction-Specific Syndrome field begin in ESR
 .equ ESR_ISS_END,23         // Instruction-Specific Syndrome field end in ESR
@@ -197,6 +198,8 @@ entry_curr_el_spx_sync:
         str     w1, [sp, #272] // Store Exception Syndrom Register in the frame
         ubfm    x2, x1, #ESR_EC_BEG, #ESR_EC_END // Exception Class -> X2
         ubfm    x3, x1, #ESR_FLT_BEG, #ESR_FLT_END // FLT -> X3
+        cmp     x2, #ESR_EC_SVC64
+        b.eq    handle_system_call
         cmp     x2, #ESR_EC_DATA_ABORT
         b.eq    handle_mem_abort
         cmp     x2, #ESR_EC_INSN_ABORT
@@ -211,6 +214,29 @@ handle_mem_abort:
         pop_state_from_exception_frame
         eret
         .cfi_endproc
+handle_system_call:
+        .cfi_startproc
+        //see https://man7.org/linux/man-pages/man2/syscall.2.html for details
+        //about calling convention for arm64
+
+        //because we used x1, x2, x3 and x4 above we need to restore them from 
the frame
+        ldp x1, x2, [sp, #8]
+        ldp x3, x4, [sp, #24]
+
+        mov x6, x8      // copy syscall number passed in x8 to the last 7th 
argument of the syscall_wrapper
+
+        msr daifclr, #2 // enable interrupts, so that the functions called by 
syscall_wrapper can sleep
+        isb
+
+        bl syscall_wrapper
+
+        msr daifset, #2 // disable interrupts
+        isb
+
+        str     x0, [sp, #0] // copy the result in x0 directly into the frame 
so that it can be restored
+        pop_state_from_exception_frame
+        eret
+        .cfi_endproc
 unexpected_sync_exception:
         .cfi_startproc
         mov     x0, sp  // save exception_frame to x0
diff --git a/linux.cc b/linux.cc
--- a/linux.cc
+++ b/linux.cc
@@ -498,12 +498,22 @@ OSV_LIBC_API long syscall(long number, ...)
 }
 long __syscall(long number, ...)  __attribute__((alias("syscall")));
 
+#ifdef __x86_64__
 // In x86-64, a SYSCALL instruction has exactly 6 parameters, because this is 
the number of registers
 // alloted for passing them (additional parameters *cannot* be passed on the 
stack). So we can get
 // 7 arguments to this function (syscall number plus its 6 parameters). 
Because in the x86-64 ABI the
 // seventh argument is on the stack, we must pass the arguments explicitly to 
the syscall() function
 // and can't just call it without any arguments and hope everything will be 
passed on
 extern "C" long syscall_wrapper(long number, long p1, long p2, long p3, long 
p4, long p5, long p6)
+#endif
+#ifdef __aarch64__
+// In aarch64, the first 8 parameters to a procedure call are passed in the 
x0-x7 registers and
+// the parameters of syscall call (SVC intruction) in are passed in x0-x5 
registers and syscall number
+// in x8 register before. To avoid shuffling the arguments around we make 
syscall_wrapper()
+// accept the syscall parameters as is but accept the syscall number as the 
last 7th argument which
+// the code in entry.S arranges.
+extern "C" long syscall_wrapper(long p1, long p2, long p3, long p4, long p5, 
long p6, long number)
+#endif
 {
     int errno_backup = errno;
     // syscall and function return value are in rax
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -133,15 +133,15 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so 
tst-bsd-evh.so \
        tst-getopt.so tst-getopt-pie.so tst-non-pie.so tst-semaphore.so \
        tst-elf-init.so tst-realloc.so tst-setjmp.so \
        libtls.so libtls_gold.so tst-tls.so tst-tls-gold.so tst-tls-pie.so \
-       tst-sigaction.so
+       tst-sigaction.so tst-syscall.so
 #      libstatic-thread-variable.so tst-static-thread-variable.so \
 
 #TODO For now let us disable these tests for aarch64 until
 # we support floating point numbers, TLS and correct syscall handling
 # The tst-ifaddrs.so is an exception and it does not compile due to some
 # missing headers
 ifeq ($(arch),x64)
-tests += tst-syscall.so tst-ifaddrs.so tst-mmx-fpu.so
+tests += tst-ifaddrs.so tst-mmx-fpu.so
 endif
 
 tests += testrunner.so

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/000000000000cf027305de39b8e7%40google.com.

Reply via email to