xref: /src/sys/arm64/linux/linux_support.S (revision bed65d85c631c3a8e60a81a15a5a745c8ef92fbe)
11fbaf06eSEd Maste/*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31fbaf06eSEd Maste *
41fbaf06eSEd Maste * Copyright (C) 2018 Turing Robotic Industries Inc.
53bae1cd6SDmitry Chagin * Copyright (C) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
61fbaf06eSEd Maste *
71fbaf06eSEd Maste * Redistribution and use in source and binary forms, with or without
81fbaf06eSEd Maste * modification, are permitted provided that the following conditions
91fbaf06eSEd Maste * are met:
101fbaf06eSEd Maste * 1. Redistributions of source code must retain the above copyright
111fbaf06eSEd Maste *    notice, this list of conditions and the following disclaimer.
121fbaf06eSEd Maste * 2. Redistributions in binary form must reproduce the above copyright
131fbaf06eSEd Maste *    notice, this list of conditions and the following disclaimer in the
141fbaf06eSEd Maste *    documentation and/or other materials provided with the distribution.
151fbaf06eSEd Maste *
161fbaf06eSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
171fbaf06eSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
181fbaf06eSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
191fbaf06eSEd Maste * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
201fbaf06eSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
211fbaf06eSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
221fbaf06eSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
231fbaf06eSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
241fbaf06eSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
251fbaf06eSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
261fbaf06eSEd Maste * SUCH DAMAGE.
271fbaf06eSEd Maste */
281fbaf06eSEd Maste
29*bed65d85SAndrew Turner#include <sys/elf_common.h>
30*bed65d85SAndrew Turner
311fbaf06eSEd Maste#include <machine/asm.h>
323bae1cd6SDmitry Chagin#include <machine/param.h>
333bae1cd6SDmitry Chagin#include <machine/vmparam.h>
343bae1cd6SDmitry Chagin
353bae1cd6SDmitry Chagin#include <sys/errno.h>
361fbaf06eSEd Maste
371fbaf06eSEd Maste#include "assym.inc"
381fbaf06eSEd Maste
393bae1cd6SDmitry Chagin.macro check_user_access user_arg, limit, bad_addr_func
403bae1cd6SDmitry Chagin	ldr	x7, =(\limit)
413bae1cd6SDmitry Chagin	cmp	x\user_arg, x7
423bae1cd6SDmitry Chagin	b.cs	\bad_addr_func
433bae1cd6SDmitry Chagin.endm
443bae1cd6SDmitry Chagin
453bae1cd6SDmitry Chaginfutex_fault:
463bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(xzr, x1)
473bae1cd6SDmitry Chagin	EXIT_USER_ACCESS_CHECK(w0, x1)
483bae1cd6SDmitry Chaginfutex_fault_nopcb:
493bae1cd6SDmitry Chagin	mov	x0, #EFAULT
503bae1cd6SDmitry Chagin	ret
513bae1cd6SDmitry Chagin
523bae1cd6SDmitry Chagin#define	LINUX_FUTEX_MAX_LOOPS	128
533bae1cd6SDmitry Chagin
541fbaf06eSEd Maste/*
553bae1cd6SDmitry Chagin * int oparg, uint32_t *uaddr, int *oldval
563bae1cd6SDmitry Chagin *
573bae1cd6SDmitry Chagin * Return 0 on success, errno on failure,
583bae1cd6SDmitry Chagin * EAGAIN is returned if LL/SC operation fails.
593bae1cd6SDmitry Chagin *
603bae1cd6SDmitry Chagin * XXX. VM_MAXUSER_ADDRESS is not applicable here, should be replaced
613bae1cd6SDmitry Chagin * by something like LINUX_SHAREDPAGE.
621fbaf06eSEd Maste */
631fbaf06eSEd Maste
643bae1cd6SDmitry Chagin/* (int *)uaddr2 = oparg */
651fbaf06eSEd MasteENTRY(futex_xchgl)
663bae1cd6SDmitry Chagin	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
673bae1cd6SDmitry Chagin	adr	x9, futex_fault		/* Load the fault handler */
683bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(x9, x4)	/* And set it */
693bae1cd6SDmitry Chagin	ENTER_USER_ACCESS(w9, x4)
703bae1cd6SDmitry Chagin	mov	w5, #LINUX_FUTEX_MAX_LOOPS
713bae1cd6SDmitry Chagin	prfm	pstl1strm, [x1]
723bae1cd6SDmitry Chagin	mov	w6, w0			/* Save oparg */
733bae1cd6SDmitry Chagin1:	ldxr	w4, [x1]		/* Load oldval from uaddr */
743bae1cd6SDmitry Chagin	stlxr	w0, w6, [x1]		/* Store oparg to uaddr */
753bae1cd6SDmitry Chagin	cbz	w0, 3f			/* Exit on success */
763bae1cd6SDmitry Chagin	sub	w5, w5, w0		/* Dec loop counter, w0 is 1 */
773bae1cd6SDmitry Chagin	cbnz	w5, 1b			/* Loop */
783bae1cd6SDmitry Chagin	mov	x0, #EAGAIN		/* Store of newval failed */
793bae1cd6SDmitry Chagin3:	dmb	ish
803bae1cd6SDmitry Chagin	EXIT_USER_ACCESS(w9)
813bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(xzr, x9)	/* Reset the fault handler */
823bae1cd6SDmitry Chagin	str w4, [x2]			/* Store oldval */
831fbaf06eSEd Maste	ret
8478599c32SConrad MeyerEND(futex_xchgl)
851fbaf06eSEd Maste
863bae1cd6SDmitry Chagin/* (int *)uaddr2 += oparg */
871fbaf06eSEd MasteENTRY(futex_addl)
883bae1cd6SDmitry Chagin	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
893bae1cd6SDmitry Chagin	adr	x9, futex_fault
903bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(x9, x4)
913bae1cd6SDmitry Chagin	ENTER_USER_ACCESS(w9, x4)
923bae1cd6SDmitry Chagin	mov	w5, #LINUX_FUTEX_MAX_LOOPS
933bae1cd6SDmitry Chagin	prfm	pstl1strm, [x1]
943bae1cd6SDmitry Chagin	mov	w6, w0
953bae1cd6SDmitry Chagin1:	ldxr	w4, [x1]
963bae1cd6SDmitry Chagin	add	w3, w4, w6		/* oldval + oparg */
973bae1cd6SDmitry Chagin	stlxr	w0, w3, [x1]
983bae1cd6SDmitry Chagin	cbz	w0, 3f
993bae1cd6SDmitry Chagin	sub	w5, w5, w0
1003bae1cd6SDmitry Chagin	cbnz	w5, 1b
1013bae1cd6SDmitry Chagin	mov	x0, #EAGAIN
1023bae1cd6SDmitry Chagin3:	dmb	ish
1033bae1cd6SDmitry Chagin	EXIT_USER_ACCESS(w9)
1043bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(xzr, x9)
1053bae1cd6SDmitry Chagin	str w4, [x2]
1061fbaf06eSEd Maste	ret
10778599c32SConrad MeyerEND(futex_addl)
1081fbaf06eSEd Maste
1093bae1cd6SDmitry Chagin/* (int *)uaddr2 |= oparg */
1101fbaf06eSEd MasteENTRY(futex_orl)
1113bae1cd6SDmitry Chagin	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
1123bae1cd6SDmitry Chagin	adr	x9, futex_fault
1133bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(x9, x4)
1143bae1cd6SDmitry Chagin	ENTER_USER_ACCESS(w9, x4)
1153bae1cd6SDmitry Chagin	mov	w5, #LINUX_FUTEX_MAX_LOOPS
1163bae1cd6SDmitry Chagin	prfm	pstl1strm, [x1]
1173bae1cd6SDmitry Chagin	mov	w6, w0
1183bae1cd6SDmitry Chagin1:	ldxr	w4, [x1]
1193bae1cd6SDmitry Chagin	orr	w3, w4, w6		/* oldavl |= oparg */
1203bae1cd6SDmitry Chagin	stlxr	w0, w3, [x1]
1213bae1cd6SDmitry Chagin	cbz	w0, 3f
1223bae1cd6SDmitry Chagin	sub	w5, w5, w0
1233bae1cd6SDmitry Chagin	cbnz	w5, 1b
1243bae1cd6SDmitry Chagin	mov	x0, #EAGAIN
1253bae1cd6SDmitry Chagin3:	dmb	ish
1263bae1cd6SDmitry Chagin	EXIT_USER_ACCESS(w9)
1273bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(xzr, x9)
1283bae1cd6SDmitry Chagin	str w4, [x2]
1291fbaf06eSEd Maste	ret
13078599c32SConrad MeyerEND(futex_orl)
1311fbaf06eSEd Maste
1323bae1cd6SDmitry Chagin/* (int *)uaddr2 &= oparg */
1331fbaf06eSEd MasteENTRY(futex_andl)
1343bae1cd6SDmitry Chagin	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
1353bae1cd6SDmitry Chagin	adr	x9, futex_fault
1363bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(x9, x4)
1373bae1cd6SDmitry Chagin	ENTER_USER_ACCESS(w9, x4)
1383bae1cd6SDmitry Chagin	mov	w5, #LINUX_FUTEX_MAX_LOOPS
1393bae1cd6SDmitry Chagin	prfm	pstl1strm, [x1]
1403bae1cd6SDmitry Chagin	mov	w6, w0
1413bae1cd6SDmitry Chagin1:	ldxr	w4, [x1]
1423bae1cd6SDmitry Chagin	and	w3, w4, w6		/* oldval &= oparg */
1433bae1cd6SDmitry Chagin	stlxr	w0, w3, [x1]
1443bae1cd6SDmitry Chagin	cbz	w0, 3f
1453bae1cd6SDmitry Chagin	sub	w5, w5, w0
1463bae1cd6SDmitry Chagin	cbnz	w5, 1b
1473bae1cd6SDmitry Chagin	mov	x0, #EAGAIN
1483bae1cd6SDmitry Chagin3:	dmb	ish
1493bae1cd6SDmitry Chagin	EXIT_USER_ACCESS(w9)
1503bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(xzr, x9)
1513bae1cd6SDmitry Chagin	str w4, [x2]
1521fbaf06eSEd Maste	ret
15378599c32SConrad MeyerEND(futex_andl)
1541fbaf06eSEd Maste
1553bae1cd6SDmitry Chagin/* (int *)uaddr2 ^= oparg */
1561fbaf06eSEd MasteENTRY(futex_xorl)
1573bae1cd6SDmitry Chagin	check_user_access 1, (VM_MAXUSER_ADDRESS-3), futex_fault_nopcb
1583bae1cd6SDmitry Chagin	adr	x9, futex_fault
1593bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(x9, x4)
1603bae1cd6SDmitry Chagin	ENTER_USER_ACCESS(w9, x4)
1613bae1cd6SDmitry Chagin	mov	w5, #LINUX_FUTEX_MAX_LOOPS
1623bae1cd6SDmitry Chagin	prfm	pstl1strm, [x1]
1633bae1cd6SDmitry Chagin	mov	w6, w0
1643bae1cd6SDmitry Chagin1:	ldxr	w4, [x1]
1653bae1cd6SDmitry Chagin	eor	w3, w4, w6		/* oldval ^= oparg */
1663bae1cd6SDmitry Chagin	stlxr	w0, w3, [x1]
1673bae1cd6SDmitry Chagin	cbz	w0, 3f
1683bae1cd6SDmitry Chagin	sub	w5, w5, w0
1693bae1cd6SDmitry Chagin	cbnz	w5, 1b
1703bae1cd6SDmitry Chagin	mov	x0, #EAGAIN
1713bae1cd6SDmitry Chagin3:	dmb	ish
1723bae1cd6SDmitry Chagin	EXIT_USER_ACCESS(w9)
1733bae1cd6SDmitry Chagin	SET_FAULT_HANDLER(xzr, x9)
1743bae1cd6SDmitry Chagin	str w4, [x2]
1751fbaf06eSEd Maste	ret
17678599c32SConrad MeyerEND(futex_xorl)
177*bed65d85SAndrew Turner
178*bed65d85SAndrew TurnerGNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL)
179