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 */ 23safe_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 */ 65safe_syscall_start: 66 /* if signal_pending is non-zero, don't do the call */ 67 cmpl $0, (%rbp) 68 jnz 2f 69 syscall 70safe_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__) 910: neg %eax 92 jmp 1f 93#endif 94 95 /* code path when we didn't execute the syscall */ 962: mov $QEMU_ERESTARTSYS, %eax 97 98 /* code path setting errno */ 991: pop %rbp 100 .cfi_def_cfa_offset 8 101 .cfi_restore rbp 102 jmp safe_syscall_set_errno_tail 103 .cfi_endproc 104 105 .size safe_syscall_base, .-safe_syscall_base 106