qemu

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

safe-syscall.inc.S (3907B)


      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 
     18         .cfi_sections   .debug_frame
     19 
     20         .text
     21         .syntax unified
     22         .arm
     23         .align 2
     24 
     25         /* This is the entry point for making a system call. The calling
     26          * convention here is that of a C varargs function with the
     27          * first argument an 'int *' to the signal_pending flag, the
     28          * second one the system call number (as a 'long'), and all further
     29          * arguments being syscall arguments (also 'long').
     30          */
     31 safe_syscall_base:
     32         .fnstart
     33         .cfi_startproc
     34         mov     r12, sp                 /* save entry stack */
     35         push    { r4, r5, r6, r7, r8, lr }
     36         .save   { r4, r5, r6, r7, r8, lr }
     37         .cfi_adjust_cfa_offset 24
     38         .cfi_rel_offset r4, 0
     39         .cfi_rel_offset r5, 4
     40         .cfi_rel_offset r6, 8
     41         .cfi_rel_offset r7, 12
     42         .cfi_rel_offset r8, 16
     43         .cfi_rel_offset lr, 20
     44 
     45         /* The syscall calling convention isn't the same as the C one:
     46          * we enter with r0 == &signal_pending
     47          *               r1 == syscall number
     48          *               r2, r3, [sp+0] ... [sp+12] == syscall arguments
     49          *               and return the result in r0
     50          * and the syscall instruction needs
     51          *               r7 == syscall number
     52          *               r0 ... r6 == syscall arguments
     53          *               and returns the result in r0
     54          * Shuffle everything around appropriately.
     55          * Note the 16 bytes that we pushed to save registers.
     56          */
     57         mov     r8, r0                  /* copy signal_pending */
     58         mov     r7, r1                  /* syscall number */
     59         mov     r0, r2                  /* syscall args */
     60         mov     r1, r3
     61         ldm     r12, { r2, r3, r4, r5, r6 }
     62 
     63         /* This next sequence of code works in conjunction with the
     64          * rewind_if_safe_syscall_function(). If a signal is taken
     65          * and the interrupted PC is anywhere between 'safe_syscall_start'
     66          * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
     67          * The code sequence must therefore be able to cope with this, and
     68          * the syscall instruction must be the final one in the sequence.
     69          */
     70 safe_syscall_start:
     71         /* if signal_pending is non-zero, don't do the call */
     72         ldr     r12, [r8]               /* signal_pending */
     73         tst     r12, r12
     74         bne     2f
     75         swi     0
     76 safe_syscall_end:
     77 
     78         /* code path for having successfully executed the syscall */
     79 #if defined(__linux__)
     80         /* Linux kernel returns (small) negative errno. */
     81         cmp     r0, #-4096
     82         neghi   r0, r0
     83         bhi     1f
     84 #elif defined(__FreeBSD__)
     85         /* FreeBSD kernel returns positive errno and C bit set. */
     86         bcs     1f
     87 #else
     88 #error "unsupported os"
     89 #endif
     90         pop     { r4, r5, r6, r7, r8, pc }
     91 
     92         /* code path when we didn't execute the syscall */
     93 2:      mov     r0, #QEMU_ERESTARTSYS
     94 
     95         /* code path setting errno */
     96 1:      pop     { r4, r5, r6, r7, r8, lr }
     97         .cfi_adjust_cfa_offset -24
     98         .cfi_restore r4
     99         .cfi_restore r5
    100         .cfi_restore r6
    101         .cfi_restore r7
    102         .cfi_restore r8
    103         .cfi_restore lr
    104         b       safe_syscall_set_errno_tail
    105 
    106         .fnend
    107         .cfi_endproc
    108         .size   safe_syscall_base, .-safe_syscall_base