xref: /freebsd/sys/powerpc/powerpc/copyinout.c (revision 7bd6fde3)
1 /*-
2  * Copyright (C) 2002 Benno Rice
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
20  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
21  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
23  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25 /*-
26  * Copyright (C) 1993 Wolfgang Solfrank.
27  * Copyright (C) 1993 TooLs GmbH.
28  * All rights reserved.
29  *
30  * Redistribution and use in source and binary forms, with or without
31  * modification, are permitted provided that the following conditions
32  * are met:
33  * 1. Redistributions of source code must retain the above copyright
34  *    notice, this list of conditions and the following disclaimer.
35  * 2. Redistributions in binary form must reproduce the above copyright
36  *    notice, this list of conditions and the following disclaimer in the
37  *    documentation and/or other materials provided with the distribution.
38  * 3. All advertising materials mentioning features or use of this software
39  *    must display the following acknowledgement:
40  *	This product includes software developed by TooLs GmbH.
41  * 4. The name of TooLs GmbH may not be used to endorse or promote products
42  *    derived from this software without specific prior written permission.
43  *
44  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
45  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
48  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
49  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
50  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
51  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
52  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
53  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
54  */
55 
56 #include <sys/cdefs.h>
57 __FBSDID("$FreeBSD$");
58 
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/proc.h>
62 
63 #include <vm/vm.h>
64 #include <vm/pmap.h>
65 #include <vm/vm_map.h>
66 
67 #include <machine/pcb.h>
68 #include <machine/sr.h>
69 
70 int	setfault(faultbuf);	/* defined in locore.S */
71 
72 /*
73  * Makes sure that the right segment of userspace is mapped in.
74  */
75 static __inline void
76 set_user_sr(register_t vsid)
77 {
78 
79 	isync();
80 	__asm __volatile ("mtsr %0,%1" :: "n"(USER_SR), "r"(vsid));
81 	isync();
82 }
83 
84 int
85 copyout(const void *kaddr, void *udaddr, size_t len)
86 {
87 	struct		thread *td;
88 	pmap_t		pm;
89 	faultbuf	env;
90 	const char	*kp;
91 	char		*up, *p;
92 	size_t		l;
93 
94 	td = PCPU_GET(curthread);
95 	pm = &td->td_proc->p_vmspace->vm_pmap;
96 
97 	if (setfault(env)) {
98 		td->td_pcb->pcb_onfault = NULL;
99 		return (EFAULT);
100 	}
101 
102 	kp = kaddr;
103 	up = udaddr;
104 
105 	while (len > 0) {
106 		p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
107 
108 		l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
109 		if (l > len)
110 			l = len;
111 
112 		set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
113 
114 		bcopy(kp, p, l);
115 
116 		up += l;
117 		kp += l;
118 		len -= l;
119 	}
120 
121 	td->td_pcb->pcb_onfault = NULL;
122 	return (0);
123 }
124 
125 int
126 copyin(const void *udaddr, void *kaddr, size_t len)
127 {
128 	struct		thread *td;
129 	pmap_t		pm;
130 	faultbuf	env;
131 	const char	*up;
132 	char		*kp, *p;
133 	size_t		l;
134 
135 	td = PCPU_GET(curthread);
136 	pm = &td->td_proc->p_vmspace->vm_pmap;
137 
138 	if (setfault(env)) {
139 		td->td_pcb->pcb_onfault = NULL;
140 		return (EFAULT);
141 	}
142 
143 	kp = kaddr;
144 	up = udaddr;
145 
146 	while (len > 0) {
147 		p = (char *)USER_ADDR + ((u_int)up & ~SEGMENT_MASK);
148 
149 		l = ((char *)USER_ADDR + SEGMENT_LENGTH) - p;
150 		if (l > len)
151 			l = len;
152 
153 		set_user_sr(pm->pm_sr[(u_int)up >> ADDR_SR_SHFT]);
154 
155 		bcopy(p, kp, l);
156 
157 		up += l;
158 		kp += l;
159 		len -= l;
160 	}
161 
162 	td->td_pcb->pcb_onfault = NULL;
163 	return (0);
164 }
165 
166 int
167 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
168 {
169 	struct		thread *td;
170 	pmap_t		pm;
171 	faultbuf	env;
172 	const char	*up;
173 	char		*kp;
174 	size_t		l;
175 	int		rv, c;
176 
177 	td = PCPU_GET(curthread);
178 	pm = &td->td_proc->p_vmspace->vm_pmap;
179 
180 	if (setfault(env)) {
181 		td->td_pcb->pcb_onfault = NULL;
182 		return (EFAULT);
183 	}
184 
185 	kp = kaddr;
186 	up = udaddr;
187 
188 	rv = ENAMETOOLONG;
189 
190 	for (l = 0; len-- > 0; l++) {
191 		if ((c = fubyte(up++)) < 0) {
192 			rv = EFAULT;
193 			break;
194 		}
195 
196 		if (!(*kp++ = c)) {
197 			l++;
198 			rv = 0;
199 			break;
200 		}
201 	}
202 
203 	if (done != NULL) {
204 		*done = l;
205 	}
206 
207 	td->td_pcb->pcb_onfault = NULL;
208 	return (rv);
209 }
210 
211 int
212 subyte(void *addr, int byte)
213 {
214 	struct		thread *td;
215 	pmap_t		pm;
216 	faultbuf	env;
217 	char		*p;
218 
219 	td = PCPU_GET(curthread);
220 	pm = &td->td_proc->p_vmspace->vm_pmap;
221 	p = (char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
222 
223 	if (setfault(env)) {
224 		td->td_pcb->pcb_onfault = NULL;
225 		return (-1);
226 	}
227 
228 	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
229 
230 	*p = (char)byte;
231 
232 	td->td_pcb->pcb_onfault = NULL;
233 	return (0);
234 }
235 
236 int
237 suword(void *addr, long word)
238 {
239 	struct		thread *td;
240 	pmap_t		pm;
241 	faultbuf	env;
242 	long		*p;
243 
244 	td = PCPU_GET(curthread);
245 	pm = &td->td_proc->p_vmspace->vm_pmap;
246 	p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
247 
248 	if (setfault(env)) {
249 		td->td_pcb->pcb_onfault = NULL;
250 		return (-1);
251 	}
252 
253 	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
254 
255 	*p = word;
256 
257 	td->td_pcb->pcb_onfault = NULL;
258 	return (0);
259 }
260 
261 int
262 suword32(void *addr, int32_t word)
263 {
264 	return (suword(addr, (long)word));
265 }
266 
267 
268 int
269 fubyte(const void *addr)
270 {
271 	struct		thread *td;
272 	pmap_t		pm;
273 	faultbuf	env;
274 	u_char		*p;
275 	int		val;
276 
277 	td = PCPU_GET(curthread);
278 	pm = &td->td_proc->p_vmspace->vm_pmap;
279 	p = (u_char *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
280 
281 	if (setfault(env)) {
282 		td->td_pcb->pcb_onfault = NULL;
283 		return (-1);
284 	}
285 
286 	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
287 
288 	val = *p;
289 
290 	td->td_pcb->pcb_onfault = NULL;
291 	return (val);
292 }
293 
294 long
295 fuword(const void *addr)
296 {
297 	struct		thread *td;
298 	pmap_t		pm;
299 	faultbuf	env;
300 	long		*p, val;
301 
302 	td = PCPU_GET(curthread);
303 	pm = &td->td_proc->p_vmspace->vm_pmap;
304 	p = (long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
305 
306 	if (setfault(env)) {
307 		td->td_pcb->pcb_onfault = NULL;
308 		return (-1);
309 	}
310 
311 	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
312 
313 	val = *p;
314 
315 	td->td_pcb->pcb_onfault = NULL;
316 	return (val);
317 }
318 
319 int32_t
320 fuword32(const void *addr)
321 {
322 	return ((int32_t)fuword(addr));
323 }
324 
325 uint32_t
326 casuword32(volatile uint32_t *base, uint32_t oldval, uint32_t newval)
327 {
328 	return (casuword((volatile u_long *)base, oldval, newval));
329 }
330 
331 u_long
332 casuword(volatile u_long *addr, u_long old, u_long new)
333 {
334 	struct thread *td;
335 	pmap_t pm;
336 	faultbuf env;
337 	u_long *p, val;
338 
339 	td = PCPU_GET(curthread);
340 	pm = &td->td_proc->p_vmspace->vm_pmap;
341 	p = (u_long *)((u_int)USER_ADDR + ((u_int)addr & ~SEGMENT_MASK));
342 
343 	set_user_sr(pm->pm_sr[(u_int)addr >> ADDR_SR_SHFT]);
344 
345 	if (setfault(env)) {
346 		td->td_pcb->pcb_onfault = NULL;
347 		return (-1);
348 	}
349 
350 	val = *p;
351 	(void) atomic_cmpset_32((volatile uint32_t *)p, old, new);
352 
353 	td->td_pcb->pcb_onfault = NULL;
354 
355 	return (val);
356 }
357