export/vhost-user-blk: Fix consecutive drains
[qemu/kevin.git] / common-user / host / riscv / safe-syscall.inc.S
blobdfe83c300ebeafb753cc027f4333bc550cef2da6
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) 2018 Linaro, 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  */
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
20         /*
21          * This is the entry point for making a system call. The calling
22          * convention here is that of a C varargs function with the
23          * first argument an 'int *' to the signal_pending flag, the
24          * second one the system call number (as a 'long'), and all further
25          * arguments being syscall arguments (also 'long').
26          */
27 safe_syscall_base:
28         .cfi_startproc
29         /*
30          * The syscall calling convention is nearly the same as C:
31          * we enter with a0 == &signal_pending
32          *               a1 == syscall number
33          *               a2 ... a7 == syscall arguments
34          *               and return the result in a0
35          * and the syscall instruction needs
36          *               a7 == syscall number
37          *               a0 ... a5 == syscall arguments
38          *               and returns the result in a0
39          * Shuffle everything around appropriately.
40          */
41         mv      t0, a0          /* signal_pending pointer */
42         mv      t1, a1          /* syscall number */
43         mv      a0, a2          /* syscall arguments */
44         mv      a1, a3
45         mv      a2, a4
46         mv      a3, a5
47         mv      a4, a6
48         mv      a5, a7
49         mv      a7, t1
51         /*
52          * This next sequence of code works in conjunction with the
53          * rewind_if_safe_syscall_function(). If a signal is taken
54          * and the interrupted PC is anywhere between 'safe_syscall_start'
55          * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
56          * The code sequence must therefore be able to cope with this, and
57          * the syscall instruction must be the final one in the sequence.
58          */
59 safe_syscall_start:
60         /* If signal_pending is non-zero, don't do the call */
61         lw      t1, 0(t0)
62         bnez    t1, 2f
63         scall
64 safe_syscall_end:
65         /* code path for having successfully executed the syscall */
66         li      t2, -4096
67         bgtu    a0, t2, 0f
68         ret
70         /* code path setting errno */
71 0:      neg     a0, a0
72         j       safe_syscall_set_errno_tail
74         /* code path when we didn't execute the syscall */
75 2:      li      a0, QEMU_ERESTARTSYS
76         j       safe_syscall_set_errno_tail
78         .cfi_endproc
79         .size   safe_syscall_base, .-safe_syscall_base