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