]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powerpc/copyinout.c
MFV r341618:
[FreeBSD/FreeBSD.git] / sys / powerpc / powerpc / copyinout.c
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
437         td = curthread;
438         pm = &td->td_proc->p_vmspace->vm_pmap;
439
440         td->td_pcb->pcb_onfault = &env;
441         if (setjmp(env)) {
442                 td->td_pcb->pcb_onfault = NULL;
443                 return (-1);
444         }
445
446         if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
447             sizeof(*p), NULL)) {
448                 td->td_pcb->pcb_onfault = NULL;
449                 return (-1);
450         }
451
452         __asm __volatile (
453                 "1:\tlwarx %0, 0, %2\n\t"       /* load old value */
454                 "cmplw %3, %0\n\t"              /* compare */
455                 "bne 2f\n\t"                    /* exit if not equal */
456                 "stwcx. %4, 0, %2\n\t"          /* attempt to store */
457                 "bne- 1b\n\t"                   /* spin if failed */
458                 "b 3f\n\t"                      /* we've succeeded */
459                 "2:\n\t"
460                 "stwcx. %0, 0, %2\n\t"          /* clear reservation (74xx) */
461                 "3:\n\t"
462                 : "=&r" (val), "=m" (*p)
463                 : "r" (p), "r" (old), "r" (new), "m" (*p)
464                 : "cr0", "memory");
465
466         td->td_pcb->pcb_onfault = NULL;
467
468         *oldvalp = val;
469         return (0);
470 }
471
472 #ifndef __powerpc64__
473 int
474 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
475 {
476
477         return (casueword32((volatile uint32_t *)addr, old,
478             (uint32_t *)oldvalp, new));
479 }
480 #else
481 int
482 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
483 {
484         struct thread *td;
485         pmap_t pm;
486         jmp_buf         env;
487         u_long *p, val;
488
489         td = curthread;
490         pm = &td->td_proc->p_vmspace->vm_pmap;
491
492         td->td_pcb->pcb_onfault = &env;
493         if (setjmp(env)) {
494                 td->td_pcb->pcb_onfault = NULL;
495                 return (-1);
496         }
497
498         if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
499             sizeof(*p), NULL)) {
500                 td->td_pcb->pcb_onfault = NULL;
501                 return (-1);
502         }
503
504         __asm __volatile (
505                 "1:\tldarx %0, 0, %2\n\t"       /* load old value */
506                 "cmpld %3, %0\n\t"              /* compare */
507                 "bne 2f\n\t"                    /* exit if not equal */
508                 "stdcx. %4, 0, %2\n\t"          /* attempt to store */
509                 "bne- 1b\n\t"                   /* spin if failed */
510                 "b 3f\n\t"                      /* we've succeeded */
511                 "2:\n\t"
512                 "stdcx. %0, 0, %2\n\t"          /* clear reservation (74xx) */
513                 "3:\n\t"
514                 : "=&r" (val), "=m" (*p)
515                 : "r" (p), "r" (old), "r" (new), "m" (*p)
516                 : "cr0", "memory");
517
518         td->td_pcb->pcb_onfault = NULL;
519
520         *oldvalp = val;
521         return (0);
522 }
523 #endif