1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-4-Clause
3 *
4 * Copyright (C) 2002 Benno Rice
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*-
28 * Copyright (C) 1993 Wolfgang Solfrank.
29 * Copyright (C) 1993 TooLs GmbH.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by TooLs GmbH.
43 * 4. The name of TooLs GmbH may not be used to endorse or promote products
44 * derived from this software without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
47 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
48 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
51 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
52 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
53 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
54 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
55 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 */
57
58 #include <sys/cdefs.h>
59 __FBSDID("$FreeBSD$");
60
61 #include <sys/param.h>
62 #include <sys/lock.h>
63 #include <sys/mutex.h>
64 #include <sys/systm.h>
65 #include <sys/proc.h>
66
67 #include <vm/vm.h>
68 #include <vm/pmap.h>
69 #include <vm/vm_map.h>
70
71 #include <machine/pcb.h>
72 #include <machine/vmparam.h>
73
74 int
75 copyout(const void *kaddr, void *udaddr, size_t len)
76 {
77 struct thread *td;
78 pmap_t pm;
79 jmp_buf env;
80 const char *kp;
81 char *up, *p;
82 size_t l;
83
84 td = curthread;
85 pm = &td->td_proc->p_vmspace->vm_pmap;
86
87 td->td_pcb->pcb_onfault = &env;
88 if (setjmp(env)) {
89 td->td_pcb->pcb_onfault = NULL;
90 return (EFAULT);
91 }
92
93 kp = kaddr;
94 up = udaddr;
95
96 while (len > 0) {
97 if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) {
98 td->td_pcb->pcb_onfault = NULL;
99 return (EFAULT);
100 }
101
102 bcopy(kp, p, l);
103
104 up += l;
105 kp += l;
106 len -= l;
107 }
108
109 td->td_pcb->pcb_onfault = NULL;
110 return (0);
111 }
112
113 int
114 copyin(const void *udaddr, void *kaddr, size_t len)
115 {
116 struct thread *td;
117 pmap_t pm;
118 jmp_buf env;
119 const char *up;
120 char *kp, *p;
121 size_t l;
122
123 td = curthread;
124 pm = &td->td_proc->p_vmspace->vm_pmap;
125
126 td->td_pcb->pcb_onfault = &env;
127 if (setjmp(env)) {
128 td->td_pcb->pcb_onfault = NULL;
129 return (EFAULT);
130 }
131
132 kp = kaddr;
133 up = udaddr;
134
135 while (len > 0) {
136 if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) {
137 td->td_pcb->pcb_onfault = NULL;
138 return (EFAULT);
139 }
140
141 bcopy(p, kp, l);
142
143 up += l;
144 kp += l;
145 len -= l;
146 }
147
148 td->td_pcb->pcb_onfault = NULL;
149 return (0);
150 }
151
152 int
153 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
154 {
155 const char *up;
156 char *kp;
157 size_t l;
158 int rv, c;
159
160 kp = kaddr;
161 up = udaddr;
162
163 rv = ENAMETOOLONG;
164
165 for (l = 0; len-- > 0; l++) {
166 if ((c = fubyte(up++)) < 0) {
167 rv = EFAULT;
168 break;
169 }
170
171 if (!(*kp++ = c)) {
172 l++;
173 rv = 0;
174 break;
175 }
176 }
177
178 if (done != NULL) {
179 *done = l;
180 }
181
182 return (rv);
183 }
184
185 int
186 subyte(volatile void *addr, int byte)
187 {
188 struct thread *td;
189 pmap_t pm;
190 jmp_buf env;
191 char *p;
192
193 td = curthread;
194 pm = &td->td_proc->p_vmspace->vm_pmap;
195
196 td->td_pcb->pcb_onfault = &env;
197 if (setjmp(env)) {
198 td->td_pcb->pcb_onfault = NULL;
199 return (-1);
200 }
201
202 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
203 td->td_pcb->pcb_onfault = NULL;
204 return (-1);
205 }
206
207 *p = (char)byte;
208
209 td->td_pcb->pcb_onfault = NULL;
210 return (0);
211 }
212
213 #ifdef __powerpc64__
214 int
215 suword32(volatile void *addr, int word)
216 {
217 struct thread *td;
218 pmap_t pm;
219 jmp_buf env;
220 int *p;
221
222 td = curthread;
223 pm = &td->td_proc->p_vmspace->vm_pmap;
224
225 td->td_pcb->pcb_onfault = &env;
226 if (setjmp(env)) {
227 td->td_pcb->pcb_onfault = NULL;
228 return (-1);
229 }
230
231 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
232 td->td_pcb->pcb_onfault = NULL;
233 return (-1);
234 }
235
236 *p = word;
237
238 td->td_pcb->pcb_onfault = NULL;
239 return (0);
240 }
241 #endif
242
243 int
244 suword(volatile void *addr, long word)
245 {
246 struct thread *td;
247 pmap_t pm;
248 jmp_buf env;
249 long *p;
250
251 td = curthread;
252 pm = &td->td_proc->p_vmspace->vm_pmap;
253
254 td->td_pcb->pcb_onfault = &env;
255 if (setjmp(env)) {
256 td->td_pcb->pcb_onfault = NULL;
257 return (-1);
258 }
259
260 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
261 td->td_pcb->pcb_onfault = NULL;
262 return (-1);
263 }
264
265 *p = word;
266
267 td->td_pcb->pcb_onfault = NULL;
268 return (0);
269 }
270
271 #ifdef __powerpc64__
272 int
273 suword64(volatile void *addr, int64_t word)
274 {
275 return (suword(addr, (long)word));
276 }
277 #else
278 int
279 suword32(volatile void *addr, int32_t word)
280 {
281 return (suword(addr, (long)word));
282 }
283 #endif
284
285 int
286 fubyte(volatile const void *addr)
287 {
288 struct thread *td;
289 pmap_t pm;
290 jmp_buf env;
291 u_char *p;
292 int val;
293
294 td = curthread;
295 pm = &td->td_proc->p_vmspace->vm_pmap;
296
297 td->td_pcb->pcb_onfault = &env;
298 if (setjmp(env)) {
299 td->td_pcb->pcb_onfault = NULL;
300 return (-1);
301 }
302
303 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
304 td->td_pcb->pcb_onfault = NULL;
305 return (-1);
306 }
307
308 val = *p;
309
310 td->td_pcb->pcb_onfault = NULL;
311 return (val);
312 }
313
314 int
315 fuword16(volatile const void *addr)
316 {
317 struct thread *td;
318 pmap_t pm;
319 jmp_buf env;
320 uint16_t *p, val;
321
322 td = curthread;
323 pm = &td->td_proc->p_vmspace->vm_pmap;
324
325 td->td_pcb->pcb_onfault = &env;
326 if (setjmp(env)) {
327 td->td_pcb->pcb_onfault = NULL;
328 return (-1);
329 }
330
331 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
332 td->td_pcb->pcb_onfault = NULL;
333 return (-1);
334 }
335
336 val = *p;
337
338 td->td_pcb->pcb_onfault = NULL;
339 return (val);
340 }
341
342 int
343 fueword32(volatile const void *addr, int32_t *val)
344 {
345 struct thread *td;
346 pmap_t pm;
347 jmp_buf env;
348 int32_t *p;
349
350 td = curthread;
351 pm = &td->td_proc->p_vmspace->vm_pmap;
352
353 td->td_pcb->pcb_onfault = &env;
354 if (setjmp(env)) {
355 td->td_pcb->pcb_onfault = NULL;
356 return (-1);
357 }
358
359 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
360 td->td_pcb->pcb_onfault = NULL;
361 return (-1);
362 }
363
364 *val = *p;
365
366 td->td_pcb->pcb_onfault = NULL;
367 return (0);
368 }
369
370 #ifdef __powerpc64__
371 int
372 fueword64(volatile const void *addr, int64_t *val)
373 {
374 struct thread *td;
375 pmap_t pm;
376 jmp_buf env;
377 int64_t *p;
378
379 td = curthread;
380 pm = &td->td_proc->p_vmspace->vm_pmap;
381
382 td->td_pcb->pcb_onfault = &env;
383 if (setjmp(env)) {
384 td->td_pcb->pcb_onfault = NULL;
385 return (-1);
386 }
387
388 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
389 td->td_pcb->pcb_onfault = NULL;
390 return (-1);
391 }
392
393 *val = *p;
394
395 td->td_pcb->pcb_onfault = NULL;
396 return (0);
397 }
398 #endif
399
400 int
401 fueword(volatile const void *addr, long *val)
402 {
403 struct thread *td;
404 pmap_t pm;
405 jmp_buf env;
406 long *p;
407
408 td = curthread;
409 pm = &td->td_proc->p_vmspace->vm_pmap;
410
411 td->td_pcb->pcb_onfault = &env;
412 if (setjmp(env)) {
413 td->td_pcb->pcb_onfault = NULL;
414 return (-1);
415 }
416
417 if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
418 td->td_pcb->pcb_onfault = NULL;
419 return (-1);
420 }
421
422 *val = *p;
423
424 td->td_pcb->pcb_onfault = NULL;
425 return (0);
426 }
427
428 int
429 casueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
430 uint32_t new)
431 {
432 struct thread *td;
433 pmap_t pm;
434 jmp_buf env;
435 uint32_t *p, val;
436 int res;
437
438 td = curthread;
439 pm = &td->td_proc->p_vmspace->vm_pmap;
440
441 td->td_pcb->pcb_onfault = &env;
442 if (setjmp(env)) {
443 td->td_pcb->pcb_onfault = NULL;
444 return (-1);
445 }
446
447 if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
448 sizeof(*p), NULL)) {
449 td->td_pcb->pcb_onfault = NULL;
450 return (-1);
451 }
452
453 res = 0;
454 __asm __volatile (
455 "lwarx %0, 0, %3\n\t" /* load old value */
456 "cmplw %4, %0\n\t" /* compare */
457 "bne 1f\n\t" /* exit if not equal */
458 "stwcx. %5, 0, %3\n\t" /* attempt to store */
459 "bne- 2f\n\t" /* if failed */
460 "b 3f\n\t" /* we've succeeded */
461 "1:\n\t"
462 "stwcx. %0, 0, %3\n\t" /* clear reservation (74xx) */
463 "2:li %2, 1\n\t"
464 "3:\n\t"
465 : "=&r" (val), "=m" (*p), "+&r" (res)
466 : "r" (p), "r" (old), "r" (new), "m" (*p)
467 : "cr0", "memory");
468
469 td->td_pcb->pcb_onfault = NULL;
470
471 *oldvalp = val;
472 return (res);
473 }
474
475 #ifndef __powerpc64__
476 int
477 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
478 {
479
480 return (casueword32((volatile uint32_t *)addr, old,
481 (uint32_t *)oldvalp, new));
482 }
483 #else
484 int
485 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
486 {
487 struct thread *td;
488 pmap_t pm;
489 jmp_buf env;
490 u_long *p, val;
491 int res;
492
493 td = curthread;
494 pm = &td->td_proc->p_vmspace->vm_pmap;
495
496 td->td_pcb->pcb_onfault = &env;
497 if (setjmp(env)) {
498 td->td_pcb->pcb_onfault = NULL;
499 return (-1);
500 }
501
502 if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
503 sizeof(*p), NULL)) {
504 td->td_pcb->pcb_onfault = NULL;
505 return (-1);
506 }
507
508 res = 0;
509 __asm __volatile (
510 "ldarx %0, 0, %3\n\t" /* load old value */
511 "cmpld %4, %0\n\t" /* compare */
512 "bne 1f\n\t" /* exit if not equal */
513 "stdcx. %5, 0, %3\n\t" /* attempt to store */
514 "bne- 2f\n\t" /* if failed */
515 "b 3f\n\t" /* we've succeeded */
516 "1:\n\t"
517 "stdcx. %0, 0, %3\n\t" /* clear reservation (74xx) */
518 "2:li %2, 1\n\t"
519 "3:\n\t"
520 : "=&r" (val), "=m" (*p), "+&r" (res)
521 : "r" (p), "r" (old), "r" (new), "m" (*p)
522 : "cr0", "memory");
523
524 td->td_pcb->pcb_onfault = NULL;
525
526 *oldvalp = val;
527 return (res);
528 }
529 #endif
Cache object: f9f2580531eccc88cb2c745c50dcab07
|