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