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