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 .cfi_sections .debug_frame 19bbf15aafSRichard Henderson 20bbf15aafSRichard Henderson .text 21bbf15aafSRichard Henderson .syntax unified 22bbf15aafSRichard Henderson .arm 23bbf15aafSRichard Henderson .align 2 24bbf15aafSRichard Henderson 25bbf15aafSRichard Henderson /* This is the entry point for making a system call. The calling 26bbf15aafSRichard Henderson * convention here is that of a C varargs function with the 27bbf15aafSRichard Henderson * first argument an 'int *' to the signal_pending flag, the 28bbf15aafSRichard Henderson * second one the system call number (as a 'long'), and all further 29bbf15aafSRichard Henderson * arguments being syscall arguments (also 'long'). 30bbf15aafSRichard Henderson */ 31bbf15aafSRichard Hendersonsafe_syscall_base: 32bbf15aafSRichard Henderson .fnstart 33bbf15aafSRichard Henderson .cfi_startproc 34bbf15aafSRichard Henderson mov r12, sp /* save entry stack */ 35bbf15aafSRichard Henderson push { r4, r5, r6, r7, r8, lr } 36bbf15aafSRichard Henderson .save { r4, r5, r6, r7, r8, lr } 37bbf15aafSRichard Henderson .cfi_adjust_cfa_offset 24 38bbf15aafSRichard Henderson .cfi_rel_offset r4, 0 39bbf15aafSRichard Henderson .cfi_rel_offset r5, 4 40bbf15aafSRichard Henderson .cfi_rel_offset r6, 8 41bbf15aafSRichard Henderson .cfi_rel_offset r7, 12 42bbf15aafSRichard Henderson .cfi_rel_offset r8, 16 43bbf15aafSRichard Henderson .cfi_rel_offset lr, 20 44bbf15aafSRichard Henderson 45bbf15aafSRichard Henderson /* The syscall calling convention isn't the same as the C one: 46bbf15aafSRichard Henderson * we enter with r0 == &signal_pending 47bbf15aafSRichard Henderson * r1 == syscall number 48bbf15aafSRichard Henderson * r2, r3, [sp+0] ... [sp+12] == syscall arguments 49bbf15aafSRichard Henderson * and return the result in r0 50bbf15aafSRichard Henderson * and the syscall instruction needs 51bbf15aafSRichard Henderson * r7 == syscall number 52bbf15aafSRichard Henderson * r0 ... r6 == syscall arguments 53bbf15aafSRichard Henderson * and returns the result in r0 54bbf15aafSRichard Henderson * Shuffle everything around appropriately. 55bbf15aafSRichard Henderson * Note the 16 bytes that we pushed to save registers. 56bbf15aafSRichard Henderson */ 57bbf15aafSRichard Henderson mov r8, r0 /* copy signal_pending */ 58bbf15aafSRichard Henderson mov r7, r1 /* syscall number */ 59bbf15aafSRichard Henderson mov r0, r2 /* syscall args */ 60bbf15aafSRichard Henderson mov r1, r3 61bbf15aafSRichard Henderson ldm r12, { r2, r3, r4, r5, r6 } 62bbf15aafSRichard Henderson 63bbf15aafSRichard Henderson /* This next sequence of code works in conjunction with the 64bbf15aafSRichard Henderson * rewind_if_safe_syscall_function(). If a signal is taken 65bbf15aafSRichard Henderson * and the interrupted PC is anywhere between 'safe_syscall_start' 66bbf15aafSRichard Henderson * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. 67bbf15aafSRichard Henderson * The code sequence must therefore be able to cope with this, and 68bbf15aafSRichard Henderson * the syscall instruction must be the final one in the sequence. 69bbf15aafSRichard Henderson */ 70bbf15aafSRichard Hendersonsafe_syscall_start: 71bbf15aafSRichard Henderson /* if signal_pending is non-zero, don't do the call */ 72bbf15aafSRichard Henderson ldr r12, [r8] /* signal_pending */ 73bbf15aafSRichard Henderson tst r12, r12 74bbf15aafSRichard Henderson bne 2f 75bbf15aafSRichard Henderson swi 0 76bbf15aafSRichard Hendersonsafe_syscall_end: 77*5bfd125eSRichard Henderson 78bbf15aafSRichard Henderson /* code path for having successfully executed the syscall */ 79*5bfd125eSRichard Henderson#if defined(__linux__) 80*5bfd125eSRichard Henderson /* Linux kernel returns (small) negative errno. */ 81bbf15aafSRichard Henderson cmp r0, #-4096 82bbf15aafSRichard Henderson neghi r0, r0 83bbf15aafSRichard Henderson bhi 1f 84*5bfd125eSRichard Henderson#elif defined(__FreeBSD__) 85*5bfd125eSRichard Henderson /* FreeBSD kernel returns positive errno and C bit set. */ 86*5bfd125eSRichard Henderson bcs 1f 87*5bfd125eSRichard Henderson#else 88*5bfd125eSRichard Henderson#error "unsupported os" 89*5bfd125eSRichard Henderson#endif 90bbf15aafSRichard Henderson pop { r4, r5, r6, r7, r8, pc } 91bbf15aafSRichard Henderson 92bbf15aafSRichard Henderson /* code path when we didn't execute the syscall */ 93bbf15aafSRichard Henderson2: mov r0, #QEMU_ERESTARTSYS 94bbf15aafSRichard Henderson 95bbf15aafSRichard Henderson /* code path setting errno */ 96bbf15aafSRichard Henderson1: pop { r4, r5, r6, r7, r8, lr } 97bbf15aafSRichard Henderson .cfi_adjust_cfa_offset -24 98bbf15aafSRichard Henderson .cfi_restore r4 99bbf15aafSRichard Henderson .cfi_restore r5 100bbf15aafSRichard Henderson .cfi_restore r6 101bbf15aafSRichard Henderson .cfi_restore r7 102bbf15aafSRichard Henderson .cfi_restore r8 103bbf15aafSRichard Henderson .cfi_restore lr 104bbf15aafSRichard Henderson b safe_syscall_set_errno_tail 105bbf15aafSRichard Henderson 106bbf15aafSRichard Henderson .fnend 107bbf15aafSRichard Henderson .cfi_endproc 108bbf15aafSRichard Henderson .size safe_syscall_base, .-safe_syscall_base 109