1bbf15aafSRichard Henderson/* 2bbf15aafSRichard Henderson * safe-syscall.inc.S : host-specific assembly fragment 3bbf15aafSRichard Henderson * to handle signals occurring at the same time as system calls. 4bbf15aafSRichard Henderson * This is intended to be included by common-user/safe-syscall.S 5bbf15aafSRichard Henderson * 6bbf15aafSRichard Henderson * Written by Richard Henderson <rth@twiddle.net> 7bbf15aafSRichard Henderson * Copyright (C) 2016 Red Hat, Inc. 8bbf15aafSRichard Henderson * 9bbf15aafSRichard Henderson * This work is licensed under the terms of the GNU GPL, version 2 or later. 10bbf15aafSRichard Henderson * See the COPYING file in the top-level directory. 11bbf15aafSRichard Henderson */ 12bbf15aafSRichard Henderson 13bbf15aafSRichard Henderson .global safe_syscall_base 14bbf15aafSRichard Henderson .global safe_syscall_start 15bbf15aafSRichard Henderson .global safe_syscall_end 16bbf15aafSRichard Henderson .type safe_syscall_base, @function 17bbf15aafSRichard Henderson 18bbf15aafSRichard Henderson /* This is the entry point for making a system call. The calling 19bbf15aafSRichard Henderson * convention here is that of a C varargs function with the 20bbf15aafSRichard Henderson * first argument an 'int *' to the signal_pending flag, the 21bbf15aafSRichard Henderson * second one the system call number (as a 'long'), and all further 22bbf15aafSRichard Henderson * arguments being syscall arguments (also 'long'). 23bbf15aafSRichard Henderson */ 24bbf15aafSRichard Hendersonsafe_syscall_base: 25bbf15aafSRichard Henderson .cfi_startproc 26bbf15aafSRichard Henderson push %ebp 27bbf15aafSRichard Henderson .cfi_adjust_cfa_offset 4 28bbf15aafSRichard Henderson .cfi_rel_offset ebp, 0 29bbf15aafSRichard Henderson push %esi 30bbf15aafSRichard Henderson .cfi_adjust_cfa_offset 4 31bbf15aafSRichard Henderson .cfi_rel_offset esi, 0 32bbf15aafSRichard Henderson push %edi 33bbf15aafSRichard Henderson .cfi_adjust_cfa_offset 4 34bbf15aafSRichard Henderson .cfi_rel_offset edi, 0 35bbf15aafSRichard Henderson push %ebx 36bbf15aafSRichard Henderson .cfi_adjust_cfa_offset 4 37bbf15aafSRichard Henderson .cfi_rel_offset ebx, 0 38bbf15aafSRichard Henderson 39bbf15aafSRichard Henderson /* The syscall calling convention isn't the same as the C one: 40bbf15aafSRichard Henderson * we enter with 0(%esp) == return address 41bbf15aafSRichard Henderson * 4(%esp) == &signal_pending 42bbf15aafSRichard Henderson * 8(%esp) == syscall number 43bbf15aafSRichard Henderson * 12(%esp) ... 32(%esp) == syscall arguments 44bbf15aafSRichard Henderson * and return the result in eax 45bbf15aafSRichard Henderson * and the syscall instruction needs 46bbf15aafSRichard Henderson * eax == syscall number 47bbf15aafSRichard Henderson * ebx, ecx, edx, esi, edi, ebp == syscall arguments 48bbf15aafSRichard Henderson * and returns the result in eax 49bbf15aafSRichard Henderson * Shuffle everything around appropriately. 50bbf15aafSRichard Henderson * Note the 16 bytes that we pushed to save registers. 51bbf15aafSRichard Henderson */ 52bbf15aafSRichard Henderson mov 12+16(%esp), %ebx /* the syscall arguments */ 53bbf15aafSRichard Henderson mov 16+16(%esp), %ecx 54bbf15aafSRichard Henderson mov 20+16(%esp), %edx 55bbf15aafSRichard Henderson mov 24+16(%esp), %esi 56bbf15aafSRichard Henderson mov 28+16(%esp), %edi 57bbf15aafSRichard Henderson mov 32+16(%esp), %ebp 58bbf15aafSRichard Henderson 59bbf15aafSRichard Henderson /* This next sequence of code works in conjunction with the 60bbf15aafSRichard Henderson * rewind_if_safe_syscall_function(). If a signal is taken 61bbf15aafSRichard Henderson * and the interrupted PC is anywhere between 'safe_syscall_start' 62bbf15aafSRichard Henderson * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. 63bbf15aafSRichard Henderson * The code sequence must therefore be able to cope with this, and 64bbf15aafSRichard Henderson * the syscall instruction must be the final one in the sequence. 65bbf15aafSRichard Henderson */ 66bbf15aafSRichard Hendersonsafe_syscall_start: 67bbf15aafSRichard Henderson /* if signal_pending is non-zero, don't do the call */ 68bbf15aafSRichard Henderson mov 4+16(%esp), %eax /* signal_pending */ 69bbf15aafSRichard Henderson cmpl $0, (%eax) 70bbf15aafSRichard Henderson jnz 2f 71bbf15aafSRichard Henderson mov 8+16(%esp), %eax /* syscall number */ 72bbf15aafSRichard Henderson int $0x80 73bbf15aafSRichard Hendersonsafe_syscall_end: 745bfd125eSRichard Henderson 75bbf15aafSRichard Henderson /* code path for having successfully executed the syscall */ 765bfd125eSRichard Henderson#if defined(__linux__) 775bfd125eSRichard Henderson /* Linux kernel returns (small) negative errno. */ 78bbf15aafSRichard Henderson cmp $-4095, %eax 79bbf15aafSRichard Henderson jae 0f 805bfd125eSRichard Henderson#elif defined(__FreeBSD__) 815bfd125eSRichard Henderson /* FreeBSD kernel returns positive errno and C bit set. */ 825bfd125eSRichard Henderson jc 1f 835bfd125eSRichard Henderson#else 845bfd125eSRichard Henderson#error "unsupported os" 855bfd125eSRichard Henderson#endif 86bbf15aafSRichard Henderson pop %ebx 87bbf15aafSRichard Henderson .cfi_remember_state 88bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 89bbf15aafSRichard Henderson .cfi_restore ebx 90bbf15aafSRichard Henderson pop %edi 91bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 92bbf15aafSRichard Henderson .cfi_restore edi 93bbf15aafSRichard Henderson pop %esi 94bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 95bbf15aafSRichard Henderson .cfi_restore esi 96bbf15aafSRichard Henderson pop %ebp 97bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 98bbf15aafSRichard Henderson .cfi_restore ebp 99bbf15aafSRichard Henderson ret 100bbf15aafSRichard Henderson .cfi_restore_state 101bbf15aafSRichard Henderson 1025bfd125eSRichard Henderson#if defined(__linux__) 103bbf15aafSRichard Henderson0: neg %eax 104bbf15aafSRichard Henderson jmp 1f 1055bfd125eSRichard Henderson#endif 106bbf15aafSRichard Henderson 107bbf15aafSRichard Henderson /* code path when we didn't execute the syscall */ 108bbf15aafSRichard Henderson2: mov $QEMU_ERESTARTSYS, %eax 109bbf15aafSRichard Henderson 110bbf15aafSRichard Henderson /* code path setting errno */ 111bbf15aafSRichard Henderson1: pop %ebx 112bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 113bbf15aafSRichard Henderson .cfi_restore ebx 114bbf15aafSRichard Henderson pop %edi 115bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 116bbf15aafSRichard Henderson .cfi_restore edi 117bbf15aafSRichard Henderson pop %esi 118bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 119bbf15aafSRichard Henderson .cfi_restore esi 120bbf15aafSRichard Henderson pop %ebp 121bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -4 122bbf15aafSRichard Henderson .cfi_restore ebp 123*fb084237SRichard Henderson mov %eax, 4(%esp) 124bbf15aafSRichard Henderson jmp safe_syscall_set_errno_tail 125bbf15aafSRichard Henderson 126bbf15aafSRichard Henderson .cfi_endproc 127bbf15aafSRichard Henderson .size safe_syscall_base, .-safe_syscall_base 128