]>
Commit | Line | Data |
---|---|---|
31f875f2 RH |
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 | */ | |
12 | ||
b9d2af3c RH |
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 | |
31f875f2 | 19 | |
b9d2af3c RH |
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'). | |
b9d2af3c | 25 | */ |
31f875f2 | 26 | safe_syscall_base: |
b9d2af3c RH |
27 | .cfi_startproc |
28 | /* The syscall calling convention isn't the same as the | |
29 | * C one: | |
a3310c03 | 30 | * we enter with x0 == &signal_pending |
b9d2af3c RH |
31 | * x1 == syscall number |
32 | * x2 ... x7, (stack) == syscall arguments | |
33 | * and return the result in x0 | |
34 | * and the syscall instruction needs | |
35 | * x8 == syscall number | |
36 | * x0 ... x6 == syscall arguments | |
37 | * and returns the result in x0 | |
38 | * Shuffle everything around appropriately. | |
39 | */ | |
40 | mov x9, x0 /* signal_pending pointer */ | |
41 | mov x8, x1 /* syscall number */ | |
42 | mov x0, x2 /* syscall arguments */ | |
43 | mov x1, x3 | |
44 | mov x2, x4 | |
45 | mov x3, x5 | |
46 | mov x4, x6 | |
47 | mov x5, x7 | |
48 | ldr x6, [sp] | |
31f875f2 | 49 | |
b9d2af3c RH |
50 | /* This next sequence of code works in conjunction with the |
51 | * rewind_if_safe_syscall_function(). If a signal is taken | |
52 | * and the interrupted PC is anywhere between 'safe_syscall_start' | |
53 | * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'. | |
54 | * The code sequence must therefore be able to cope with this, and | |
55 | * the syscall instruction must be the final one in the sequence. | |
56 | */ | |
31f875f2 | 57 | safe_syscall_start: |
b9d2af3c RH |
58 | /* if signal_pending is non-zero, don't do the call */ |
59 | ldr w10, [x9] | |
a3310c03 | 60 | cbnz w10, 2f |
b9d2af3c | 61 | svc 0x0 |
31f875f2 | 62 | safe_syscall_end: |
b9d2af3c | 63 | /* code path for having successfully executed the syscall */ |
a3310c03 RH |
64 | cmp x0, #-4096 |
65 | b.hi 0f | |
b9d2af3c | 66 | ret |
31f875f2 | 67 | |
a3310c03 RH |
68 | /* code path setting errno */ |
69 | 0: neg w0, w0 | |
70 | b safe_syscall_set_errno_tail | |
71 | ||
b9d2af3c | 72 | /* code path when we didn't execute the syscall */ |
af254a27 | 73 | 2: mov w0, #QEMU_ERESTARTSYS |
a3310c03 | 74 | b safe_syscall_set_errno_tail |
a3310c03 | 75 | .cfi_endproc |
b9d2af3c | 76 | .size safe_syscall_base, .-safe_syscall_base |