Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
[qemu/ar7.git] / linux-user / host / ppc64 / safe-syscall.inc.S
blob875133173bb699870db75144b5d1541c570f3863
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 linux-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  */
13         .global safe_syscall_base
14         .global safe_syscall_start
15         .global safe_syscall_end
16         .type   safe_syscall_base, @function
18         .text
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          * We return a long which is the syscall's return value, which
26          * may be negative-errno on failure. Conversion to the
27          * -1-and-errno-set convention is done by the calling wrapper.
28          */
29 #if _CALL_ELF == 2
30 safe_syscall_base:
31         .cfi_startproc
32         .localentry safe_syscall_base,0
33 #else
34         .section ".opd","aw"
35         .align  3
36 safe_syscall_base:
37         .quad   .L.safe_syscall_base,.TOC.@tocbase,0
38         .previous
39 .L.safe_syscall_base:
40         .cfi_startproc
41 #endif
42         /* We enter with r3 == *signal_pending
43          *               r4 == syscall number
44          *               r5 ... r10 == syscall arguments
45          *               and return the result in r3
46          * and the syscall instruction needs
47          *               r0 == syscall number
48          *               r3 ... r8 == syscall arguments
49          *               and returns the result in r3
50          * Shuffle everything around appropriately.
51          */
52         std     14, 16(1) /* Preserve r14 in SP+16 */
53         .cfi_offset 14, 16
54         mr      14, 3   /* signal_pending */
55         mr      0, 4    /* syscall number */
56         mr      3, 5    /* syscall arguments */
57         mr      4, 6
58         mr      5, 7
59         mr      6, 8
60         mr      7, 9
61         mr      8, 10
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          */
70 safe_syscall_start:
71         /* if signal_pending is non-zero, don't do the call */
72         lwz     12, 0(14)
73         cmpwi   0, 12, 0
74         bne-    0f
75         sc
76 safe_syscall_end:
77         /* code path when we did execute the syscall */
78         ld 14, 16(1) /* restore r14 to its original value */
79         bnslr+
81         /* syscall failed; return negative errno */
82         neg     3, 3
83         blr
85         /* code path when we didn't execute the syscall */
86 0:      addi    3, 0, -TARGET_ERESTARTSYS
87         ld 14, 16(1) /* restore r14 to its original value */
88         blr
89         .cfi_endproc
91 #if _CALL_ELF == 2
92         .size   safe_syscall_base, .-safe_syscall_base
93 #else
94         .size   safe_syscall_base, .-.L.safe_syscall_base
95         .size   .L.safe_syscall_base, .-.L.safe_syscall_base
96 #endif