xref: /freebsd/sys/powerpc/powerpc/support.S (revision 4e8d558c)
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
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
213ENTRY(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
2370:					/* < 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
2451:					/* < 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
2512:					/* < 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
2583:					/* < 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
2654:					/* < 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
2801:
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
2951:
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
321END(bcopy_generic)
322
323/*
324 * copyout(from_kernel, to_user, len)
325 *         %r3,        %r4,    %r5
326 */
327ENTRY_DIRECT(copyout)
328	PROLOGUE
329	SET_COPYFAULT(%r4, %r7, %r5)
330	bl bcopy_generic
331	nop
332	CLEAR_FAULT(%r7)
333	EPILOGUE
334END_DIRECT(copyout)
335
336/*
337 * copyin(from_user, to_kernel, len)
338 *        %r3,        %r4,    %r5
339 */
340ENTRY_DIRECT(copyin)
341	PROLOGUE
342	SET_COPYFAULT(%r3, %r7, %r5)
343	bl bcopy_generic
344	nop
345	CLEAR_FAULT(%r7)
346	EPILOGUE
347END_DIRECT(copyin)
348
349/*
350 * copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
351 *			%r3          %r4         %r5        %r6
352 */
353
354ENTRY_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
3630:
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
3721:
373	li	%r3, 0
3742:
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)
3813:
382	CLEAR_FAULT_NO_CLOBBER(%r7)
383	EPILOGUE
384END_DIRECT(copyinstr)
385
386ENTRY_DIRECT(subyte)
387	PROLOGUE
388	SET_FUSUFAULT(%r3, %r7)
389	stb  %r4, 0(%r3)
390	CLEAR_FAULT(%r7)
391	EPILOGUE
392END_DIRECT(subyte)
393
394#ifndef __powerpc64__
395ENTRY_DIRECT(suword)
396	PROLOGUE
397	SET_FUSUFAULT(%r3, %r7)
398	stw  %r4, 0(%r3)
399	CLEAR_FAULT(%r7)
400	EPILOGUE
401END_DIRECT(suword)
402#endif
403
404ENTRY_DIRECT(suword16)
405	PROLOGUE
406	SET_FUSUFAULT(%r3, %r7)
407	sth  %r4, 0(%r3)
408	CLEAR_FAULT(%r7)
409	EPILOGUE
410END_DIRECT(suword16)
411
412ENTRY_DIRECT(suword32)
413	PROLOGUE
414	SET_FUSUFAULT(%r3, %r7)
415	stw  %r4, 0(%r3)
416	CLEAR_FAULT(%r7)
417	EPILOGUE
418END_DIRECT(suword32)
419
420#ifdef __powerpc64__
421ENTRY_DIRECT(suword64)
422	PROLOGUE
423	SET_FUSUFAULT(%r3, %r7)
424	std  %r4, 0(%r3)
425	CLEAR_FAULT(%r7)
426	EPILOGUE
427END_DIRECT(suword64)
428
429ENTRY_DIRECT(suword)
430	PROLOGUE
431	SET_FUSUFAULT(%r3, %r7)
432	std  %r4, 0(%r3)
433	CLEAR_FAULT(%r7)
434	EPILOGUE
435END_DIRECT(suword)
436#endif
437
438ENTRY_DIRECT(fubyte)
439	PROLOGUE
440	SET_FUSUFAULT(%r3, %r7)
441	lbz %r3, 0(%r3)
442	CLEAR_FAULT_NO_CLOBBER(%r7)
443	EPILOGUE
444END_DIRECT(fubyte)
445
446ENTRY_DIRECT(fuword16)
447	PROLOGUE
448	SET_FUSUFAULT(%r3, %r7)
449	lhz %r3, 0(%r3)
450	CLEAR_FAULT_NO_CLOBBER(%r7)
451	EPILOGUE
452END_DIRECT(fuword16)
453
454#ifndef __powerpc64__
455ENTRY_DIRECT(fueword)
456	PROLOGUE
457	SET_FUSUFAULT(%r3, %r7)
458	lwz  %r0, 0(%r3)
459	stw  %r0,  0(%r4)
460	CLEAR_FAULT(%r7)
461	EPILOGUE
462END_DIRECT(fueword)
463#endif
464ENTRY_DIRECT(fueword32)
465	PROLOGUE
466	SET_FUSUFAULT(%r3, %r7)
467	lwz  %r0, 0(%r3)
468	stw  %r0,  0(%r4)
469	CLEAR_FAULT(%r7)
470	EPILOGUE
471END_DIRECT(fueword32)
472
473#ifdef __powerpc64__
474ENTRY_DIRECT(fueword)
475	PROLOGUE
476	SET_FUSUFAULT(%r3, %r7)
477	ld  %r0, 0(%r3)
478	std %r0, 0(%r4)
479	CLEAR_FAULT(%r7)
480	EPILOGUE
481END_DIRECT(fueword)
482
483ENTRY_DIRECT(fueword64)
484	PROLOGUE
485	SET_FUSUFAULT(%r3, %r7)
486	ld  %r0, 0(%r3)
487	std %r0, 0(%r4)
488	CLEAR_FAULT(%r7)
489	EPILOGUE
490END_DIRECT(fueword64)
491#endif
492
493/*
494 * casueword(volatile u_long *base, u_long old, u_long *oldp, u_long new)
495 *			      %r3          %r4           %r5         %r6
496 */
497
498#define	CASUEWORD32(raddr, rpcb)					;\
499	PROLOGUE							;\
500	SET_FUSUFAULT(raddr, rpcb)					;\
501	li	%r8, 0							;\
5021:									;\
503	lwarx	%r0, 0, %r3						;\
504	cmplw	%r4, %r0						;\
505	bne	2f							;\
506	stwcx.	%r6, 0, %r3						;\
507	bne-	3f							;\
508	b	4f							;\
5092:									;\
510	stwcx.	%r0, 0, %r3       	/* clear reservation (74xx) */	;\
5113:									;\
512	li	%r8, 1							;\
5134:									;\
514	stw	%r0, 0(%r5)						;\
515	CLEAR_FAULT_NO_CLOBBER(rpcb)					;\
516	mr	%r3, %r8						;\
517	EPILOGUE
518
519ENTRY_DIRECT(casueword32)
520	CASUEWORD32(%r3, %r7)
521END_DIRECT(casueword32)
522
523#ifdef __powerpc64__
524#define	CASUEWORD64(raddr, rpcb)					;\
525	PROLOGUE							;\
526	SET_FUSUFAULT(raddr, rpcb)					;\
527	li	%r8, 0							;\
5281:									;\
529	ldarx	%r0, 0, %r3						;\
530	cmpld	%r4, %r0						;\
531	bne	2f							;\
532	stdcx.	%r6, 0, %r3						;\
533	bne-	3f							;\
534	b	4f							;\
5352:									;\
536	stdcx.	%r0, 0, %r3       	/* clear reservation (74xx) */	;\
5373:									;\
538	li	%r8, 1							;\
5394:									;\
540	std	%r0, 0(%r5)						;\
541	CLEAR_FAULT_NO_CLOBBER(rpcb)					;\
542	mr	%r3, %r8						;\
543	EPILOGUE
544
545ENTRY_DIRECT(casueword)
546	CASUEWORD64(%r3, %r7)
547END_DIRECT(casueword)
548
549ENTRY_DIRECT(casueword64)
550	CASUEWORD64(%r3, %r7)
551END_DIRECT(casueword64)
552#else
553ENTRY_DIRECT(casueword)
554	CASUEWORD32(%r3, %r7)
555END_DIRECT(casueword)
556#endif
557
558_NAKED_ENTRY(fusufault)
559	CLEAR_FAULT_NO_CLOBBER(%r7)
560	li %r3, -1
561	EPILOGUE
562_END(fusufault)
563
564_NAKED_ENTRY(copy_fault)
565	CLEAR_FAULT_NO_CLOBBER(%r7)
566	li %r3, EFAULT
567	EPILOGUE
568_END(copy_fault)
569