]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/arm/bcopyinout.S
Update libucl to latest git snapshot (20151027)
[FreeBSD/FreeBSD.git] / sys / arm / arm / bcopyinout.S
1 /*      $NetBSD: bcopyinout.S,v 1.11 2003/10/13 21:22:40 scw Exp $      */
2
3 /*-
4  * Copyright (c) 2002 Wasabi Systems, Inc.
5  * All rights reserved.
6  *
7  * Written by Allen Briggs for Wasabi Systems, Inc.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed for the NetBSD Project by
20  *      Wasabi Systems, Inc.
21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22  *    or promote products derived from this software without specific prior
23  *    written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37
38
39 #include "assym.s"
40
41 #include <machine/acle-compat.h>
42 #include <machine/asm.h>
43 #include <sys/errno.h>
44
45 .L_arm_memcpy:
46         .word   _C_LABEL(_arm_memcpy)
47 .L_min_memcpy_size:
48         .word   _C_LABEL(_min_memcpy_size)
49
50 __FBSDID("$FreeBSD$");
51 #ifdef _ARM_ARCH_5E
52 #include <arm/arm/bcopyinout_xscale.S>
53 #else
54
55         .text
56         .align  2
57
58 #if __ARM_ARCH >= 6
59 #define GET_PCB(tmp) \
60         mrc p15, 0, tmp, c13, c0, 4; \
61         add     tmp, tmp, #(TD_PCB)
62 #else
63 .Lcurpcb:
64         .word   _C_LABEL(__pcpu) + PC_CURPCB
65
66 #define GET_PCB(tmp) \
67         ldr     tmp, .Lcurpcb
68 #endif
69
70
71 #define SAVE_REGS       stmfd   sp!, {r4-r11}; _SAVE({r4-r11})
72 #define RESTORE_REGS    ldmfd   sp!, {r4-r11}
73
74 #if defined(_ARM_ARCH_5E)
75 #define HELLOCPP #
76 #define PREFETCH(rx,o)  pld     [ rx , HELLOCPP (o) ]
77 #else
78 #define PREFETCH(rx,o)
79 #endif
80
81 /*
82  * r0 = user space address
83  * r1 = kernel space address
84  * r2 = length
85  *
86  * Copies bytes from user space to kernel space
87  *
88  * We save/restore r4-r11:
89  * r4-r11 are scratch
90  */
91 ENTRY(copyin)
92         /* Quick exit if length is zero */
93         teq     r2, #0
94         moveq   r0, #0
95         RETeq
96
97         adds    r3, r0, r2
98         movcs   r0, #EFAULT
99         RETc(cs)
100
101         ldr     r12, =(VM_MAXUSER_ADDRESS + 1)
102         cmp     r3, r12
103         movcs   r0, #EFAULT
104         RETc(cs)
105
106         ldr     r3, .L_arm_memcpy
107         ldr     r3, [r3]
108         cmp     r3, #0
109         beq     .Lnormal
110         ldr     r3, .L_min_memcpy_size
111         ldr     r3, [r3]
112         cmp     r2, r3
113         blt     .Lnormal
114         stmfd   sp!, {r0-r2, r4, lr}
115         mov     r3, r0
116         mov     r0, r1
117         mov     r1, r3
118         mov     r3, #2 /* SRC_IS_USER */
119         ldr     r4, .L_arm_memcpy
120         mov     lr, pc
121         ldr     pc, [r4]
122         cmp     r0, #0
123         ldmfd   sp!, {r0-r2, r4, lr}
124         moveq   r0, #0
125         RETeq
126
127 .Lnormal:
128         SAVE_REGS
129         GET_PCB(r4)
130         ldr     r4, [r4]
131
132
133         ldr     r5, [r4, #PCB_ONFAULT]
134         adr     r3, .Lcopyfault
135         str     r3, [r4, #PCB_ONFAULT]
136
137         PREFETCH(r0, 0)
138         PREFETCH(r1, 0)
139
140         /*
141          * If not too many bytes, take the slow path.
142          */
143         cmp     r2, #0x08
144         blt     .Licleanup
145
146         /*
147          * Align destination to word boundary.
148          */
149         and     r6, r1, #0x3
150         ldr     pc, [pc, r6, lsl #2]
151         b       .Lialend
152         .word   .Lialend
153         .word   .Lial3
154         .word   .Lial2
155         .word   .Lial1
156 .Lial3: ldrbt   r6, [r0], #1
157         sub     r2, r2, #1
158         strb    r6, [r1], #1
159 .Lial2: ldrbt   r7, [r0], #1
160         sub     r2, r2, #1
161         strb    r7, [r1], #1
162 .Lial1: ldrbt   r6, [r0], #1
163         sub     r2, r2, #1
164         strb    r6, [r1], #1
165 .Lialend:
166
167         /*
168          * If few bytes left, finish slow.
169          */
170         cmp     r2, #0x08
171         blt     .Licleanup
172
173         /*
174          * If source is not aligned, finish slow.
175          */
176         ands    r3, r0, #0x03
177         bne     .Licleanup
178
179         cmp     r2, #0x60       /* Must be > 0x5f for unrolled cacheline */
180         blt     .Licleanup8
181
182         /*
183          * Align destination to cacheline boundary.
184          * If source and destination are nicely aligned, this can be a big
185          * win.  If not, it's still cheaper to copy in groups of 32 even if
186          * we don't get the nice cacheline alignment.
187          */
188         and     r6, r1, #0x1f
189         ldr     pc, [pc, r6]
190         b       .Licaligned
191         .word   .Licaligned
192         .word   .Lical28
193         .word   .Lical24
194         .word   .Lical20
195         .word   .Lical16
196         .word   .Lical12
197         .word   .Lical8
198         .word   .Lical4
199 .Lical28:ldrt   r6, [r0], #4
200         sub     r2, r2, #4
201         str     r6, [r1], #4
202 .Lical24:ldrt   r7, [r0], #4
203         sub     r2, r2, #4
204         str     r7, [r1], #4
205 .Lical20:ldrt   r6, [r0], #4
206         sub     r2, r2, #4
207         str     r6, [r1], #4
208 .Lical16:ldrt   r7, [r0], #4
209         sub     r2, r2, #4
210         str     r7, [r1], #4
211 .Lical12:ldrt   r6, [r0], #4
212         sub     r2, r2, #4
213         str     r6, [r1], #4
214 .Lical8:ldrt    r7, [r0], #4
215         sub     r2, r2, #4
216         str     r7, [r1], #4
217 .Lical4:ldrt    r6, [r0], #4
218         sub     r2, r2, #4
219         str     r6, [r1], #4
220
221         /*
222          * We start with > 0x40 bytes to copy (>= 0x60 got us into this
223          * part of the code, and we may have knocked that down by as much
224          * as 0x1c getting aligned).
225          *
226          * This loop basically works out to:
227          * do {
228          *      prefetch-next-cacheline(s)
229          *      bytes -= 0x20;
230          *      copy cacheline
231          * } while (bytes >= 0x40);
232          * bytes -= 0x20;
233          * copy cacheline
234          */
235 .Licaligned:
236         PREFETCH(r0, 32)
237         PREFETCH(r1, 32)
238
239         sub     r2, r2, #0x20
240
241         /* Copy a cacheline */
242         ldrt    r10, [r0], #4
243         ldrt    r11, [r0], #4
244         ldrt    r6, [r0], #4
245         ldrt    r7, [r0], #4
246         ldrt    r8, [r0], #4
247         ldrt    r9, [r0], #4
248         stmia   r1!, {r10-r11}
249         ldrt    r10, [r0], #4
250         ldrt    r11, [r0], #4
251         stmia   r1!, {r6-r11}
252
253         cmp     r2, #0x40
254         bge     .Licaligned
255
256         sub     r2, r2, #0x20
257
258         /* Copy a cacheline */
259         ldrt    r10, [r0], #4
260         ldrt    r11, [r0], #4
261         ldrt    r6, [r0], #4
262         ldrt    r7, [r0], #4
263         ldrt    r8, [r0], #4
264         ldrt    r9, [r0], #4
265         stmia   r1!, {r10-r11}
266         ldrt    r10, [r0], #4
267         ldrt    r11, [r0], #4
268         stmia   r1!, {r6-r11}
269
270         cmp     r2, #0x08
271         blt     .Liprecleanup
272
273 .Licleanup8:
274         ldrt    r8, [r0], #4
275         ldrt    r9, [r0], #4
276         sub     r2, r2, #8
277         stmia   r1!, {r8, r9}
278         cmp     r2, #8
279         bge     .Licleanup8
280
281 .Liprecleanup:
282         /*
283          * If we're done, bail.
284          */
285         cmp     r2, #0
286         beq     .Lout
287
288 .Licleanup:
289         and     r6, r2, #0x3
290         ldr     pc, [pc, r6, lsl #2]
291         b       .Licend
292         .word   .Lic4
293         .word   .Lic1
294         .word   .Lic2
295         .word   .Lic3
296 .Lic4:  ldrbt   r6, [r0], #1
297         sub     r2, r2, #1
298         strb    r6, [r1], #1
299 .Lic3:  ldrbt   r7, [r0], #1
300         sub     r2, r2, #1
301         strb    r7, [r1], #1
302 .Lic2:  ldrbt   r6, [r0], #1
303         sub     r2, r2, #1
304         strb    r6, [r1], #1
305 .Lic1:  ldrbt   r7, [r0], #1
306         subs    r2, r2, #1
307         strb    r7, [r1], #1
308 .Licend:
309         bne     .Licleanup
310
311 .Liout:
312         mov     r0, #0
313
314         str     r5, [r4, #PCB_ONFAULT]
315         RESTORE_REGS
316
317         RET
318
319 .Lcopyfault:
320         ldr     r0, =EFAULT
321         str     r5, [r4, #PCB_ONFAULT]
322         RESTORE_REGS
323
324         RET
325 END(copyin)
326
327 /*
328  * r0 = kernel space address
329  * r1 = user space address
330  * r2 = length
331  *
332  * Copies bytes from kernel space to user space
333  *
334  * We save/restore r4-r11:
335  * r4-r11 are scratch
336  */
337
338 ENTRY(copyout)
339         /* Quick exit if length is zero */
340         teq     r2, #0
341         moveq   r0, #0
342         RETeq
343
344         adds    r3, r1, r2
345         movcs   r0, #EFAULT
346         RETc(cs)
347
348         ldr     r12, =(VM_MAXUSER_ADDRESS + 1)
349         cmp     r3, r12
350         movcs   r0, #EFAULT
351         RETc(cs)
352
353         ldr     r3, .L_arm_memcpy
354         ldr     r3, [r3]
355         cmp     r3, #0
356         beq     .Lnormale
357         ldr     r3, .L_min_memcpy_size
358         ldr     r3, [r3]
359         cmp     r2, r3
360         blt     .Lnormale
361         stmfd   sp!, {r0-r2, r4, lr}
362         _SAVE({r0-r2, r4, lr})
363         mov     r3, r0
364         mov     r0, r1
365         mov     r1, r3
366         mov     r3, #1 /* DST_IS_USER */
367         ldr     r4, .L_arm_memcpy
368         mov     lr, pc
369         ldr     pc, [r4]
370         cmp     r0, #0
371         ldmfd   sp!, {r0-r2, r4, lr}
372         moveq   r0, #0
373         RETeq
374
375 .Lnormale:
376         SAVE_REGS
377         GET_PCB(r4)
378         ldr     r4, [r4]
379
380         ldr     r5, [r4, #PCB_ONFAULT]
381         adr     r3, .Lcopyfault
382         str     r3, [r4, #PCB_ONFAULT]
383
384         PREFETCH(r0, 0)
385         PREFETCH(r1, 0)
386
387         /*
388          * If not too many bytes, take the slow path.
389          */
390         cmp     r2, #0x08
391         blt     .Lcleanup
392
393         /*
394          * Align destination to word boundary.
395          */
396         and     r6, r1, #0x3
397         ldr     pc, [pc, r6, lsl #2]
398         b       .Lalend
399         .word   .Lalend
400         .word   .Lal3
401         .word   .Lal2
402         .word   .Lal1
403 .Lal3:  ldrb    r6, [r0], #1
404         sub     r2, r2, #1
405         strbt   r6, [r1], #1
406 .Lal2:  ldrb    r7, [r0], #1
407         sub     r2, r2, #1
408         strbt   r7, [r1], #1
409 .Lal1:  ldrb    r6, [r0], #1
410         sub     r2, r2, #1
411         strbt   r6, [r1], #1
412 .Lalend:
413
414         /*
415          * If few bytes left, finish slow.
416          */
417         cmp     r2, #0x08
418         blt     .Lcleanup
419
420         /*
421          * If source is not aligned, finish slow.
422          */
423         ands    r3, r0, #0x03
424         bne     .Lcleanup
425
426         cmp     r2, #0x60       /* Must be > 0x5f for unrolled cacheline */
427         blt     .Lcleanup8
428
429         /*
430          * Align source & destination to cacheline boundary.
431          */
432         and     r6, r1, #0x1f
433         ldr     pc, [pc, r6]
434         b       .Lcaligned
435         .word   .Lcaligned
436         .word   .Lcal28
437         .word   .Lcal24
438         .word   .Lcal20
439         .word   .Lcal16
440         .word   .Lcal12
441         .word   .Lcal8
442         .word   .Lcal4
443 .Lcal28:ldr     r6, [r0], #4
444         sub     r2, r2, #4
445         strt    r6, [r1], #4
446 .Lcal24:ldr     r7, [r0], #4
447         sub     r2, r2, #4
448         strt    r7, [r1], #4
449 .Lcal20:ldr     r6, [r0], #4
450         sub     r2, r2, #4
451         strt    r6, [r1], #4
452 .Lcal16:ldr     r7, [r0], #4
453         sub     r2, r2, #4
454         strt    r7, [r1], #4
455 .Lcal12:ldr     r6, [r0], #4
456         sub     r2, r2, #4
457         strt    r6, [r1], #4
458 .Lcal8: ldr     r7, [r0], #4
459         sub     r2, r2, #4
460         strt    r7, [r1], #4
461 .Lcal4: ldr     r6, [r0], #4
462         sub     r2, r2, #4
463         strt    r6, [r1], #4
464
465         /*
466          * We start with > 0x40 bytes to copy (>= 0x60 got us into this
467          * part of the code, and we may have knocked that down by as much
468          * as 0x1c getting aligned).
469          *
470          * This loop basically works out to:
471          * do {
472          *      prefetch-next-cacheline(s)
473          *      bytes -= 0x20;
474          *      copy cacheline
475          * } while (bytes >= 0x40);
476          * bytes -= 0x20;
477          * copy cacheline
478          */
479 .Lcaligned:
480         PREFETCH(r0, 32)
481         PREFETCH(r1, 32)
482
483         sub     r2, r2, #0x20
484
485         /* Copy a cacheline */
486         ldmia   r0!, {r6-r11}
487         strt    r6, [r1], #4
488         strt    r7, [r1], #4
489         ldmia   r0!, {r6-r7}
490         strt    r8, [r1], #4
491         strt    r9, [r1], #4
492         strt    r10, [r1], #4
493         strt    r11, [r1], #4
494         strt    r6, [r1], #4
495         strt    r7, [r1], #4
496
497         cmp     r2, #0x40
498         bge     .Lcaligned
499
500         sub     r2, r2, #0x20
501
502         /* Copy a cacheline */
503         ldmia   r0!, {r6-r11}
504         strt    r6, [r1], #4
505         strt    r7, [r1], #4
506         ldmia   r0!, {r6-r7}
507         strt    r8, [r1], #4
508         strt    r9, [r1], #4
509         strt    r10, [r1], #4
510         strt    r11, [r1], #4
511         strt    r6, [r1], #4
512         strt    r7, [r1], #4
513
514         cmp     r2, #0x08
515         blt     .Lprecleanup
516
517 .Lcleanup8:
518         ldmia   r0!, {r8-r9}
519         sub     r2, r2, #8
520         strt    r8, [r1], #4
521         strt    r9, [r1], #4
522         cmp     r2, #8
523         bge     .Lcleanup8
524
525 .Lprecleanup:
526         /*
527          * If we're done, bail.
528          */
529         cmp     r2, #0
530         beq     .Lout
531
532 .Lcleanup:
533         and     r6, r2, #0x3
534         ldr     pc, [pc, r6, lsl #2]
535         b       .Lcend
536         .word   .Lc4
537         .word   .Lc1
538         .word   .Lc2
539         .word   .Lc3
540 .Lc4:   ldrb    r6, [r0], #1
541         sub     r2, r2, #1
542         strbt   r6, [r1], #1
543 .Lc3:   ldrb    r7, [r0], #1
544         sub     r2, r2, #1
545         strbt   r7, [r1], #1
546 .Lc2:   ldrb    r6, [r0], #1
547         sub     r2, r2, #1
548         strbt   r6, [r1], #1
549 .Lc1:   ldrb    r7, [r0], #1
550         subs    r2, r2, #1
551         strbt   r7, [r1], #1
552 .Lcend:
553         bne     .Lcleanup
554
555 .Lout:
556         mov     r0, #0
557
558         str     r5, [r4, #PCB_ONFAULT]
559         RESTORE_REGS
560
561         RET
562 END(copyout)
563 #endif
564
565 /*
566  * int badaddr_read_1(const uint8_t *src, uint8_t *dest)
567  *
568  * Copies a single 8-bit value from src to dest, returning 0 on success,
569  * else EFAULT if a page fault occurred.
570  */
571 ENTRY(badaddr_read_1)
572         GET_PCB(r2)
573         ldr     r2, [r2]
574
575         ldr     ip, [r2, #PCB_ONFAULT]
576         adr     r3, 1f
577         str     r3, [r2, #PCB_ONFAULT]
578         nop
579         nop
580         nop
581         ldrb    r3, [r0]
582         nop
583         nop
584         nop
585         strb    r3, [r1]
586         mov     r0, #0          /* No fault */
587 1:      str     ip, [r2, #PCB_ONFAULT]
588         RET
589 END(badaddr_read_1)
590
591 /*
592  * int badaddr_read_2(const uint16_t *src, uint16_t *dest)
593  *
594  * Copies a single 16-bit value from src to dest, returning 0 on success,
595  * else EFAULT if a page fault occurred.
596  */
597 ENTRY(badaddr_read_2)
598         GET_PCB(r2)
599         ldr     r2, [r2]
600
601         ldr     ip, [r2, #PCB_ONFAULT]
602         adr     r3, 1f
603         str     r3, [r2, #PCB_ONFAULT]
604         nop
605         nop
606         nop
607         ldrh    r3, [r0]
608         nop
609         nop
610         nop
611         strh    r3, [r1]
612         mov     r0, #0          /* No fault */
613 1:      str     ip, [r2, #PCB_ONFAULT]
614         RET
615 END(badaddr_read_2)
616
617 /*
618  * int badaddr_read_4(const uint32_t *src, uint32_t *dest)
619  *
620  * Copies a single 32-bit value from src to dest, returning 0 on success,
621  * else EFAULT if a page fault occurred.
622  */
623 ENTRY(badaddr_read_4)
624         GET_PCB(r2)
625         ldr     r2, [r2]
626
627         ldr     ip, [r2, #PCB_ONFAULT]
628         adr     r3, 1f
629         str     r3, [r2, #PCB_ONFAULT]
630         nop
631         nop
632         nop
633         ldr     r3, [r0]
634         nop
635         nop
636         nop
637         str     r3, [r1]
638         mov     r0, #0          /* No fault */
639 1:      str     ip, [r2, #PCB_ONFAULT]
640         RET
641 END(badaddr_read_4)
642