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