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 .type safe_syscall_start, #function 18 .type safe_syscall_end, #function 19 20 /* This is the entry point for making a system call. The calling 21 * convention here is that of a C varargs function with the 22 * first argument an 'int *' to the signal_pending flag, the 23 * second one the system call number (as a 'long'), and all further 24 * arguments being syscall arguments (also 'long'). 25 */ 26safe_syscall_base: 27 .cfi_startproc 28 /* The syscall calling convention isn't the same as the 29 * C one: 30 * we enter with x0 == &signal_pending 31 * x1 == syscall number 32 * x2 ... x7, (stack) == syscall arguments 33 * and return the result in x0 34 * and the syscall instruction needs 35 * x8 == syscall number 36 * x0 ... x6 == syscall arguments 37 * and returns the result in x0 38 * Shuffle everything around appropriately. 39 */ 40 mov x9, x0 /* signal_pending pointer */ 41 mov x8, x1 /* syscall number */ 42 mov x0, x2 /* syscall arguments */ 43 mov x1, x3 44 mov x2, x4 45 mov x3, x5 46 mov x4, x6 47 mov x5, x7 48 ldr x6, [sp] 49 50 /* This next sequence of code works in conjunction with the 51 * rewind_if_safe_syscall_function(). If a signal is taken 52 * and the interrupted PC is anywhere between 'safe_syscall_start' 53 * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. 54 * The code sequence must therefore be able to cope with this, and 55 * the syscall instruction must be the final one in the sequence. 56 */ 57safe_syscall_start: 58 /* if signal_pending is non-zero, don't do the call */ 59 ldr w10, [x9] 60 cbnz w10, 2f 61 svc 0x0 62safe_syscall_end: 63 64 /* code path for having successfully executed the syscall */ 65#if defined(__linux__) 66 /* Linux kernel returns (small) negative errno. */ 67 cmp x0, #-4096 68 b.hi 0f 69#elif defined(__FreeBSD__) 70 /* FreeBSD kernel returns positive errno and C bit set. */ 71 b.cs 1f 72#else 73#error "unsupported os" 74#endif 75 ret 76 77#if defined(__linux__) 78 /* code path setting errno */ 790: neg w0, w0 80 b safe_syscall_set_errno_tail 81#endif 82 83 /* code path when we didn't execute the syscall */ 842: mov w0, #QEMU_ERESTARTSYS 851: b safe_syscall_set_errno_tail 86 87 .cfi_endproc 88 .size safe_syscall_base, .-safe_syscall_base 89