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