qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

safe-syscall.inc.S (3256B)


      1 /*
      2  * safe-syscall.inc.S : host-specific assembly fragment
      3  * to handle signals occurring at the same time as system calls.
      4  * This is intended to be included by common-user/safe-syscall.S
      5  *
      6  * Written by Richard Henderson <rth@twiddle.net>
      7  * Copyright (C) 2016 Red Hat, Inc.
      8  *
      9  * This work is licensed under the terms of the GNU GPL, version 2 or later.
     10  * See the COPYING file in the top-level directory.
     11  */
     12 
     13         .global safe_syscall_base
     14         .global safe_syscall_start
     15         .global safe_syscall_end
     16         .type   safe_syscall_base, #function
     17         .type   safe_syscall_start, #function
     18         .type   safe_syscall_end, #function
     19 
     20         /* This is the entry point for making a system call. The calling
     21          * convention here is that of a C varargs function with the
     22          * first argument an 'int *' to the signal_pending flag, the
     23          * second one the system call number (as a 'long'), and all further
     24          * arguments being syscall arguments (also 'long').
     25          */
     26 safe_syscall_base:
     27         .cfi_startproc
     28         /* The syscall calling convention isn't the same as the
     29          * C one:
     30          * we enter with x0 == &signal_pending
     31          *               x1 == syscall number
     32          *               x2 ... x7, (stack) == syscall arguments
     33          *               and return the result in x0
     34          * and the syscall instruction needs
     35          *               x8 == syscall number
     36          *               x0 ... x6 == syscall arguments
     37          *               and returns the result in x0
     38          * Shuffle everything around appropriately.
     39          */
     40         mov     x9, x0          /* signal_pending pointer */
     41         mov     x8, x1          /* syscall number */
     42         mov     x0, x2          /* syscall arguments */
     43         mov     x1, x3
     44         mov     x2, x4
     45         mov     x3, x5
     46         mov     x4, x6
     47         mov     x5, x7
     48         ldr     x6, [sp]
     49 
     50         /* This next sequence of code works in conjunction with the
     51          * rewind_if_safe_syscall_function(). If a signal is taken
     52          * and the interrupted PC is anywhere between 'safe_syscall_start'
     53          * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
     54          * The code sequence must therefore be able to cope with this, and
     55          * the syscall instruction must be the final one in the sequence.
     56          */
     57 safe_syscall_start:
     58         /* if signal_pending is non-zero, don't do the call */
     59         ldr     w10, [x9]
     60         cbnz    w10, 2f
     61         svc     0x0
     62 safe_syscall_end:
     63 
     64         /* code path for having successfully executed the syscall */
     65 #if defined(__linux__)
     66         /* Linux kernel returns (small) negative errno. */
     67         cmp     x0, #-4096
     68         b.hi    0f
     69 #elif defined(__FreeBSD__)
     70         /* FreeBSD kernel returns positive errno and C bit set. */
     71         b.cs    1f
     72 #else
     73 #error "unsupported os"
     74 #endif
     75         ret
     76 
     77 #if defined(__linux__)
     78         /* code path setting errno */
     79 0:      neg     w0, w0
     80         b       safe_syscall_set_errno_tail
     81 #endif
     82 
     83         /* code path when we didn't execute the syscall */
     84 2:      mov     w0, #QEMU_ERESTARTSYS
     85 1:      b       safe_syscall_set_errno_tail
     86 
     87         .cfi_endproc
     88         .size   safe_syscall_base, .-safe_syscall_base