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
futex_xchgl_slow0(vm_offset_t kva,void * arg)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
futex_xchgl(int oparg,uint32_t * uaddr,int * oldval)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
futex_addl_slow0(vm_offset_t kva,void * arg)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
futex_addl(int oparg,uint32_t * uaddr,int * oldval)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
futex_orl_slow0(vm_offset_t kva,void * arg)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
futex_orl(int oparg,uint32_t * uaddr,int * oldval)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
futex_andl_slow0(vm_offset_t kva,void * arg)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
futex_andl(int oparg,uint32_t * uaddr,int * oldval)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
futex_xorl_slow0(vm_offset_t kva,void * arg)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
futex_xorl(int oparg,uint32_t * uaddr,int * oldval)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