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