xref: /freebsd/sys/arm64/linux/linux_support.S (revision 96190b4fef3b4a0cc3ca0606b0c4e3e69a5e6717)
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2018 Turing Robotic Industries Inc.
5 * Copyright (C) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/elf_common.h>
30
31#include <machine/asm.h>
32#include <machine/param.h>
33#include <machine/vmparam.h>
34
35#include <sys/errno.h>
36
37#include "assym.inc"
38
39.macro check_user_access user_arg, limit, bad_addr_func
40	ldr	x7, =(\limit)
41	cmp	x\user_arg, x7
42	b.cs	\bad_addr_func
43.endm
44
45futex_fault:
46	SET_FAULT_HANDLER(xzr, x1)
47	EXIT_USER_ACCESS_CHECK(w0, x1)
48futex_fault_nopcb:
49	mov	x0, #EFAULT
50	ret
51
52#define	LINUX_FUTEX_MAX_LOOPS	128
53
54/*
55 * int oparg, uint32_t *uaddr, int *oldval
56 *
57 * Return 0 on success, errno on failure,
58 * EAGAIN is returned if LL/SC operation fails.
59 *
60 * XXX. VM_MAXUSER_ADDRESS is not applicable here, should be replaced
61 * by something like LINUX_SHAREDPAGE.
62 */
63
64/* (int *)uaddr2 = oparg */
65ENTRY(futex_xchgl)
66	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
67	adr	x9, futex_fault		/* Load the fault handler */
68	SET_FAULT_HANDLER(x9, x4)	/* And set it */
69	ENTER_USER_ACCESS(w9, x4)
70	mov	w5, #LINUX_FUTEX_MAX_LOOPS
71	prfm	pstl1strm, [x1]
72	mov	w6, w0			/* Save oparg */
731:	ldxr	w4, [x1]		/* Load oldval from uaddr */
74	stlxr	w0, w6, [x1]		/* Store oparg to uaddr */
75	cbz	w0, 3f			/* Exit on success */
76	sub	w5, w5, w0		/* Dec loop counter, w0 is 1 */
77	cbnz	w5, 1b			/* Loop */
78	mov	x0, #EAGAIN		/* Store of newval failed */
793:	dmb	ish
80	EXIT_USER_ACCESS(w9)
81	SET_FAULT_HANDLER(xzr, x9)	/* Reset the fault handler */
82	str w4, [x2]			/* Store oldval */
83	ret
84END(futex_xchgl)
85
86/* (int *)uaddr2 += oparg */
87ENTRY(futex_addl)
88	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
89	adr	x9, futex_fault
90	SET_FAULT_HANDLER(x9, x4)
91	ENTER_USER_ACCESS(w9, x4)
92	mov	w5, #LINUX_FUTEX_MAX_LOOPS
93	prfm	pstl1strm, [x1]
94	mov	w6, w0
951:	ldxr	w4, [x1]
96	add	w3, w4, w6		/* oldval + oparg */
97	stlxr	w0, w3, [x1]
98	cbz	w0, 3f
99	sub	w5, w5, w0
100	cbnz	w5, 1b
101	mov	x0, #EAGAIN
1023:	dmb	ish
103	EXIT_USER_ACCESS(w9)
104	SET_FAULT_HANDLER(xzr, x9)
105	str w4, [x2]
106	ret
107END(futex_addl)
108
109/* (int *)uaddr2 |= oparg */
110ENTRY(futex_orl)
111	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
112	adr	x9, futex_fault
113	SET_FAULT_HANDLER(x9, x4)
114	ENTER_USER_ACCESS(w9, x4)
115	mov	w5, #LINUX_FUTEX_MAX_LOOPS
116	prfm	pstl1strm, [x1]
117	mov	w6, w0
1181:	ldxr	w4, [x1]
119	orr	w3, w4, w6		/* oldavl |= oparg */
120	stlxr	w0, w3, [x1]
121	cbz	w0, 3f
122	sub	w5, w5, w0
123	cbnz	w5, 1b
124	mov	x0, #EAGAIN
1253:	dmb	ish
126	EXIT_USER_ACCESS(w9)
127	SET_FAULT_HANDLER(xzr, x9)
128	str w4, [x2]
129	ret
130END(futex_orl)
131
132/* (int *)uaddr2 &= oparg */
133ENTRY(futex_andl)
134	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
135	adr	x9, futex_fault
136	SET_FAULT_HANDLER(x9, x4)
137	ENTER_USER_ACCESS(w9, x4)
138	mov	w5, #LINUX_FUTEX_MAX_LOOPS
139	prfm	pstl1strm, [x1]
140	mov	w6, w0
1411:	ldxr	w4, [x1]
142	and	w3, w4, w6		/* oldval &= oparg */
143	stlxr	w0, w3, [x1]
144	cbz	w0, 3f
145	sub	w5, w5, w0
146	cbnz	w5, 1b
147	mov	x0, #EAGAIN
1483:	dmb	ish
149	EXIT_USER_ACCESS(w9)
150	SET_FAULT_HANDLER(xzr, x9)
151	str w4, [x2]
152	ret
153END(futex_andl)
154
155/* (int *)uaddr2 ^= oparg */
156ENTRY(futex_xorl)
157	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
158	adr	x9, futex_fault
159	SET_FAULT_HANDLER(x9, x4)
160	ENTER_USER_ACCESS(w9, x4)
161	mov	w5, #LINUX_FUTEX_MAX_LOOPS
162	prfm	pstl1strm, [x1]
163	mov	w6, w0
1641:	ldxr	w4, [x1]
165	eor	w3, w4, w6		/* oldval ^= oparg */
166	stlxr	w0, w3, [x1]
167	cbz	w0, 3f
168	sub	w5, w5, w0
169	cbnz	w5, 1b
170	mov	x0, #EAGAIN
1713:	dmb	ish
172	EXIT_USER_ACCESS(w9)
173	SET_FAULT_HANDLER(xzr, x9)
174	str w4, [x2]
175	ret
176END(futex_xorl)
177
178GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL)
179