]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/powerpc/powerpc/support.S
Update to bmake-20200902
[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 #else
78 #define ENTRY_DIRECT(x) ENTRY(x)
79 #endif
80         
81 #ifdef __powerpc64__
82 #define PROLOGUE                ;\
83         mflr    %r0             ;\
84         std     %r0, 16(%r1)    ;\
85
86 #define EPILOGUE                ;\
87         ld      %r0, 16(%r1)    ;\
88         mtlr    %r0             ;\
89         blr                     ;\
90         nop
91
92 #define VALIDATE_TRUNCATE_ADDR_COPY     VALIDATE_ADDR_COPY
93 #define VALIDATE_ADDR_COPY(raddr, len)  \
94         srdi  %r0, raddr, 52            ;\
95         cmpwi %r0, 1                    ;\
96         bge-    copy_fault              ;\
97         nop
98
99 #define VALIDATE_ADDR_FUSU(raddr)       ;\
100         srdi  %r0, raddr, 52            ;\
101         cmpwi %r0, 1                    ;\
102         bge-    fusufault               ;\
103         nop
104
105 #else
106 #define PROLOGUE                ;\
107         mflr    %r0             ;\
108         stw     %r0, 4(%r1)     ;\
109
110 #define EPILOGUE                ;\
111         lwz     %r0, 4(%r1)     ;\
112         mtlr    %r0             ;\
113         blr                     ;\
114         nop
115
116 /* %r0 is temporary */
117 /*
118  * Validate address and length are valid.
119  * For VALIDATE_ADDR_COPY() have to account for wraparound.
120  */
121 #define VALIDATE_ADDR_COPY(raddr, len)          \
122         lis     %r0, VM_MAXUSER_ADDRESS@h       ;\
123         ori     %r0, %r0, VM_MAXUSER_ADDRESS@l  ;\
124         cmplw   %r0, raddr                      ;\
125         blt-    copy_fault                      ;\
126         add     %r0, raddr, len                 ;\
127         cmplw   7, %r0, raddr                   ;\
128         blt-    7, copy_fault                   ;\
129         mtcrf   0x80, %r0                       ;\
130         bt-     0, copy_fault                   ;\
131         nop
132
133 #define VALIDATE_TRUNCATE_ADDR_COPY(raddr, len)         \
134         lis     %r0, VM_MAXUSER_ADDRESS@h       ;\
135         ori     %r0, %r0, VM_MAXUSER_ADDRESS@l  ;\
136         cmplw   %r0, raddr                      ;\
137         blt-    copy_fault                      ;\
138         sub     %r0, %r0, raddr                 ;\
139         cmplw   len, %r0                        ;\
140         isel    len, len, %r0, 0                ;\
141
142 #define VALIDATE_ADDR_FUSU(raddr)               \
143         lis     %r0, VM_MAXUSER_ADDRESS@h       ;\
144         ori     %r0, %r0, VM_MAXUSER_ADDRESS@l  ;\
145         cmplw   %r0, raddr                      ;\
146         ble-    fusufault
147
148 #endif
149
150 #define PCPU(reg) mfsprg  reg, 0
151
152 #define SET_COPYFAULT(raddr, rpcb, len) \
153         VALIDATE_ADDR_COPY(raddr, len)  ;\
154         PCPU(%r9)                       ;\
155         li      %r0, COPYFAULT          ;\
156         LOAD    rpcb, PC_CURPCB(%r9)    ;\
157         STORE   %r0, PCB_ONFAULT(rpcb)  ;\
158
159 #define SET_COPYFAULT_TRUNCATE(raddr, rpcb, len)\
160         VALIDATE_TRUNCATE_ADDR_COPY(raddr, len) ;\
161         PCPU(%r9)                               ;\
162         li      %r0, COPYFAULT                  ;\
163         LOAD    rpcb, PC_CURPCB(%r9)            ;\
164         STORE   %r0, PCB_ONFAULT(rpcb)
165
166 #define SET_FUSUFAULT(raddr, rpcb)      \
167         VALIDATE_ADDR_FUSU(raddr)       ;\
168         PCPU(%r9)                       ;\
169         li      %r0, FUSUFAULT          ;\
170         LOAD    rpcb, PC_CURPCB(%r9)    ;\
171         STORE   %r0, PCB_ONFAULT(rpcb)
172
173 #define CLEAR_FAULT_NO_CLOBBER(rpcb)    \
174         PCPU(%r9)                       ;\
175         LOAD    rpcb, PC_CURPCB(%r9)    ;\
176         li      %r0, 0                  ;\
177         STORE   %r0, PCB_ONFAULT(rpcb)
178
179 #define CLEAR_FAULT(rpcb)               \
180         CLEAR_FAULT_NO_CLOBBER(rpcb)    ;\
181         li      %r3, 0
182
183 /*
184  *  bcopy(src, dst, len)
185  *        %r3  %r4  %r5
186  * 
187  *  %r7 is the pcb pointer
188  * 
189  *  %r0 and %r8-%r10 are volatile
190  *  %r11 and %r12 are generally volatile, used in linking and exception
191  *  handling.  Can be clobbered here.
192  *
193  * Does not allocate or use stack space, but clobbers all volatile registers.
194  */
195
196 #define rs      %r3
197 #define rd      %r4
198 #define rl      %r5
199
200 #define t1      %r6
201 #define t2      %r7
202 #define t3      %r8
203 #define t4      %r9
204 #define t5      %r10
205 #define t6      %r11
206 #define t7      %r12
207 #define t8      %r0
208
209 #define Thresh  WORD * 8
210 #define W4      3
211 #define W2      2
212 #define W1      1
213 #define WORDS(n)        (32 - LOG_WORD - W##n)
214 .text
215 ENTRY(bcopy_generic)
216         CMPLI   0, %r5, 0
217         beq     .Lend
218         dcbtst  0, rd
219         dcbt    0, rs
220         CMPLI   rl, Thresh
221         blt     .Lsmall
222         b       .Llarge
223 /* memcpy */
224 /* ... */
225 .Lsmall:                                /* < 8 words remaining */
226         mtcrf   0x3, rl
227 .Lsmall_start:
228         bf      WORDS(4), 0f
229         LOAD    t1, 0(rs)
230         LOAD    t2, WORD*1(rs)
231         LOAD    t3, WORD*2(rs)
232         LOAD    t4, WORD*3(rs)
233         addi    rs, rs, WORD*4
234         STORE   t1, 0(rd)
235         STORE   t2, WORD*1(rd)
236         STORE   t3, WORD*2(rd)
237         STORE   t4, WORD*3(rd)
238         addi    rd, rd, WORD*4
239 0:                                      /* < 4 words remaining */
240         bf      WORDS(2), 1f
241         LOAD    t1, 0(rs)
242         LOAD    t2, WORD*1(rs)
243         addi    rs, rs, WORD*2
244         STORE   t1, 0(rd)
245         STORE   t2, WORD*1(rd)
246         addi    rd, rd, WORD*2
247 1:                                      /* < 2 words remaining */
248         bf      WORDS(1), 2f
249         LOAD    t1, 0(rs)
250         addi    rs, rs, WORD
251         STORE   t1, 0(rd)
252         addi    rd, rd, WORD
253 2:                                      /* < 1 word remaining */
254 #ifdef __powerpc64__
255         bf      29, 3f
256         lwz     t1, 0(rs)
257         addi    rs, rs, 4
258         stw     t1, 0(rd)
259         addi    rd, rd, 4
260 3:                                      /* < 4 bytes remaining */
261 #endif
262         bf      30, 4f
263         lhz     t1, 0(rs)
264         addi    rs, rs, 2
265         sth     t1, 0(rd)
266         addi    rd, rd, 2
267 4:                                      /* < 2 bytes remaining */
268         bf      31, .Lout
269         lbz     t1, 0(rs)
270         addi    rs, rs, 1
271         stb     t1, 0(rd)
272         addi    rd, rd, 1
273         b       .Lout
274
275         .align 4
276 .Llarge:
277         neg     t3, rd
278         andi.   t6, t3, WORD-1          /* Align rd to word size */
279         mtctr   t6
280         sub     rl, rl, t6
281         beq+    .Llargealigned
282 1:
283         lbz     t1, 0(rs)
284         addi    rs, rs, 1
285         stb     t1, 0(rd)
286         addi    rd, rd, 1
287         bdnz    1b
288
289 .Llargealigned:
290         srwi.   t2, rl, LOOP_LOG  /* length >> log_2(loop_size) => 8W iterations */
291         mtcrf   0x3, rl
292         beq     .Lsmall_start
293         mtctr   t2
294         b       1f
295
296         .align 5
297 1:
298         LOAD    t1, 0(rs)
299         LOAD    t2, WORD(rs)
300         LOAD    t3, WORD*2(rs)
301         LOAD    t4, WORD*3(rs)
302         LOAD    t5, WORD*4(rs)
303         LOAD    t6, WORD*5(rs)
304         LOAD    t7, WORD*6(rs)
305         LOAD    t8, WORD*7(rs)
306         addi    rs, rs, WORD*8
307         STORE   t1, 0(rd)
308         STORE   t2, WORD*1(rd)
309         STORE   t3, WORD*2(rd)
310         STORE   t4, WORD*3(rd)
311         STORE   t5, WORD*4(rd)
312         STORE   t6, WORD*5(rd)
313         STORE   t7, WORD*6(rd)
314         STORE   t8, WORD*7(rd)
315         addi    rd, rd, WORD*8
316         bdnz    1b
317
318         b       .Lsmall_start
319 .Lout:
320 /* done */      
321 .Lend:  
322         blr
323
324 /*
325  * copyout(from_kernel, to_user, len)
326  *         %r3,        %r4,    %r5
327  */
328 ENTRY_DIRECT(copyout)
329         PROLOGUE
330         SET_COPYFAULT(%r4, %r7, %r5)
331         bl bcopy_generic 
332         nop
333         CLEAR_FAULT(%r7)
334         EPILOGUE
335
336 /*
337  * copyin(from_user, to_kernel, len)
338  *        %r3,        %r4,    %r5
339  */
340 ENTRY_DIRECT(copyin)
341         PROLOGUE
342         SET_COPYFAULT(%r3, %r7, %r5)
343         bl bcopy_generic
344         nop
345         CLEAR_FAULT(%r7)
346         EPILOGUE
347 /*
348  * copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
349  *                      %r3          %r4         %r5        %r6 
350  */
351         
352 ENTRY_DIRECT(copyinstr)
353         PROLOGUE
354         SET_COPYFAULT_TRUNCATE(%r3, %r7, %r5)
355         addi    %r9, %r5, 1
356         mtctr   %r9
357         mr      %r8, %r3
358         addi    %r8, %r8, -1
359         addi    %r4, %r4, -1
360         li      %r3, ENAMETOOLONG
361 0:
362         bdz-    2f
363         lbzu    %r0, 1(%r8)
364         stbu    %r0, 1(%r4)
365
366         // NULL byte reached ?
367         CMPI    %r0, 0
368         beq-    1f
369         b       0b
370 1:
371         li      %r3, 0
372 2:
373         /* skip storing length if done is NULL */
374         CMPI    %r6, 0
375         beq-    3f
376         mfctr   %r0
377         sub     %r0, %r9, %r0
378         STORE   %r0, 0(%r6)
379 3:
380         CLEAR_FAULT_NO_CLOBBER(%r7)
381         EPILOGUE
382
383 ENTRY_DIRECT(subyte)
384         PROLOGUE
385         SET_FUSUFAULT(%r3, %r7)
386         stb  %r4, 0(%r3)
387         CLEAR_FAULT(%r7)
388         EPILOGUE
389
390 #ifndef __powerpc64__
391 ENTRY_DIRECT(suword)
392         PROLOGUE
393         SET_FUSUFAULT(%r3, %r7)
394         stw  %r4, 0(%r3)
395         CLEAR_FAULT(%r7)
396         EPILOGUE
397 #endif  
398
399 ENTRY_DIRECT(suword32)
400         PROLOGUE
401         SET_FUSUFAULT(%r3, %r7)
402         stw  %r4, 0(%r3)
403         CLEAR_FAULT(%r7)
404         EPILOGUE
405
406 #ifdef __powerpc64__    
407 ENTRY_DIRECT(suword64)
408         PROLOGUE
409         SET_FUSUFAULT(%r3, %r7)
410         std  %r4, 0(%r3) 
411         CLEAR_FAULT(%r7)
412         EPILOGUE
413 ENTRY_DIRECT(suword)
414         PROLOGUE
415         SET_FUSUFAULT(%r3, %r7)
416         std  %r4, 0(%r3) 
417         CLEAR_FAULT(%r7)
418         EPILOGUE
419 #endif  
420         
421 ENTRY_DIRECT(fubyte)
422         PROLOGUE
423         SET_FUSUFAULT(%r3, %r7)
424         lbz %r3, 0(%r3)
425         CLEAR_FAULT_NO_CLOBBER(%r7)
426         EPILOGUE
427
428 ENTRY_DIRECT(fuword16)
429         PROLOGUE
430         SET_FUSUFAULT(%r3, %r7)
431         lhz %r3, 0(%r3)
432         CLEAR_FAULT_NO_CLOBBER(%r7)
433         EPILOGUE
434
435 #ifndef __powerpc64__
436 ENTRY_DIRECT(fueword)   
437         PROLOGUE
438         SET_FUSUFAULT(%r3, %r7)
439         lwz  %r0, 0(%r3)
440         stw  %r0,  0(%r4)
441         CLEAR_FAULT(%r7)
442         EPILOGUE
443 #endif  
444 ENTRY_DIRECT(fueword32)
445         PROLOGUE
446         SET_FUSUFAULT(%r3, %r7)
447         lwz  %r0, 0(%r3)
448         stw  %r0,  0(%r4)
449         CLEAR_FAULT(%r7)
450         EPILOGUE
451
452 #ifdef __powerpc64__
453 ENTRY_DIRECT(fueword)   
454         PROLOGUE
455         SET_FUSUFAULT(%r3, %r7)
456         ld  %r0, 0(%r3)
457         std %r0, 0(%r4)
458         CLEAR_FAULT(%r7)
459         EPILOGUE
460
461 ENTRY_DIRECT(fueword64)
462         PROLOGUE
463         SET_FUSUFAULT(%r3, %r7)
464         ld  %r0, 0(%r3)
465         std %r0, 0(%r4)
466         CLEAR_FAULT(%r7)
467         EPILOGUE
468 #endif
469
470 /*
471  * casueword(volatile u_long *base, u_long old, u_long *oldp, u_long new)
472  *                            %r3          %r4           %r5         %r6 
473  */
474
475 #define CASUEWORD32(raddr, rpcb)                                        ;\
476         PROLOGUE                                                        ;\
477         SET_FUSUFAULT(raddr, rpcb)                                      ;\
478         li      %r8, 0                                                  ;\
479 1:                                                                      ;\
480         lwarx   %r0, 0, %r3                                             ;\
481         cmplw   %r4, %r0                                                ;\
482         bne     2f                                                      ;\
483         stwcx.  %r6, 0, %r3                                             ;\
484         bne-    3f                                                      ;\
485         b       4f                                                      ;\
486 2:                                                                      ;\
487         stwcx.  %r0, 0, %r3             /* clear reservation (74xx) */  ;\
488 3:                                                                      ;\
489         li      %r8, 1                                                  ;\
490 4:                                                                      ;\
491         stw     %r0, 0(%r5)                                             ;\
492         CLEAR_FAULT_NO_CLOBBER(rpcb)                                    ;\
493         mr      %r3, %r8                                                ;\
494         EPILOGUE        
495         
496 ENTRY_DIRECT(casueword32)
497         CASUEWORD32(%r3, %r7)
498
499 #ifdef __powerpc64__
500 #define CASUEWORD64(raddr, rpcb)                                        ;\
501         PROLOGUE                                                        ;\
502         SET_FUSUFAULT(raddr, rpcb)                                      ;\
503         li      %r8, 0                                                  ;\
504 1:                                                                      ;\
505         ldarx   %r0, 0, %r3                                             ;\
506         cmpld   %r4, %r0                                                ;\
507         bne     2f                                                      ;\
508         stdcx.  %r6, 0, %r3                                             ;\
509         bne-    3f                                                      ;\
510         b       4f                                                      ;\
511 2:                                                                      ;\
512         stdcx.  %r0, 0, %r3             /* clear reservation (74xx) */  ;\
513 3:                                                                      ;\
514         li      %r8, 1                                                  ;\
515 4:                                                                      ;\
516         std     %r0, 0(%r5)                                             ;\
517         CLEAR_FAULT_NO_CLOBBER(rpcb)                                    ;\
518         mr      %r3, %r8                                                ;\
519         EPILOGUE
520
521 ENTRY_DIRECT(casueword)
522         CASUEWORD64(%r3, %r7)
523
524 ENTRY_DIRECT(casueword64)
525         CASUEWORD64(%r3, %r7)
526 #else
527 ENTRY_DIRECT(casueword)
528         CASUEWORD32(%r3, %r7)
529 #endif
530         
531 _NAKED_ENTRY(fusufault)
532         CLEAR_FAULT_NO_CLOBBER(%r7)
533         li %r3, -1
534         EPILOGUE
535
536 _NAKED_ENTRY(copy_fault)
537         CLEAR_FAULT_NO_CLOBBER(%r7)
538         li %r3, EFAULT
539         EPILOGUE