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
6 * Written by Richard Henderson <rth@twiddle.net>
7 * Copyright (C) 2016 Red Hat, Inc.
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.
13 .global safe_syscall_base
14 .global safe_syscall_start
15 .global safe_syscall_end
16 .type safe_syscall_base, @function
18 /* This is the entry point for making a system call. The calling
19 * convention here is that of a C varargs function with the
20 * first argument an 'int *' to the signal_pending flag, the
21 * second one the system call number (as a 'long'), and all further
22 * arguments being syscall arguments (also 'long').
27 .cfi_adjust_cfa_offset 4
28 .cfi_rel_offset ebp, 0
30 .cfi_adjust_cfa_offset 4
31 .cfi_rel_offset esi, 0
33 .cfi_adjust_cfa_offset 4
34 .cfi_rel_offset edi, 0
36 .cfi_adjust_cfa_offset 4
37 .cfi_rel_offset ebx, 0
39 /* The syscall calling convention isn't the same as the C one:
40 * we enter with 0(%esp) == return address
41 * 4(%esp) == &signal_pending
42 * 8(%esp) == syscall number
43 * 12(%esp) ... 32(%esp) == syscall arguments
44 * and return the result in eax
45 * and the syscall instruction needs
46 * eax == syscall number
47 * ebx, ecx, edx, esi, edi, ebp == syscall arguments
48 * and returns the result in eax
49 * Shuffle everything around appropriately.
50 * Note the 16 bytes that we pushed to save registers.
52 mov 12+16(%esp), %ebx /* the syscall arguments */
59 /* This next sequence of code works in conjunction with the
60 * rewind_if_safe_syscall_function(). If a signal is taken
61 * and the interrupted PC is anywhere between 'safe_syscall_start'
62 * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
63 * The code sequence must therefore be able to cope with this, and
64 * the syscall instruction must be the final one in the sequence.
67 /* if signal_pending is non-zero, don't do the call */
68 mov 4+16(%esp), %eax /* signal_pending */
71 mov 8+16(%esp), %eax /* syscall number */
75 /* code path for having successfully executed the syscall */
76 #if defined(__linux__)
77 /* Linux kernel returns (small) negative errno. */
80 #elif defined(__FreeBSD__)
81 /* FreeBSD kernel returns positive errno and C bit set. */
84 #error "unsupported os"
88 .cfi_adjust_cfa_offset -4
91 .cfi_adjust_cfa_offset -4
94 .cfi_adjust_cfa_offset -4
97 .cfi_adjust_cfa_offset -4
102 #if defined(__linux__)
107 /* code path when we didn't execute the syscall */
108 2: mov $QEMU_ERESTARTSYS, %eax
110 /* code path setting errno */
112 .cfi_adjust_cfa_offset -4
115 .cfi_adjust_cfa_offset -4
118 .cfi_adjust_cfa_offset -4
121 .cfi_adjust_cfa_offset -4
124 jmp safe_syscall_set_errno_tail
127 .size safe_syscall_base, .-safe_syscall_base