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/param.h> 32 #include <sys/imgact.h> 33 #include <sys/lock.h> 34 #include <sys/sx.h> 35 36 #include <vm/vm.h> 37 #include <vm/vm_param.h> 38 #include <vm/vm_extern.h> 39 #include <vm/pmap.h> 40 41 #include <machine/atomic.h> 42 #include <machine/md_var.h> 43 44 #include <i386/linux/linux.h> 45 #include <compat/linux/linux_emul.h> 46 #include <compat/linux/linux_futex.h> 47 48 struct futex_st0 { 49 int oparg; 50 int *oldval; 51 }; 52 53 static void 54 futex_xchgl_slow0(vm_offset_t kva, void *arg) 55 { 56 struct futex_st0 *st; 57 58 st = arg; 59 *st->oldval = atomic_swap_int((int *)kva, st->oparg); 60 } 61 62 int 63 futex_xchgl(int oparg, uint32_t *uaddr, int *oldval) 64 { 65 struct futex_st0 st; 66 67 st.oparg = oparg; 68 st.oldval = oldval; 69 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 70 futex_xchgl_slow0, &st) != 0) 71 return (EFAULT); 72 return (0); 73 } 74 75 static void 76 futex_addl_slow0(vm_offset_t kva, void *arg) 77 { 78 struct futex_st0 *st; 79 80 st = arg; 81 *st->oldval = atomic_fetchadd_int((int *)kva, st->oparg); 82 } 83 84 int 85 futex_addl(int oparg, uint32_t *uaddr, int *oldval) 86 { 87 struct futex_st0 st; 88 89 st.oparg = oparg; 90 st.oldval = oldval; 91 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 92 futex_addl_slow0, &st) != 0) 93 return (EFAULT); 94 return (0); 95 } 96 97 static void 98 futex_orl_slow0(vm_offset_t kva, void *arg) 99 { 100 struct futex_st0 *st; 101 int old; 102 103 st = arg; 104 old = *(int *)kva; 105 while (!atomic_fcmpset_int((int *)kva, &old, old | st->oparg)) 106 ; 107 *st->oldval = old; 108 } 109 110 int 111 futex_orl(int oparg, uint32_t *uaddr, int *oldval) 112 { 113 struct futex_st0 st; 114 115 st.oparg = oparg; 116 st.oldval = oldval; 117 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 118 futex_orl_slow0, &st) != 0) 119 return (EFAULT); 120 return (0); 121 } 122 123 static void 124 futex_andl_slow0(vm_offset_t kva, void *arg) 125 { 126 struct futex_st0 *st; 127 int old; 128 129 st = arg; 130 old = *(int *)kva; 131 while (!atomic_fcmpset_int((int *)kva, &old, old & st->oparg)) 132 ; 133 *st->oldval = old; 134 } 135 136 int 137 futex_andl(int oparg, uint32_t *uaddr, int *oldval) 138 { 139 struct futex_st0 st; 140 141 st.oparg = oparg; 142 st.oldval = oldval; 143 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 144 futex_andl_slow0, &st) != 0) 145 return (EFAULT); 146 return (0); 147 } 148 149 static void 150 futex_xorl_slow0(vm_offset_t kva, void *arg) 151 { 152 struct futex_st0 *st; 153 int old; 154 155 st = arg; 156 old = *(int *)kva; 157 while (!atomic_fcmpset_int((int *)kva, &old, old ^ st->oparg)) 158 ; 159 *st->oldval = old; 160 } 161 162 int 163 futex_xorl(int oparg, uint32_t *uaddr, int *oldval) 164 { 165 struct futex_st0 st; 166 167 st.oparg = oparg; 168 st.oldval = oldval; 169 if (cp_slow0((vm_offset_t)uaddr, sizeof(uint32_t), true, 170 futex_xorl_slow0, &st) != 0) 171 return (EFAULT); 172 return (0); 173 } 174