]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powerpc/copyinout.c
Optionally bind ktls threads to NUMA domains
[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_extern.h>
70 #include <vm/vm_map.h>
71
72 #include <machine/mmuvar.h>
73 #include <machine/pcb.h>
74 #include <machine/vmparam.h>
75 #include <machine/ifunc.h>
76
77 /*
78  * On powerpc64 (AIM only) the copy functions are IFUNCs, selecting the best
79  * option based on the PMAP in use.
80  *
81  * There are two options for copy functions on powerpc64:
82  * - 'remap' copies, which remap userspace segments into kernel space for
83  *   copying.  This is used by the 'oea64' pmap.
84  * - 'direct' copies, which copy directly from userspace.  This does not require
85  *   remapping user segments into kernel.  This is used by the 'radix' pmap for
86  *   performance.
87  *
88  * Book-E does not use the C 'remap' functions, opting instead to use the
89  * 'direct' copies, directly, avoiding the IFUNC overhead.
90  *
91  * On 32-bit AIM these functions bypass the IFUNC machinery for performance.
92  */
93 #ifdef __powerpc64__
94 int subyte_remap(volatile void *addr, int byte);
95 int subyte_direct(volatile void *addr, int byte);
96 int copyinstr_remap(const void *udaddr, void *kaddr, size_t len, size_t *done);
97 int copyinstr_direct(const void *udaddr, void *kaddr, size_t len, size_t *done);
98 int copyout_remap(const void *kaddr, void *udaddr, size_t len);
99 int copyout_direct(const void *kaddr, void *udaddr, size_t len);
100 int copyin_remap(const void *uaddr, void *kaddr, size_t len);
101 int copyin_direct(const void *uaddr, void *kaddr, size_t len);
102 int suword32_remap(volatile void *addr, int word);
103 int suword32_direct(volatile void *addr, int word);
104 int suword_remap(volatile void *addr, long word);
105 int suword_direct(volatile void *addr, long word);
106 int suword64_remap(volatile void *addr, int64_t word);
107 int suword64_direct(volatile void *addr, int64_t word);
108 int fubyte_remap(volatile const void *addr);
109 int fubyte_direct(volatile const void *addr);
110 int fuword16_remap(volatile const void *addr);
111 int fuword16_direct(volatile const void *addr);
112 int fueword32_remap(volatile const void *addr, int32_t *val);
113 int fueword32_direct(volatile const void *addr, int32_t *val);
114 int fueword64_remap(volatile const void *addr, int64_t *val);
115 int fueword64_direct(volatile const void *addr, int64_t *val);
116 int fueword_remap(volatile const void *addr, long *val);
117 int fueword_direct(volatile const void *addr, long *val);
118 int casueword32_remap(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
119         uint32_t new);
120 int casueword32_direct(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
121         uint32_t new);
122 int casueword_remap(volatile u_long *addr, u_long old, u_long *oldvalp,
123         u_long new);
124 int casueword_direct(volatile u_long *addr, u_long old, u_long *oldvalp,
125         u_long new);
126
127 /*
128  * The IFUNC resolver determines the copy based on whether the PMAP
129  * implementation includes a pmap_map_user_ptr function.
130  */
131 #define DEFINE_COPY_FUNC(ret, func, args)                       \
132         DEFINE_IFUNC(, ret, func, args)                         \
133         {                                                       \
134                 return (PMAP_RESOLVE_FUNC(map_user_ptr) ?       \
135                     func##_remap : func##_direct);              \
136         }
137 DEFINE_COPY_FUNC(int, subyte, (volatile void *, int))
138 DEFINE_COPY_FUNC(int, copyinstr, (const void *, void *, size_t, size_t *))
139 DEFINE_COPY_FUNC(int, copyin, (const void *, void *, size_t))
140 DEFINE_COPY_FUNC(int, copyout, (const void *, void *, size_t))
141 DEFINE_COPY_FUNC(int, suword, (volatile void *, long))
142 DEFINE_COPY_FUNC(int, suword32, (volatile void *, int))
143 DEFINE_COPY_FUNC(int, suword64, (volatile void *, int64_t))
144 DEFINE_COPY_FUNC(int, fubyte, (volatile const void *))
145 DEFINE_COPY_FUNC(int, fuword16, (volatile const void *))
146 DEFINE_COPY_FUNC(int, fueword32, (volatile const void *, int32_t *))
147 DEFINE_COPY_FUNC(int, fueword64, (volatile const void *, int64_t *))
148 DEFINE_COPY_FUNC(int, fueword, (volatile const void *, long *))
149 DEFINE_COPY_FUNC(int, casueword32,
150     (volatile uint32_t *, uint32_t, uint32_t *, uint32_t))
151 DEFINE_COPY_FUNC(int, casueword, (volatile u_long *, u_long, u_long *, u_long))
152
153 #define REMAP(x)        x##_remap
154 #else
155 #define REMAP(x)        x
156 #endif
157
158 int
159 REMAP(copyout)(const void *kaddr, void *udaddr, size_t len)
160 {
161         struct          thread *td;
162         pmap_t          pm;
163         jmp_buf         env;
164         const char      *kp;
165         char            *up, *p;
166         size_t          l;
167
168         td = curthread;
169         pm = &td->td_proc->p_vmspace->vm_pmap;
170
171         td->td_pcb->pcb_onfault = &env;
172         if (setjmp(env)) {
173                 td->td_pcb->pcb_onfault = NULL;
174                 return (EFAULT);
175         }
176
177         kp = kaddr;
178         up = udaddr;
179
180         while (len > 0) {
181                 if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) {
182                         td->td_pcb->pcb_onfault = NULL;
183                         return (EFAULT);
184                 }
185
186                 bcopy(kp, p, l);
187
188                 up += l;
189                 kp += l;
190                 len -= l;
191         }
192
193         td->td_pcb->pcb_onfault = NULL;
194         return (0);
195 }
196
197 int
198 REMAP(copyin)(const void *udaddr, void *kaddr, size_t len)
199 {
200         struct          thread *td;
201         pmap_t          pm;
202         jmp_buf         env;
203         const char      *up;
204         char            *kp, *p;
205         size_t          l;
206
207         td = curthread;
208         pm = &td->td_proc->p_vmspace->vm_pmap;
209
210         td->td_pcb->pcb_onfault = &env;
211         if (setjmp(env)) {
212                 td->td_pcb->pcb_onfault = NULL;
213                 return (EFAULT);
214         }
215
216         kp = kaddr;
217         up = udaddr;
218
219         while (len > 0) {
220                 if (pmap_map_user_ptr(pm, up, (void **)&p, len, &l)) {
221                         td->td_pcb->pcb_onfault = NULL;
222                         return (EFAULT);
223                 }
224
225                 bcopy(p, kp, l);
226
227                 up += l;
228                 kp += l;
229                 len -= l;
230         }
231
232         td->td_pcb->pcb_onfault = NULL;
233         return (0);
234 }
235
236 int
237 REMAP(copyinstr)(const void *udaddr, void *kaddr, size_t len, size_t *done)
238 {
239         const char      *up;
240         char            *kp;
241         size_t          l;
242         int             rv, c;
243
244         kp = kaddr;
245         up = udaddr;
246
247         rv = ENAMETOOLONG;
248
249         for (l = 0; len-- > 0; l++) {
250                 if ((c = fubyte(up++)) < 0) {
251                         rv = EFAULT;
252                         break;
253                 }
254
255                 if (!(*kp++ = c)) {
256                         l++;
257                         rv = 0;
258                         break;
259                 }
260         }
261
262         if (done != NULL) {
263                 *done = l;
264         }
265
266         return (rv);
267 }
268
269 int
270 REMAP(subyte)(volatile void *addr, int byte)
271 {
272         struct          thread *td;
273         pmap_t          pm;
274         jmp_buf         env;
275         char            *p;
276
277         td = curthread;
278         pm = &td->td_proc->p_vmspace->vm_pmap;
279
280         td->td_pcb->pcb_onfault = &env;
281         if (setjmp(env)) {
282                 td->td_pcb->pcb_onfault = NULL;
283                 return (-1);
284         }
285
286         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
287                 td->td_pcb->pcb_onfault = NULL;
288                 return (-1);
289         }
290
291         *p = (char)byte;
292
293         td->td_pcb->pcb_onfault = NULL;
294         return (0);
295 }
296
297 #ifdef __powerpc64__
298 int
299 REMAP(suword32)(volatile void *addr, int word)
300 {
301         struct          thread *td;
302         pmap_t          pm;
303         jmp_buf         env;
304         int             *p;
305
306         td = curthread;
307         pm = &td->td_proc->p_vmspace->vm_pmap;
308
309         td->td_pcb->pcb_onfault = &env;
310         if (setjmp(env)) {
311                 td->td_pcb->pcb_onfault = NULL;
312                 return (-1);
313         }
314
315         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
316                 td->td_pcb->pcb_onfault = NULL;
317                 return (-1);
318         }
319
320         *p = word;
321
322         td->td_pcb->pcb_onfault = NULL;
323         return (0);
324 }
325 #else
326 int
327 REMAP(suword32)(volatile void *addr, int32_t word)
328 {
329 REMAP(  return (suword)(addr, (long)word));
330 }
331 #endif
332
333 int
334 REMAP(suword)(volatile void *addr, long word)
335 {
336         struct          thread *td;
337         pmap_t          pm;
338         jmp_buf         env;
339         long            *p;
340
341         td = curthread;
342         pm = &td->td_proc->p_vmspace->vm_pmap;
343
344         td->td_pcb->pcb_onfault = &env;
345         if (setjmp(env)) {
346                 td->td_pcb->pcb_onfault = NULL;
347                 return (-1);
348         }
349
350         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
351                 td->td_pcb->pcb_onfault = NULL;
352                 return (-1);
353         }
354
355         *p = word;
356
357         td->td_pcb->pcb_onfault = NULL;
358         return (0);
359 }
360
361 #ifdef __powerpc64__
362 int
363 REMAP(suword64)(volatile void *addr, int64_t word)
364 {
365         return (REMAP(suword)(addr, (long)word));
366 }
367 #endif
368
369 int
370 REMAP(fubyte)(volatile const void *addr)
371 {
372         struct          thread *td;
373         pmap_t          pm;
374         jmp_buf         env;
375         u_char          *p;
376         int             val;
377
378         td = curthread;
379         pm = &td->td_proc->p_vmspace->vm_pmap;
380
381         td->td_pcb->pcb_onfault = &env;
382         if (setjmp(env)) {
383                 td->td_pcb->pcb_onfault = NULL;
384                 return (-1);
385         }
386
387         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
388                 td->td_pcb->pcb_onfault = NULL;
389                 return (-1);
390         }
391
392         val = *p;
393
394         td->td_pcb->pcb_onfault = NULL;
395         return (val);
396 }
397
398 int
399 REMAP(fuword16)(volatile const void *addr)
400 {
401         struct          thread *td;
402         pmap_t          pm;
403         jmp_buf         env;
404         uint16_t        *p, val;
405
406         td = curthread;
407         pm = &td->td_proc->p_vmspace->vm_pmap;
408
409         td->td_pcb->pcb_onfault = &env;
410         if (setjmp(env)) {
411                 td->td_pcb->pcb_onfault = NULL;
412                 return (-1);
413         }
414
415         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
416                 td->td_pcb->pcb_onfault = NULL;
417                 return (-1);
418         }
419
420         val = *p;
421
422         td->td_pcb->pcb_onfault = NULL;
423         return (val);
424 }
425
426 int
427 REMAP(fueword32)(volatile const void *addr, int32_t *val)
428 {
429         struct          thread *td;
430         pmap_t          pm;
431         jmp_buf         env;
432         int32_t         *p;
433
434         td = curthread;
435         pm = &td->td_proc->p_vmspace->vm_pmap;
436
437         td->td_pcb->pcb_onfault = &env;
438         if (setjmp(env)) {
439                 td->td_pcb->pcb_onfault = NULL;
440                 return (-1);
441         }
442
443         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
444                 td->td_pcb->pcb_onfault = NULL;
445                 return (-1);
446         }
447
448         *val = *p;
449
450         td->td_pcb->pcb_onfault = NULL;
451         return (0);
452 }
453
454 #ifdef __powerpc64__
455 int
456 REMAP(fueword64)(volatile const void *addr, int64_t *val)
457 {
458         struct          thread *td;
459         pmap_t          pm;
460         jmp_buf         env;
461         int64_t         *p;
462
463         td = curthread;
464         pm = &td->td_proc->p_vmspace->vm_pmap;
465
466         td->td_pcb->pcb_onfault = &env;
467         if (setjmp(env)) {
468                 td->td_pcb->pcb_onfault = NULL;
469                 return (-1);
470         }
471
472         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
473                 td->td_pcb->pcb_onfault = NULL;
474                 return (-1);
475         }
476
477         *val = *p;
478
479         td->td_pcb->pcb_onfault = NULL;
480         return (0);
481 }
482 #endif
483
484 int
485 REMAP(fueword)(volatile const void *addr, long *val)
486 {
487         struct          thread *td;
488         pmap_t          pm;
489         jmp_buf         env;
490         long            *p;
491
492         td = curthread;
493         pm = &td->td_proc->p_vmspace->vm_pmap;
494
495         td->td_pcb->pcb_onfault = &env;
496         if (setjmp(env)) {
497                 td->td_pcb->pcb_onfault = NULL;
498                 return (-1);
499         }
500
501         if (pmap_map_user_ptr(pm, addr, (void **)&p, sizeof(*p), NULL)) {
502                 td->td_pcb->pcb_onfault = NULL;
503                 return (-1);
504         }
505
506         *val = *p;
507
508         td->td_pcb->pcb_onfault = NULL;
509         return (0);
510 }
511
512 int
513 REMAP(casueword32)(volatile uint32_t *addr, uint32_t old, uint32_t *oldvalp,
514     uint32_t new)
515 {
516         struct thread *td;
517         pmap_t pm;
518         jmp_buf         env;
519         uint32_t *p, val;
520         int res;
521
522         td = curthread;
523         pm = &td->td_proc->p_vmspace->vm_pmap;
524
525         td->td_pcb->pcb_onfault = &env;
526         if (setjmp(env)) {
527                 td->td_pcb->pcb_onfault = NULL;
528                 return (-1);
529         }
530
531         if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
532             sizeof(*p), NULL)) {
533                 td->td_pcb->pcb_onfault = NULL;
534                 return (-1);
535         }
536
537         res = 0;
538         __asm __volatile (
539                 "lwarx %0, 0, %3\n\t"           /* load old value */
540                 "cmplw %4, %0\n\t"              /* compare */
541                 "bne 1f\n\t"                    /* exit if not equal */
542                 "stwcx. %5, 0, %3\n\t"          /* attempt to store */
543                 "bne- 2f\n\t"                   /* if failed */
544                 "b 3f\n\t"                      /* we've succeeded */
545                 "1:\n\t"
546                 "stwcx. %0, 0, %3\n\t"          /* clear reservation (74xx) */
547                 "2:li %2, 1\n\t"
548                 "3:\n\t"
549                 : "=&r" (val), "=m" (*p), "+&r" (res)
550                 : "r" (p), "r" (old), "r" (new), "m" (*p)
551                 : "cr0", "memory");
552
553         td->td_pcb->pcb_onfault = NULL;
554
555         *oldvalp = val;
556         return (res);
557 }
558
559 #ifndef __powerpc64__
560 int
561 REMAP(casueword)(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
562 {
563
564         return (casueword32((volatile uint32_t *)addr, old,
565             (uint32_t *)oldvalp, new));
566 }
567 #else
568 int
569 REMAP(casueword)(volatile u_long *addr, u_long old, u_long *oldvalp, u_long new)
570 {
571         struct thread *td;
572         pmap_t pm;
573         jmp_buf         env;
574         u_long *p, val;
575         int res;
576
577         td = curthread;
578         pm = &td->td_proc->p_vmspace->vm_pmap;
579
580         td->td_pcb->pcb_onfault = &env;
581         if (setjmp(env)) {
582                 td->td_pcb->pcb_onfault = NULL;
583                 return (-1);
584         }
585
586         if (pmap_map_user_ptr(pm, (void *)(uintptr_t)addr, (void **)&p,
587             sizeof(*p), NULL)) {
588                 td->td_pcb->pcb_onfault = NULL;
589                 return (-1);
590         }
591
592         res = 0;
593         __asm __volatile (
594                 "ldarx %0, 0, %3\n\t"           /* load old value */
595                 "cmpld %4, %0\n\t"              /* compare */
596                 "bne 1f\n\t"                    /* exit if not equal */
597                 "stdcx. %5, 0, %3\n\t"          /* attempt to store */
598                 "bne- 2f\n\t"                   /* if failed */
599                 "b 3f\n\t"                      /* we've succeeded */
600                 "1:\n\t"
601                 "stdcx. %0, 0, %3\n\t"          /* clear reservation (74xx) */
602                 "2:li %2, 1\n\t"
603                 "3:\n\t"
604                 : "=&r" (val), "=m" (*p), "+&r" (res)
605                 : "r" (p), "r" (old), "r" (new), "m" (*p)
606                 : "cr0", "memory");
607
608         td->td_pcb->pcb_onfault = NULL;
609
610         *oldvalp = val;
611         return (res);
612 }
613 #endif