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
13	.global safe_syscall_base
14	.global safe_syscall_start
15	.global safe_syscall_end
16	.type	safe_syscall_base, %function
17
18	.cfi_sections	.debug_frame
19
20	.text
21	.syntax unified
22	.arm
23	.align 2
24
25	/* This is the entry point for making a system call. The calling
26	 * convention here is that of a C varargs function with the
27	 * first argument an 'int *' to the signal_pending flag, the
28	 * second one the system call number (as a 'long'), and all further
29	 * arguments being syscall arguments (also 'long').
30	 * We return a long which is the syscall's return value, which
31	 * may be negative-errno on failure. Conversion to the
32	 * -1-and-errno-set convention is done by the calling wrapper.
33	 */
34safe_syscall_base:
35	.fnstart
36	.cfi_startproc
37	mov	r12, sp			/* save entry stack */
38	push	{ r4, r5, r6, r7, r8, lr }
39	.save	{ r4, r5, r6, r7, r8, lr }
40	.cfi_adjust_cfa_offset 24
41	.cfi_rel_offset r4, 0
42	.cfi_rel_offset r5, 4
43	.cfi_rel_offset r6, 8
44	.cfi_rel_offset r7, 12
45	.cfi_rel_offset r8, 16
46	.cfi_rel_offset lr, 20
47
48	/* The syscall calling convention isn't the same as the C one:
49	 * we enter with r0 == *signal_pending
50	 *               r1 == syscall number
51	 *               r2, r3, [sp+0] ... [sp+12] == syscall arguments
52	 *               and return the result in r0
53	 * and the syscall instruction needs
54	 *               r7 == syscall number
55	 *               r0 ... r6 == syscall arguments
56	 *               and returns the result in r0
57	 * Shuffle everything around appropriately.
58	 * Note the 16 bytes that we pushed to save registers.
59	 */
60	mov	r8, r0			/* copy signal_pending */
61	mov	r7, r1			/* syscall number */
62	mov	r0, r2			/* syscall args */
63	mov	r1, r3
64	ldm	r12, { r2, r3, r4, r5, r6 }
65
66	/* This next sequence of code works in conjunction with the
67	 * rewind_if_safe_syscall_function(). If a signal is taken
68	 * and the interrupted PC is anywhere between 'safe_syscall_start'
69	 * and 'safe_syscall_end' then we rewind it to 'safe_syscall_start'.
70	 * The code sequence must therefore be able to cope with this, and
71	 * the syscall instruction must be the final one in the sequence.
72	 */
73safe_syscall_start:
74	/* if signal_pending is non-zero, don't do the call */
75	ldr	r12, [r8]		/* signal_pending */
76	tst	r12, r12
77	bne	1f
78	swi	0
79safe_syscall_end:
80	/* code path for having successfully executed the syscall */
81	pop	{ r4, r5, r6, r7, r8, pc }
82
831:
84	/* code path when we didn't execute the syscall */
85	ldr	r0, =-TARGET_ERESTARTSYS
86	pop	{ r4, r5, r6, r7, r8, pc }
87	.fnend
88	.cfi_endproc
89
90	.size	safe_syscall_base, .-safe_syscall_base
91