]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powerpc/support.S
MFV r368607:
[FreeBSD/FreeBSD.git] / sys / powerpc / powerpc / support.S
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018, Matthew Macy <mmacy@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$    
28  */
29
30 /*
31  * Assembly variants of various functions, for those that don't need generic C
32  * implementations.  Currently this includes:
33  *
34  * - Direct-access versions of copyin/copyout methods.
35  *   - These are used by Radix AIM pmap (ISA 3.0), and Book-E, to avoid
36  *     unnecessary pmap_map_usr_ptr() calls.
37  */
38
39 #include "assym.inc"
40 #include "opt_sched.h"
41
42 #include <sys/syscall.h>
43 #include <sys/errno.h>
44         
45 #include <machine/param.h>
46 #include <machine/asm.h>
47 #include <machine/spr.h>
48 #include <machine/trap.h>
49 #include <machine/vmparam.h>
50
51 #ifdef _CALL_ELF
52 .abiversion _CALL_ELF
53 #endif
54
55 #ifdef __powerpc64__
56 #define LOAD    ld
57 #define STORE   std
58 #define WORD    8
59 #define CMPI    cmpdi
60 #define CMPLI   cmpldi
61 /* log_2(8 * WORD) */
62 #define LOOP_LOG        6
63 #define LOG_WORD        3
64 #else
65 #define LOAD    lwz
66 #define STORE   stw
67 #define WORD    4
68 #define CMPI    cmpwi
69 #define CMPLI   cmplwi
70 /* log_2(8 * WORD) */
71 #define LOOP_LOG        5
72 #define LOG_WORD        2
73 #endif
74
75 #ifdef AIM
76 #define ENTRY_DIRECT(x) ENTRY(x ## _direct)
77 #define END_DIRECT(x)   END(x ## _direct)
78 #else
79 #define ENTRY_DIRECT(x) ENTRY(x)
80 #define END_DIRECT(x)   END(x)
81 #endif
82         
83 #ifdef __powerpc64__
84 #define PROLOGUE                ;\
85         mflr    %r0             ;\
86         std     %r0, 16(%r1)    ;\
87
88 #define EPILOGUE                ;\
89         ld      %r0, 16(%r1)    ;\
90         mtlr    %r0             ;\
91         blr                     ;\
92         nop
93
94 #define VALIDATE_TRUNCATE_ADDR_COPY     VALIDATE_ADDR_COPY
95 #define VALIDATE_ADDR_COPY(raddr, len)  \
96         srdi  %r0, raddr, 52            ;\
97         cmpwi %r0, 1                    ;\
98         bge-    copy_fault              ;\
99         nop
100
101 #define VALIDATE_ADDR_FUSU(raddr)       ;\
102         srdi  %r0, raddr, 52            ;\
103         cmpwi %r0, 1                    ;\
104         bge-    fusufault               ;\
105         nop
106
107 #else
108 #define PROLOGUE                ;\
109         mflr    %r0             ;\
110         stw     %r0, 4(%r1)     ;\
111
112 #define EPILOGUE                ;\
113         lwz     %r0, 4(%r1)     ;\
114         mtlr    %r0             ;\
115         blr                     ;\
116         nop
117
118 /* %r0 is temporary */
119 /*
120  * Validate address and length are valid.
121  * For VALIDATE_ADDR_COPY() have to account for wraparound.
122  */
123 #define VALIDATE_ADDR_COPY(raddr, len)          \
124         lis     %r0, VM_MAXUSER_ADDRESS@h       ;\
125         ori     %r0, %r0, VM_MAXUSER_ADDRESS@l  ;\
126         cmplw   %r0, raddr                      ;\
127         blt-    copy_fault                      ;\
128         add     %r0, raddr, len                 ;\
129         cmplw   7, %r0, raddr                   ;\
130         blt-    7, copy_fault                   ;\
131         mtcrf   0x80, %r0                       ;\
132         bt-     0, copy_fault                   ;\
133         nop
134
135 #define VALIDATE_TRUNCATE_ADDR_COPY(raddr, len)         \
136         lis     %r0, VM_MAXUSER_ADDRESS@h       ;\
137         ori     %r0, %r0, VM_MAXUSER_ADDRESS@l  ;\
138         cmplw   %r0, raddr                      ;\
139         blt-    copy_fault                      ;\
140         sub     %r0, %r0, raddr                 ;\
141         cmplw   len, %r0                        ;\
142         isel    len, len, %r0, 0                ;\
143
144 #define VALIDATE_ADDR_FUSU(raddr)               \
145         lis     %r0, VM_MAXUSER_ADDRESS@h       ;\
146         ori     %r0, %r0, VM_MAXUSER_ADDRESS@l  ;\
147         cmplw   %r0, raddr                      ;\
148         ble-    fusufault
149
150 #endif
151
152 #define PCPU(reg) mfsprg  reg, 0
153
154 #define SET_COPYFAULT(raddr, rpcb, len) \
155         VALIDATE_ADDR_COPY(raddr, len)  ;\
156         PCPU(%r9)                       ;\
157         li      %r0, COPYFAULT          ;\
158         LOAD    rpcb, PC_CURPCB(%r9)    ;\
159         STORE   %r0, PCB_ONFAULT(rpcb)  ;\
160
161 #define SET_COPYFAULT_TRUNCATE(raddr, rpcb, len)\
162         VALIDATE_TRUNCATE_ADDR_COPY(raddr, len) ;\
163         PCPU(%r9)                               ;\
164         li      %r0, COPYFAULT                  ;\
165         LOAD    rpcb, PC_CURPCB(%r9)            ;\
166         STORE   %r0, PCB_ONFAULT(rpcb)
167
168 #define SET_FUSUFAULT(raddr, rpcb)      \
169         VALIDATE_ADDR_FUSU(raddr)       ;\
170         PCPU(%r9)                       ;\
171         li      %r0, FUSUFAULT          ;\
172         LOAD    rpcb, PC_CURPCB(%r9)    ;\
173         STORE   %r0, PCB_ONFAULT(rpcb)
174
175 #define CLEAR_FAULT_NO_CLOBBER(rpcb)    \
176         PCPU(%r9)                       ;\
177         LOAD    rpcb, PC_CURPCB(%r9)    ;\
178         li      %r0, 0                  ;\
179         STORE   %r0, PCB_ONFAULT(rpcb)
180
181 #define CLEAR_FAULT(rpcb)               \
182         CLEAR_FAULT_NO_CLOBBER(rpcb)    ;\
183         li      %r3, 0
184
185 /*
186  *  bcopy(src, dst, len)
187  *        %r3  %r4  %r5
188  * 
189  *  %r7 is the pcb pointer
190  * 
191  *  %r0 and %r8-%r10 are volatile
192  *  %r11 and %r12 are generally volatile, used in linking and exception
193  *  handling.  Can be clobbered here.
194  *
195  * Does not allocate or use stack space, but clobbers all volatile registers.
196  */
197
198 #define rs      %r3
199 #define rd      %r4
200 #define rl      %r5
201
202 #define t1      %r6
203 #define t2      %r7
204 #define t3      %r8
205 #define t4      %r9
206 #define t5      %r10
207 #define t6      %r11
208 #define t7      %r12
209 #define t8      %r0
210
211 #define Thresh  WORD * 8
212 #define W4      3
213 #define W2      2
214 #define W1      1
215 #define WORDS(n)        (32 - LOG_WORD - W##n)
216 .text
217 ENTRY(bcopy_generic)
218         CMPLI   0, %r5, 0
219         beq     .Lend
220         dcbtst  0, rd
221         dcbt    0, rs
222         CMPLI   rl, Thresh
223         blt     .Lsmall
224         b       .Llarge
225 /* memcpy */
226 /* ... */
227 .Lsmall:                                /* < 8 words remaining */
228         mtcrf   0x3, rl
229 .Lsmall_start:
230         bf      WORDS(4), 0f
231         LOAD    t1, 0(rs)
232         LOAD    t2, WORD*1(rs)
233         LOAD    t3, WORD*2(rs)
234         LOAD    t4, WORD*3(rs)
235         addi    rs, rs, WORD*4
236         STORE   t1, 0(rd)
237         STORE   t2, WORD*1(rd)
238         STORE   t3, WORD*2(rd)
239         STORE   t4, WORD*3(rd)
240         addi    rd, rd, WORD*4
241 0:                                      /* < 4 words remaining */
242         bf      WORDS(2), 1f
243         LOAD    t1, 0(rs)
244         LOAD    t2, WORD*1(rs)
245         addi    rs, rs, WORD*2
246         STORE   t1, 0(rd)
247         STORE   t2, WORD*1(rd)
248         addi    rd, rd, WORD*2
249 1:                                      /* < 2 words remaining */
250         bf      WORDS(1), 2f
251         LOAD    t1, 0(rs)
252         addi    rs, rs, WORD
253         STORE   t1, 0(rd)
254         addi    rd, rd, WORD
255 2:                                      /* < 1 word remaining */
256 #ifdef __powerpc64__
257         bf      29, 3f
258         lwz     t1, 0(rs)
259         addi    rs, rs, 4
260         stw     t1, 0(rd)
261         addi    rd, rd, 4
262 3:                                      /* < 4 bytes remaining */
263 #endif
264         bf      30, 4f
265         lhz     t1, 0(rs)
266         addi    rs, rs, 2
267         sth     t1, 0(rd)
268         addi    rd, rd, 2
269 4:                                      /* < 2 bytes remaining */
270         bf      31, .Lout
271         lbz     t1, 0(rs)
272         addi    rs, rs, 1
273         stb     t1, 0(rd)
274         addi    rd, rd, 1
275         b       .Lout
276
277         .align 4
278 .Llarge:
279         neg     t3, rd
280         andi.   t6, t3, WORD-1          /* Align rd to word size */
281         mtctr   t6
282         sub     rl, rl, t6
283         beq+    .Llargealigned
284 1:
285         lbz     t1, 0(rs)
286         addi    rs, rs, 1
287         stb     t1, 0(rd)
288         addi    rd, rd, 1
289         bdnz    1b
290
291 .Llargealigned:
292         srwi.   t2, rl, LOOP_LOG  /* length >> log_2(loop_size) => 8W iterations */
293         mtcrf   0x3, rl
294         beq     .Lsmall_start
295         mtctr   t2
296         b       1f
297
298         .align 5
299 1:
300         LOAD    t1, 0(rs)
301         LOAD    t2, WORD(rs)
302         LOAD    t3, WORD*2(rs)
303         LOAD    t4, WORD*3(rs)
304         LOAD    t5, WORD*4(rs)
305         LOAD    t6, WORD*5(rs)
306         LOAD    t7, WORD*6(rs)
307         LOAD    t8, WORD*7(rs)
308         addi    rs, rs, WORD*8
309         STORE   t1, 0(rd)
310         STORE   t2, WORD*1(rd)
311         STORE   t3, WORD*2(rd)
312         STORE   t4, WORD*3(rd)
313         STORE   t5, WORD*4(rd)
314         STORE   t6, WORD*5(rd)
315         STORE   t7, WORD*6(rd)
316         STORE   t8, WORD*7(rd)
317         addi    rd, rd, WORD*8
318         bdnz    1b
319
320         b       .Lsmall_start
321 .Lout:
322 /* done */      
323 .Lend:  
324         blr
325 END(bcopy_generic)
326
327 /*
328  * copyout(from_kernel, to_user, len)
329  *         %r3,        %r4,    %r5
330  */
331 ENTRY_DIRECT(copyout)
332         PROLOGUE
333         SET_COPYFAULT(%r4, %r7, %r5)
334         bl bcopy_generic 
335         nop
336         CLEAR_FAULT(%r7)
337         EPILOGUE
338 END_DIRECT(copyout)
339
340 /*
341  * copyin(from_user, to_kernel, len)
342  *        %r3,        %r4,    %r5
343  */
344 ENTRY_DIRECT(copyin)
345         PROLOGUE
346         SET_COPYFAULT(%r3, %r7, %r5)
347         bl bcopy_generic
348         nop
349         CLEAR_FAULT(%r7)
350         EPILOGUE
351 END_DIRECT(copyin)
352
353 /*
354  * copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
355  *                      %r3          %r4         %r5        %r6 
356  */
357         
358 ENTRY_DIRECT(copyinstr)
359         PROLOGUE
360         SET_COPYFAULT_TRUNCATE(%r3, %r7, %r5)
361         addi    %r9, %r5, 1
362         mtctr   %r9
363         mr      %r8, %r3
364         addi    %r8, %r8, -1
365         addi    %r4, %r4, -1
366         li      %r3, ENAMETOOLONG
367 0:
368         bdz-    2f
369         lbzu    %r0, 1(%r8)
370         stbu    %r0, 1(%r4)
371
372         // NULL byte reached ?
373         CMPI    %r0, 0
374         beq-    1f
375         b       0b
376 1:
377         li      %r3, 0
378 2:
379         /* skip storing length if done is NULL */
380         CMPI    %r6, 0
381         beq-    3f
382         mfctr   %r0
383         sub     %r0, %r9, %r0
384         STORE   %r0, 0(%r6)
385 3:
386         CLEAR_FAULT_NO_CLOBBER(%r7)
387         EPILOGUE
388 END_DIRECT(copyinstr)
389
390 ENTRY_DIRECT(subyte)
391         PROLOGUE
392         SET_FUSUFAULT(%r3, %r7)
393         stb  %r4, 0(%r3)
394         CLEAR_FAULT(%r7)
395         EPILOGUE
396 END_DIRECT(subyte)
397
398 #ifndef __powerpc64__
399 ENTRY_DIRECT(suword)
400         PROLOGUE
401         SET_FUSUFAULT(%r3, %r7)
402         stw  %r4, 0(%r3)
403         CLEAR_FAULT(%r7)
404         EPILOGUE
405 END_DIRECT(suword)
406 #endif  
407
408 ENTRY_DIRECT(suword32)
409         PROLOGUE
410         SET_FUSUFAULT(%r3, %r7)
411         stw  %r4, 0(%r3)
412         CLEAR_FAULT(%r7)
413         EPILOGUE
414 END_DIRECT(suword32)
415
416 #ifdef __powerpc64__    
417 ENTRY_DIRECT(suword64)
418         PROLOGUE
419         SET_FUSUFAULT(%r3, %r7)
420         std  %r4, 0(%r3) 
421         CLEAR_FAULT(%r7)
422         EPILOGUE
423 END_DIRECT(suword64)
424
425 ENTRY_DIRECT(suword)
426         PROLOGUE
427         SET_FUSUFAULT(%r3, %r7)
428         std  %r4, 0(%r3) 
429         CLEAR_FAULT(%r7)
430         EPILOGUE
431 END_DIRECT(suword)
432 #endif  
433         
434 ENTRY_DIRECT(fubyte)
435         PROLOGUE
436         SET_FUSUFAULT(%r3, %r7)
437         lbz %r3, 0(%r3)
438         CLEAR_FAULT_NO_CLOBBER(%r7)
439         EPILOGUE
440 END_DIRECT(fubyte)
441
442 ENTRY_DIRECT(fuword16)
443         PROLOGUE
444         SET_FUSUFAULT(%r3, %r7)
445         lhz %r3, 0(%r3)
446         CLEAR_FAULT_NO_CLOBBER(%r7)
447         EPILOGUE
448 END_DIRECT(fuword16)
449
450 #ifndef __powerpc64__
451 ENTRY_DIRECT(fueword)   
452         PROLOGUE
453         SET_FUSUFAULT(%r3, %r7)
454         lwz  %r0, 0(%r3)
455         stw  %r0,  0(%r4)
456         CLEAR_FAULT(%r7)
457         EPILOGUE
458 END_DIRECT(fueword)     
459 #endif  
460 ENTRY_DIRECT(fueword32)
461         PROLOGUE
462         SET_FUSUFAULT(%r3, %r7)
463         lwz  %r0, 0(%r3)
464         stw  %r0,  0(%r4)
465         CLEAR_FAULT(%r7)
466         EPILOGUE
467 END_DIRECT(fueword32)
468
469 #ifdef __powerpc64__
470 ENTRY_DIRECT(fueword)   
471         PROLOGUE
472         SET_FUSUFAULT(%r3, %r7)
473         ld  %r0, 0(%r3)
474         std %r0, 0(%r4)
475         CLEAR_FAULT(%r7)
476         EPILOGUE
477 END_DIRECT(fueword)     
478
479 ENTRY_DIRECT(fueword64)
480         PROLOGUE
481         SET_FUSUFAULT(%r3, %r7)
482         ld  %r0, 0(%r3)
483         std %r0, 0(%r4)
484         CLEAR_FAULT(%r7)
485         EPILOGUE
486 END_DIRECT(fueword64)
487 #endif
488
489 /*
490  * casueword(volatile u_long *base, u_long old, u_long *oldp, u_long new)
491  *                            %r3          %r4           %r5         %r6 
492  */
493
494 #define CASUEWORD32(raddr, rpcb)                                        ;\
495         PROLOGUE                                                        ;\
496         SET_FUSUFAULT(raddr, rpcb)                                      ;\
497         li      %r8, 0                                                  ;\
498 1:                                                                      ;\
499         lwarx   %r0, 0, %r3                                             ;\
500         cmplw   %r4, %r0                                                ;\
501         bne     2f                                                      ;\
502         stwcx.  %r6, 0, %r3                                             ;\
503         bne-    3f                                                      ;\
504         b       4f                                                      ;\
505 2:                                                                      ;\
506         stwcx.  %r0, 0, %r3             /* clear reservation (74xx) */  ;\
507 3:                                                                      ;\
508         li      %r8, 1                                                  ;\
509 4:                                                                      ;\
510         stw     %r0, 0(%r5)                                             ;\
511         CLEAR_FAULT_NO_CLOBBER(rpcb)                                    ;\
512         mr      %r3, %r8                                                ;\
513         EPILOGUE        
514         
515 ENTRY_DIRECT(casueword32)
516         CASUEWORD32(%r3, %r7)
517 END_DIRECT(casueword32)
518
519 #ifdef __powerpc64__
520 #define CASUEWORD64(raddr, rpcb)                                        ;\
521         PROLOGUE                                                        ;\
522         SET_FUSUFAULT(raddr, rpcb)                                      ;\
523         li      %r8, 0                                                  ;\
524 1:                                                                      ;\
525         ldarx   %r0, 0, %r3                                             ;\
526         cmpld   %r4, %r0                                                ;\
527         bne     2f                                                      ;\
528         stdcx.  %r6, 0, %r3                                             ;\
529         bne-    3f                                                      ;\
530         b       4f                                                      ;\
531 2:                                                                      ;\
532         stdcx.  %r0, 0, %r3             /* clear reservation (74xx) */  ;\
533 3:                                                                      ;\
534         li      %r8, 1                                                  ;\
535 4:                                                                      ;\
536         std     %r0, 0(%r5)                                             ;\
537         CLEAR_FAULT_NO_CLOBBER(rpcb)                                    ;\
538         mr      %r3, %r8                                                ;\
539         EPILOGUE
540
541 ENTRY_DIRECT(casueword)
542         CASUEWORD64(%r3, %r7)
543 END_DIRECT(casueword)
544
545 ENTRY_DIRECT(casueword64)
546         CASUEWORD64(%r3, %r7)
547 END_DIRECT(casueword64)
548 #else
549 ENTRY_DIRECT(casueword)
550         CASUEWORD32(%r3, %r7)
551 END_DIRECT(casueword)
552 #endif
553         
554 _NAKED_ENTRY(fusufault)
555         CLEAR_FAULT_NO_CLOBBER(%r7)
556         li %r3, -1
557         EPILOGUE
558 _END(fusufault)
559
560 _NAKED_ENTRY(copy_fault)
561         CLEAR_FAULT_NO_CLOBBER(%r7)
562         li %r3, EFAULT
563         EPILOGUE
564 _END(copy_fault)