]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/powerpc/powerpc/copyinout.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / powerpc / powerpc / copyinout.c
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/lock.h>
61 #include <sys/mutex.h>
62 #include <sys/systm.h>
63 #include <sys/proc.h>
64
65 #include <vm/vm.h>
66 #include <vm/pmap.h>
67 #include <vm/vm_map.h>
68
69 #include <machine/pcb.h>
70 #include <machine/sr.h>
71 #include <machine/slb.h>
72 #include <machine/vmparam.h>
73
74 int     setfault(faultbuf);     /* defined in locore.S */
75
76 #ifdef AIM
77 /*
78  * Makes sure that the right segment of userspace is mapped in.
79  */
80
81 #ifdef __powerpc64__
82 static __inline void
83 set_user_sr(pmap_t pm, volatile const void *addr)
84 {
85         struct slb *slb;
86         register_t slbv;
87
88         /* Try lockless look-up first */
89         slb = user_va_to_slb_entry(pm, (vm_offset_t)addr);
90
91         if (slb == NULL) {
92                 /* If it isn't there, we need to pre-fault the VSID */
93                 PMAP_LOCK(pm);
94                 slbv = va_to_vsid(pm, (vm_offset_t)addr) << SLBV_VSID_SHIFT;
95                 PMAP_UNLOCK(pm);
96         } else {
97                 slbv = slb->slbv;
98         }
99
100         /* Mark segment no-execute */
101         slbv |= SLBV_N;
102
103         /* If we have already set this VSID, we can just return */
104         if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == slbv) 
105                 return;
106
107         __asm __volatile("isync");
108         curthread->td_pcb->pcb_cpu.aim.usr_segm =
109             (uintptr_t)addr >> ADDR_SR_SHFT;
110         curthread->td_pcb->pcb_cpu.aim.usr_vsid = slbv;
111         __asm __volatile ("slbie %0; slbmte %1, %2; isync" ::
112             "r"(USER_ADDR), "r"(slbv), "r"(USER_SLB_SLBE));
113 }
114 #else
115 static __inline void
116 set_user_sr(pmap_t pm, volatile const void *addr)
117 {
118         register_t vsid;
119
120         vsid = va_to_vsid(pm, (vm_offset_t)addr);
121
122         /* Mark segment no-execute */
123         vsid |= SR_N;
124
125         /* If we have already set this VSID, we can just return */
126         if (curthread->td_pcb->pcb_cpu.aim.usr_vsid == vsid)
127                 return;
128
129         __asm __volatile("isync");
130         curthread->td_pcb->pcb_cpu.aim.usr_segm =
131             (uintptr_t)addr >> ADDR_SR_SHFT;
132         curthread->td_pcb->pcb_cpu.aim.usr_vsid = vsid;
133         __asm __volatile("mtsr %0,%1; isync" :: "n"(USER_SR), "r"(vsid));
134 }
135 #endif
136
137 static __inline int
138 map_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
139     size_t *klen)
140 {
141         size_t l;
142
143         *kaddr = (char *)USER_ADDR + ((uintptr_t)uaddr & ~SEGMENT_MASK);
144
145         l = ((char *)USER_ADDR + SEGMENT_LENGTH) - (char *)(*kaddr);
146         if (l > ulen)
147                 l = ulen;
148         if (klen)
149                 *klen = l;
150         else if (l != ulen)
151                 return (EFAULT);
152
153         set_user_sr(pm, uaddr);
154
155         return (0);
156 }
157 #else /* Book-E uses a combined kernel/user mapping */
158 static __inline int
159 map_user_ptr(pmap_t pm, volatile const void *uaddr, void **kaddr, size_t ulen,
160     size_t *klen)
161 {
162
163         if ((uintptr_t)uaddr + ulen > VM_MAXUSER_ADDRESS + PAGE_SIZE)
164                 return (EFAULT);
165
166         *kaddr = (void *)(uintptr_t)uaddr;
167         if (klen)
168                 *klen = ulen;
169
170         return (0);
171 }
172 #endif
173
174 int
175 copyout(const void *kaddr, void *udaddr, size_t len)
176 {
177         struct          thread *td;
178         pmap_t          pm;
179         faultbuf        env;
180         const char      *kp;
181         char            *up, *p;
182         size_t          l;
183
184         td = curthread;
185         pm = &td->td_proc->p_vmspace->vm_pmap;
186
187         if (setfault(env)) {
188                 td->td_pcb->pcb_onfault = NULL;
189                 return (EFAULT);
190         }
191
192         kp = kaddr;
193         up = udaddr;
194
195         while (len > 0) {
196                 if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
197                         td->td_pcb->pcb_onfault = NULL;
198                         return (EFAULT);
199                 }
200
201                 bcopy(kp, p, l);
202
203                 up += l;
204                 kp += l;
205                 len -= l;
206         }
207
208         td->td_pcb->pcb_onfault = NULL;
209         return (0);
210 }
211
212 int
213 copyin(const void *udaddr, void *kaddr, size_t len)
214 {
215         struct          thread *td;
216         pmap_t          pm;
217         faultbuf        env;
218         const char      *up;
219         char            *kp, *p;
220         size_t          l;
221
222         td = curthread;
223         pm = &td->td_proc->p_vmspace->vm_pmap;
224
225         if (setfault(env)) {
226                 td->td_pcb->pcb_onfault = NULL;
227                 return (EFAULT);
228         }
229
230         kp = kaddr;
231         up = udaddr;
232
233         while (len > 0) {
234                 if (map_user_ptr(pm, udaddr, (void **)&p, len, &l)) {
235                         td->td_pcb->pcb_onfault = NULL;
236                         return (EFAULT);
237                 }
238
239                 bcopy(p, kp, l);
240
241                 up += l;
242                 kp += l;
243                 len -= l;
244         }
245
246         td->td_pcb->pcb_onfault = NULL;
247         return (0);
248 }
249
250 int
251 copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
252 {
253         const char      *up;
254         char            *kp;
255         size_t          l;
256         int             rv, c;
257
258         kp = kaddr;
259         up = udaddr;
260
261         rv = ENAMETOOLONG;
262
263         for (l = 0; len-- > 0; l++) {
264                 if ((c = fubyte(up++)) < 0) {
265                         rv = EFAULT;
266                         break;
267                 }
268
269                 if (!(*kp++ = c)) {
270                         l++;
271                         rv = 0;
272                         break;
273                 }
274         }
275
276         if (done != NULL) {
277                 *done = l;
278         }
279
280         return (rv);
281 }
282
283 int
284 subyte(volatile void *addr, int byte)
285 {
286         struct          thread *td;
287         pmap_t          pm;
288         faultbuf        env;
289         char            *p;
290
291         td = curthread;
292         pm = &td->td_proc->p_vmspace->vm_pmap;
293
294         if (setfault(env)) {
295                 td->td_pcb->pcb_onfault = NULL;
296                 return (-1);
297         }
298
299         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
300                 td->td_pcb->pcb_onfault = NULL;
301                 return (-1);
302         }
303
304         *p = (char)byte;
305
306         td->td_pcb->pcb_onfault = NULL;
307         return (0);
308 }
309
310 #ifdef __powerpc64__
311 int
312 suword32(volatile void *addr, int word)
313 {
314         struct          thread *td;
315         pmap_t          pm;
316         faultbuf        env;
317         int             *p;
318
319         td = curthread;
320         pm = &td->td_proc->p_vmspace->vm_pmap;
321
322         if (setfault(env)) {
323                 td->td_pcb->pcb_onfault = NULL;
324                 return (-1);
325         }
326
327         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
328                 td->td_pcb->pcb_onfault = NULL;
329                 return (-1);
330         }
331
332         *p = word;
333
334         td->td_pcb->pcb_onfault = NULL;
335         return (0);
336 }
337 #endif
338
339 int
340 suword(volatile void *addr, long word)
341 {
342         struct          thread *td;
343         pmap_t          pm;
344         faultbuf        env;
345         long            *p;
346
347         td = curthread;
348         pm = &td->td_proc->p_vmspace->vm_pmap;
349
350         if (setfault(env)) {
351                 td->td_pcb->pcb_onfault = NULL;
352                 return (-1);
353         }
354
355         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
356                 td->td_pcb->pcb_onfault = NULL;
357                 return (-1);
358         }
359
360         *p = word;
361
362         td->td_pcb->pcb_onfault = NULL;
363         return (0);
364 }
365
366 #ifdef __powerpc64__
367 int
368 suword64(volatile void *addr, int64_t word)
369 {
370         return (suword(addr, (long)word));
371 }
372 #else
373 int
374 suword32(volatile void *addr, int32_t word)
375 {
376         return (suword(addr, (long)word));
377 }
378 #endif
379
380 int
381 fubyte(volatile const void *addr)
382 {
383         struct          thread *td;
384         pmap_t          pm;
385         faultbuf        env;
386         u_char          *p;
387         int             val;
388
389         td = curthread;
390         pm = &td->td_proc->p_vmspace->vm_pmap;
391
392         if (setfault(env)) {
393                 td->td_pcb->pcb_onfault = NULL;
394                 return (-1);
395         }
396
397         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
398                 td->td_pcb->pcb_onfault = NULL;
399                 return (-1);
400         }
401
402         val = *p;
403
404         td->td_pcb->pcb_onfault = NULL;
405         return (val);
406 }
407
408 int
409 fuword16(volatile const void *addr)
410 {
411         struct          thread *td;
412         pmap_t          pm;
413         faultbuf        env;
414         uint16_t        *p, val;
415
416         td = curthread;
417         pm = &td->td_proc->p_vmspace->vm_pmap;
418
419         if (setfault(env)) {
420                 td->td_pcb->pcb_onfault = NULL;
421                 return (-1);
422         }
423
424         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
425                 td->td_pcb->pcb_onfault = NULL;
426                 return (-1);
427         }
428
429         val = *p;
430
431         td->td_pcb->pcb_onfault = NULL;
432         return (val);
433 }
434
435 int
436 fueword32(volatile const void *addr, int32_t *val)
437 {
438         struct          thread *td;
439         pmap_t          pm;
440         faultbuf        env;
441         int32_t         *p;
442
443         td = curthread;
444         pm = &td->td_proc->p_vmspace->vm_pmap;
445
446         if (setfault(env)) {
447                 td->td_pcb->pcb_onfault = NULL;
448                 return (-1);
449         }
450
451         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
452                 td->td_pcb->pcb_onfault = NULL;
453                 return (-1);
454         }
455
456         *val = *p;
457
458         td->td_pcb->pcb_onfault = NULL;
459         return (0);
460 }
461
462 #ifdef __powerpc64__
463 int
464 fueword64(volatile const void *addr, int64_t *val)
465 {
466         struct          thread *td;
467         pmap_t          pm;
468         faultbuf        env;
469         int64_t         *p;
470
471         td = curthread;
472         pm = &td->td_proc->p_vmspace->vm_pmap;
473
474         if (setfault(env)) {
475                 td->td_pcb->pcb_onfault = NULL;
476                 return (-1);
477         }
478
479         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
480                 td->td_pcb->pcb_onfault = NULL;
481                 return (-1);
482         }
483
484         *val = *p;
485
486         td->td_pcb->pcb_onfault = NULL;
487         return (0);
488 }
489 #endif
490
491 int
492 fueword(volatile const void *addr, long *val)
493 {
494         struct          thread *td;
495         pmap_t          pm;
496         faultbuf        env;
497         long            *p;
498
499         td = curthread;
500         pm = &td->td_proc->p_vmspace->vm_pmap;
501
502         if (setfault(env)) {
503                 td->td_pcb->pcb_onfault = NULL;
504                 return (-1);
505         }
506
507         if (map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
508                 td->td_pcb->pcb_onfault = NULL;
509                 return (-1);
510         }
511
512         *val = *p;
513
514         td->td_pcb->pcb_onfault = NULL;
515         return (0);
516 }
517
518 int
519 casueword32(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
520     uint32_t new)
521 {
522         struct thread *td;
523         pmap_t pm;
524         faultbuf env;
525         uint32_t *p, val;
526
527         td = curthread;
528         pm = &td->td_proc->p_vmspace->vm_pmap;
529
530         if (setfault(env)) {
531                 td->td_pcb->pcb_onfault = NULL;
532                 return (-1);
533         }
534
535         if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
536             NULL)) {
537                 td->td_pcb->pcb_onfault = NULL;
538                 return (-1);
539         }
540
541         __asm __volatile (
542                 "1:\tlwarx %0, 0, %2\n\t"       /* load old value */
543                 "cmplw %3, %0\n\t"              /* compare */
544                 "bne 2f\n\t"                    /* exit if not equal */
545                 "stwcx. %4, 0, %2\n\t"          /* attempt to store */
546                 "bne- 1b\n\t"                   /* spin if failed */
547                 "b 3f\n\t"                      /* we've succeeded */
548                 "2:\n\t"
549                 "stwcx. %0, 0, %2\n\t"          /* clear reservation (74xx) */
550                 "3:\n\t"
551                 : "=&r" (val), "=m" (*p)
552                 : "r" (p), "r" (old), "r" (new), "m" (*p)
553                 : "cc", "memory");
554
555         td->td_pcb->pcb_onfault = NULL;
556
557         *oldvalp = val;
558         return (0);
559 }
560
561 #ifndef __powerpc64__
562 int
563 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
564 {
565
566         return (casueword32((volatile uint32_t *)addr, old,
567             (uint32_t *)oldvalp, new));
568 }
569 #else
570 int
571 casueword(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
572 {
573         struct thread *td;
574         pmap_t pm;
575         faultbuf env;
576         u_long *p, val;
577
578         td = curthread;
579         pm = &td->td_proc->p_vmspace->vm_pmap;
580
581         if (setfault(env)) {
582                 td->td_pcb->pcb_onfault = NULL;
583                 return (-1);
584         }
585
586         if (map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p, sizeof(*p),
587             NULL)) {
588                 td->td_pcb->pcb_onfault = NULL;
589                 return (-1);
590         }
591
592         __asm __volatile (
593                 "1:\tldarx %0, 0, %2\n\t"       /* load old value */
594                 "cmpld %3, %0\n\t"              /* compare */
595                 "bne 2f\n\t"                    /* exit if not equal */
596                 "stdcx. %4, 0, %2\n\t"          /* attempt to store */
597                 "bne- 1b\n\t"                   /* spin if failed */
598                 "b 3f\n\t"                      /* we've succeeded */
599                 "2:\n\t"
600                 "stdcx. %0, 0, %2\n\t"          /* clear reservation (74xx) */
601                 "3:\n\t"
602                 : "=&r" (val), "=m" (*p)
603                 : "r" (p), "r" (old), "r" (new), "m" (*p)
604                 : "cc", "memory");
605
606         td->td_pcb->pcb_onfault = NULL;
607
608         *oldvalp = val;
609         return (0);
610 }
611 #endif