qemu

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

safe-syscall.inc.S (3936B)


      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  * Copyright (C) 2015 Timothy Edward Baldwin <T.E.Baldwin99@members.leeds.ac.uk>
      7  *
      8  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      9  * See the COPYING file in the top-level directory.
     10  */
     11 
     12         .global safe_syscall_base
     13         .global safe_syscall_start
     14         .global safe_syscall_end
     15         .type   safe_syscall_base, @function
     16 
     17         /* This is the entry point for making a system call. The calling
     18          * convention here is that of a C varargs function with the
     19          * first argument an 'int *' to the signal_pending flag, the
     20          * second one the system call number (as a 'long'), and all further
     21          * arguments being syscall arguments (also 'long').
     22          */
     23 safe_syscall_base:
     24         .cfi_startproc
     25         /* This saves a frame pointer and aligns the stack for the syscall.
     26          * (It's unclear if the syscall ABI has the same stack alignment
     27          * requirements as the userspace function call ABI, but better safe than
     28          * sorry. Appendix A2 of http://www.x86-64.org/documentation/abi.pdf
     29          * does not list any ABI differences regarding stack alignment.)
     30          */
     31         push    %rbp
     32         .cfi_adjust_cfa_offset 8
     33         .cfi_rel_offset rbp, 0
     34 
     35         /*
     36          * The syscall calling convention isn't the same as the C one:
     37          * we enter with rdi == &signal_pending
     38          *               rsi == syscall number
     39          *               rdx, rcx, r8, r9, (stack), (stack) == syscall arguments
     40          *               and return the result in rax
     41          * and the syscall instruction needs
     42          *               rax == syscall number
     43          *               rdi, rsi, rdx, r10, r8, r9 == syscall arguments
     44          *               and returns the result in rax
     45          * Shuffle everything around appropriately.
     46          * Note that syscall will trash rcx and r11.
     47          */
     48         mov     %rsi, %rax /* syscall number */
     49         mov     %rdi, %rbp /* signal_pending pointer */
     50         /* and the syscall arguments */
     51         mov     %rdx, %rdi
     52         mov     %rcx, %rsi
     53         mov     %r8,  %rdx
     54         mov     %r9,  %r10
     55         mov     16(%rsp), %r8
     56         mov     24(%rsp), %r9
     57 
     58         /* This next sequence of code works in conjunction with the
     59          * rewind_if_safe_syscall_function(). If a signal is taken
     60          * and the interrupted PC is anywhere between 'safe_syscall_start'
     61          * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
     62          * The code sequence must therefore be able to cope with this, and
     63          * the syscall instruction must be the final one in the sequence.
     64          */
     65 safe_syscall_start:
     66         /* if signal_pending is non-zero, don't do the call */
     67         cmpl    $0, (%rbp)
     68         jnz     2f
     69         syscall
     70 safe_syscall_end:
     71 
     72         /* code path for having successfully executed the syscall */
     73 #if defined(__linux__)
     74         /* Linux kernel returns (small) negative errno. */
     75         cmp     $-4095, %rax
     76         jae     0f
     77 #elif defined(__FreeBSD__)
     78         /* FreeBSD kernel returns positive errno and C bit set. */
     79         jc      1f
     80 #else
     81 #error "unsupported os"
     82 #endif
     83         pop     %rbp
     84         .cfi_remember_state
     85         .cfi_def_cfa_offset 8
     86         .cfi_restore rbp
     87         ret
     88         .cfi_restore_state
     89 
     90 #if defined(__linux__)
     91 0:      neg     %eax
     92         jmp     1f
     93 #endif
     94 
     95         /* code path when we didn't execute the syscall */
     96 2:      mov     $QEMU_ERESTARTSYS, %eax
     97 
     98         /* code path setting errno */
     99 1:      pop     %rbp
    100         .cfi_def_cfa_offset 8
    101         .cfi_restore rbp
    102         mov     %eax, %edi
    103         jmp     safe_syscall_set_errno_tail
    104         .cfi_endproc
    105 
    106         .size   safe_syscall_base, .-safe_syscall_base