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 53 struct futex_st0 { 54 int oparg; 55 int *oldval; 56 }; 57 58 static void 59 futex_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 67 int 68 futex_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 80 static void 81 futex_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 89 int 90 futex_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 102 static void 103 futex_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 115 int 116 futex_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 128 static void 129 futex_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 141 int 142 futex_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 154 static void 155 futex_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 167 int 168 futex_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