1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2018 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 8 * under sponsorship from the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD$"); 34 35#include "opt_compat.h" 36 37#include <sys/param.h> 38#include <sys/systm.h> 39#include <sys/imgact.h> 40#include <sys/lock.h> 41#include <sys/sx.h> 42#include <vm/vm.h> 43#include <vm/vm_param.h> 44#include <vm/vm_extern.h> 45#include <vm/pmap.h> 46 47#include <machine/atomic.h> 48#include <machine/md_var.h> 49 50#include <compat/linux/linux_emul.h> 51#include <compat/linux/linux_futex.h> 52 53struct futex_st0 { 54 int oparg; 55 int *oldval; 56}; 57 58static void 59futex_xchgl_slow0(vm_offset_t kva, void *arg) 60{ 61 struct futex_st0 *st; 62 63 st = arg; 64 *st->oldval = atomic_swap_int((int *)kva, st->oparg); 65} 66 67int 68futex_xchgl(int oparg, uint32_t *uaddr, int *oldval) 69{ 70 struct futex_st0 st; 71 72 st.oparg = oparg; 73 st.oldval = oldval; 74 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 75 futex_xchgl_slow0, &st) != 0) 76 return (-EFAULT); 77 return (0); 78} 79 80static void 81futex_addl_slow0(vm_offset_t kva, void *arg) 82{ 83 struct futex_st0 *st; 84 85 st = arg; 86 *st->oldval = atomic_fetchadd_int((int *)kva, st->oparg); 87} 88 89int 90futex_addl(int oparg, uint32_t *uaddr, int *oldval) 91{ 92 struct futex_st0 st; 93 94 st.oparg = oparg; 95 st.oldval = oldval; 96 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 97 futex_addl_slow0, &st) != 0) 98 return (-EFAULT); 99 return (0); 100} 101 102static void 103futex_orl_slow0(vm_offset_t kva, void *arg) 104{ 105 struct futex_st0 *st; 106 int old; 107 108 st = arg; 109 old = *(int *)kva; 110 while (!atomic_fcmpset_int((int *)kva, &old, old | st->oparg)) 111 ; 112 *st->oldval = old; 113} 114 115int 116futex_orl(int oparg, uint32_t *uaddr, int *oldval) 117{ 118 struct futex_st0 st; 119 120 st.oparg = oparg; 121 st.oldval = oldval; 122 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 123 futex_orl_slow0, &st) != 0) 124 return (-EFAULT); 125 return (0); 126} 127 128static void 129futex_andl_slow0(vm_offset_t kva, void *arg) 130{ 131 struct futex_st0 *st; 132 int old; 133 134 st = arg; 135 old = *(int *)kva; 136 while (!atomic_fcmpset_int((int *)kva, &old, old & st->oparg)) 137 ; 138 *st->oldval = old; 139} 140 141int 142futex_andl(int oparg, uint32_t *uaddr, int *oldval) 143{ 144 struct futex_st0 st; 145 146 st.oparg = oparg; 147 st.oldval = oldval; 148 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 149 futex_andl_slow0, &st) != 0) 150 return (-EFAULT); 151 return (0); 152} 153 154static void 155futex_xorl_slow0(vm_offset_t kva, void *arg) 156{ 157 struct futex_st0 *st; 158 int old; 159 160 st = arg; 161 old = *(int *)kva; 162 while (!atomic_fcmpset_int((int *)kva, &old, old ^ st->oparg)) 163 ; 164 *st->oldval = old; 165} 166 167int 168futex_xorl(int oparg, uint32_t *uaddr, int *oldval) 169{ 170 struct futex_st0 st; 171 172 st.oparg = oparg; 173 st.oldval = oldval; 174 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 175 futex_xorl_slow0, &st) != 0) 176 return (-EFAULT); 177 return (0); 178} 179