xref: /freebsd/sys/i386/linux/linux_copyout.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
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