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 18 /* This is the entry point for making a system call. The calling 19 * convention here is that of a C varargs function with the 20 * first argument an 'int *' to the signal_pending flag, the 21 * second one the system call number (as a 'long'), and all further 22 * arguments being syscall arguments (also 'long'). 23 */ 24safe_syscall_base: 25 .cfi_startproc 26 stmg %r6,%r15,48(%r15) /* save all call-saved registers */ 27 .cfi_offset %r15,-40 28 .cfi_offset %r14,-48 29 .cfi_offset %r13,-56 30 .cfi_offset %r12,-64 31 .cfi_offset %r11,-72 32 .cfi_offset %r10,-80 33 .cfi_offset %r9,-88 34 .cfi_offset %r8,-96 35 .cfi_offset %r7,-104 36 .cfi_offset %r6,-112 37 lgr %r1,%r15 38 lg %r0,8(%r15) /* load eos */ 39 aghi %r15,-160 40 .cfi_adjust_cfa_offset 160 41 stg %r1,0(%r15) /* store back chain */ 42 stg %r0,8(%r15) /* store eos */ 43 44 /* 45 * The syscall calling convention isn't the same as the C one: 46 * we enter with r2 == &signal_pending 47 * r3 == syscall number 48 * r4, r5, r6, (stack) == syscall arguments 49 * and return the result in r2 50 * and the syscall instruction needs 51 * r1 == syscall number 52 * r2 ... r7 == syscall arguments 53 * and returns the result in r2 54 * Shuffle everything around appropriately. 55 */ 56 lgr %r8,%r2 /* signal_pending pointer */ 57 lgr %r1,%r3 /* syscall number */ 58 lgr %r2,%r4 /* syscall args */ 59 lgr %r3,%r5 60 lgr %r4,%r6 61 lmg %r5,%r7,320(%r15) 62 63 /* This next sequence of code works in conjunction with the 64 * rewind_if_safe_syscall_function(). If a signal is taken 65 * and the interrupted PC is anywhere between 'safe_syscall_start' 66 * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. 67 * The code sequence must therefore be able to cope with this, and 68 * the syscall instruction must be the final one in the sequence. 69 */ 70safe_syscall_start: 71 /* if signal_pending is non-zero, don't do the call */ 72 icm %r0,15,0(%r8) 73 jne 2f 74 svc 0 75safe_syscall_end: 76 77 /* code path for having successfully executed the syscall */ 78 lg %r15,0(%r15) /* load back chain */ 79 .cfi_remember_state 80 .cfi_adjust_cfa_offset -160 81 lmg %r6,%r15,48(%r15) /* load saved registers */ 82 83 lghi %r0, -4095 /* check for syscall error */ 84 clgr %r2, %r0 85 blr %r14 /* return on success */ 86 lcr %r2, %r2 /* create positive errno */ 87 jg safe_syscall_set_errno_tail 88 .cfi_restore_state 89 90 /* code path when we didn't execute the syscall */ 912: lg %r15,0(%r15) /* load back chain */ 92 .cfi_adjust_cfa_offset -160 93 lmg %r6,%r15,48(%r15) /* load saved registers */ 94 lghi %r2, QEMU_ERESTARTSYS 95 jg safe_syscall_set_errno_tail 96 97 .cfi_endproc 98 .size safe_syscall_base, .-safe_syscall_base 99