safe-syscall.inc.S (3198B)
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 linux-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 /* 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'). 23 * We return a long which is the syscall's return value, which 24 * may be negative-errno on failure. Conversion to the 25 * -1-and-errno-set convention is done by the calling wrapper. 26 */ 27safe_syscall_base: 28 .cfi_startproc 29 push %ebp 30 .cfi_adjust_cfa_offset 4 31 .cfi_rel_offset ebp, 0 32 push %esi 33 .cfi_adjust_cfa_offset 4 34 .cfi_rel_offset esi, 0 35 push %edi 36 .cfi_adjust_cfa_offset 4 37 .cfi_rel_offset edi, 0 38 push %ebx 39 .cfi_adjust_cfa_offset 4 40 .cfi_rel_offset ebx, 0 41 42 /* The syscall calling convention isn't the same as the C one: 43 * we enter with 0(%esp) == return address 44 * 4(%esp) == *signal_pending 45 * 8(%esp) == syscall number 46 * 12(%esp) ... 32(%esp) == syscall arguments 47 * and return the result in eax 48 * and the syscall instruction needs 49 * eax == syscall number 50 * ebx, ecx, edx, esi, edi, ebp == syscall arguments 51 * and returns the result in eax 52 * Shuffle everything around appropriately. 53 * Note the 16 bytes that we pushed to save registers. 54 */ 55 mov 12+16(%esp), %ebx /* the syscall arguments */ 56 mov 16+16(%esp), %ecx 57 mov 20+16(%esp), %edx 58 mov 24+16(%esp), %esi 59 mov 28+16(%esp), %edi 60 mov 32+16(%esp), %ebp 61 62 /* This next sequence of code works in conjunction with the 63 * rewind_if_safe_syscall_function(). If a signal is taken 64 * and the interrupted PC is anywhere between 'safe_syscall_start' 65 * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. 66 * The code sequence must therefore be able to cope with this, and 67 * the syscall instruction must be the final one in the sequence. 68 */ 69safe_syscall_start: 70 /* if signal_pending is non-zero, don't do the call */ 71 mov 4+16(%esp), %eax /* signal_pending */ 72 cmpl $0, (%eax) 73 jnz 1f 74 mov 8+16(%esp), %eax /* syscall number */ 75 int $0x80 76safe_syscall_end: 77 /* code path for having successfully executed the syscall */ 78 pop %ebx 79 .cfi_remember_state 80 .cfi_adjust_cfa_offset -4 81 .cfi_restore ebx 82 pop %edi 83 .cfi_adjust_cfa_offset -4 84 .cfi_restore edi 85 pop %esi 86 .cfi_adjust_cfa_offset -4 87 .cfi_restore esi 88 pop %ebp 89 .cfi_adjust_cfa_offset -4 90 .cfi_restore ebp 91 ret 92 931: 94 /* code path when we didn't execute the syscall */ 95 .cfi_restore_state 96 mov $-TARGET_ERESTARTSYS, %eax 97 jmp safe_syscall_end 98 .cfi_endproc 99 100 .size safe_syscall_base, .-safe_syscall_base