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