support.S revision 139790
1/*-
2 * Copyright (c) 1998 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/ia64/ia64/support.S 139790 2005-01-06 22:18:23Z imp $
27 */
28/*-
29 * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
30 * All rights reserved.
31 *
32 * Author: Chris G. Demetriou
33 *
34 * Permission to use, copy, modify and distribute this software and
35 * its documentation is hereby granted, provided that both the copyright
36 * notice and this permission notice appear in all copies of the
37 * software, derivative works or modified versions, and any portions
38 * thereof, and that both notices appear in supporting documentation.
39 *
40 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
41 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
42 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
43 *
44 * Carnegie Mellon requests users of this software to return to
45 *
46 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
47 *  School of Computer Science
48 *  Carnegie Mellon University
49 *  Pittsburgh PA 15213-3890
50 *
51 * any improvements or extensions that they make and grant Carnegie the
52 * rights to redistribute these changes.
53 */
54
55#include <machine/asm.h>
56#include <machine/ia64_cpu.h>
57#include <assym.s>
58
59	.text
60
61/*
62 * ia64_change_mode:	change mode to/from physical mode
63 *
64 * Arguments:
65 *	r14	psr for desired mode
66 *
67 * Modifies:
68 *	r15-r19	scratch
69 *	ar.bsp	tranlated to new mode
70 */
71ENTRY_NOPROFILE(ia64_change_mode, 0)
72	rsm	psr.i | psr.ic
73	mov	r19=ar.rsc		// save rsc while we change mode
74	tbit.nz	p6,p7=r14,17		// physical or virtual ?
75	;;
76	mov	ar.rsc=0		// turn off RSE
77(p6)	mov	r15=7			// RR base for virtual addresses
78(p7)	mov	r15=0			// RR base for physical addresses
79	flushrs				// no dirty registers please
80	srlz.i
81	;;
82	mov	r16=ar.bsp
83	mov	r17=rp
84	mov	r18=ar.rnat
85	;;
86	dep	r16=r15,r16,61,3	// new address of ar.bsp
87	dep	r17=r15,r17,61,3	// new address of rp
88	dep	sp=r15,sp,61,3		// new address of sp
89	;;
90	mov	ar.bspstore=r16
91	mov	rp=r17
92	;;
931:	mov	r16=ip
94	mov	ar.rnat=r18
95	mov	cr.ipsr=r14		// psr for new mode
96	;;
97	add	r16=2f-1b,r16		// address to rfi to
98	;;
99	dep	r16=r15,r16,61,3	// new mode address for rfi
100	;;
101	mov	cr.iip=r16		// setup for rfi
102	mov	cr.ifs=r0
103	;;
104	rfi
105
1062:	mov	ar.rsc=r19		// restore ar.rsc
107	br.ret.sptk.few rp		// now in new mode
108END(ia64_change_mode)
109
110/*
111 * ia64_physical_mode:	change mode to physical mode
112 *
113 * Return:
114 *	ret0	psr to restore
115 *
116 * Modifies:
117 *	r15-r18	scratch
118 *	ar.bsp	tranlated to physical mode
119 *	psr.i	cleared
120 */
121ENTRY(ia64_physical_mode, 0)
122	mov	r14=psr
123	mov	ret0=psr
124	movl	r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH)
125	movl	r16=IA64_PSR_BN
126	;;
127	andcm	r14=r14,r15		// clear various xT bits
128	;;
129	or	r14=r14,r16		// make sure BN=1
130	or	ret0=ret0,r16		// make sure BN=1
131
132	br.cond.sptk.many ia64_change_mode
133END(ia64_physical_mode)
134
135/*
136 * ia64_call_efi_physical:	call an EFI procedure in physical mode
137 *
138 * Arguments:
139 *	in0		Address of EFI procedure descriptor
140 *	in1-in5		Arguments to EFI procedure
141 *
142 * Return:
143 *	ret0-ret3	return values from EFI
144 *
145 */
146ENTRY(ia64_call_efi_physical, 6)
147	.prologue
148	.regstk	6,4,5,0
149	.save	ar.pfs,loc0
150	alloc	loc0=ar.pfs,6,4,5,0
151	;;
152	.save	rp,loc1
153	mov	loc1=rp
154	;;
155	.body
156	br.call.sptk.many rp=ia64_physical_mode
157	;;
158	mov	loc2=r8			// psr to restore mode
159	mov	loc3=gp			// save kernel gp
160	ld8	r14=[in0],8		// function address
161	;;
162	mov	out0=in1
163	mov	out1=in2
164	mov	out2=in3
165	mov	out3=in4
166	mov	out4=in5
167	ld8	gp=[in0]		// function gp value
168	;;
169	mov	b6=r14
170	;;
171	br.call.sptk.many rp=b6		// call EFI procedure
172	mov	gp=loc3			// restore kernel gp
173	;;
174	mov	r14=loc2		// psr to restore mode
175	br.call.sptk.many rp=ia64_change_mode
176	;;
177	mov	rp=loc1
178	mov	ar.pfs=loc0
179	;;
180	br.ret.sptk.many rp
181END(ia64_call_efi_physical)
182
183/**************************************************************************/
184
185ENTRY(fusufault, 0)
186{	.mib
187	st8.rel		[r15]=r0		// Clear onfault.
188	add		ret0=-1,r0
189	br.ret.sptk	rp
190	;;
191}
192END(fusufault)
193
194/*
195 * casuptr(intptr_t *p, intptr_t old, intptr_t new)
196 *	Perform a compare-exchange in user space.
197 */
198ENTRY(casuptr, 3)
199{	.mlx
200	add		r15=PC_CURTHREAD,r13
201	movl		r14=VM_MAX_ADDRESS
202	;;
203}
204{	.mib
205	ld8		r15=[r15]		// r15 = curthread
206	cmp.geu		p6,p0=in0,r14
207(p6)	br.dpnt.few	1f
208	;;
209}
210{	.mlx
211	add		r15=TD_PCB,r15
212	movl		r14=fusufault
213	;;
214}
215{	.mmi
216	ld8		r15=[r15]		// r15 = PCB
217	;;
218	mov		ar.ccv=in1
219	add		r15=PCB_ONFAULT,r15
220	;;
221}
222{	.mmi
223	st8		[r15]=r14		// Set onfault
224	;;
225	cmpxchg8.rel	ret0=[in0],in2,ar.ccv
226	nop		0
227	;;
228}
229{	.mfb
230	st8.rel		[r15]=r0		// Clear onfault
231	nop		0
232	br.ret.sptk	rp
233	;;
234}
2351:
236{	.mfb
237	add		ret0=-1,r0
238	nop		0
239	br.ret.sptk	rp
240	;;
241}
242END(casuptr)
243
244/*
245 * subyte(void *addr, int byte)
246 * suword16(void *addr, int word)
247 * suword32(void *addr, int word)
248 * suword64|suword(void *addr, long word)
249 *	Store in user space
250 */
251
252ENTRY(subyte, 2)
253{	.mlx
254	add		r15=PC_CURTHREAD,r13
255	movl		r14=VM_MAX_ADDRESS
256	;;
257}
258{	.mib
259	ld8		r15=[r15]		// r15 = curthread
260	cmp.geu		p6,p0=in0,r14
261(p6)	br.dpnt.few	1f
262	;;
263}
264{	.mlx
265	add		r15=TD_PCB,r15
266	movl		r14=fusufault
267	;;
268}
269{	.mmi
270	ld8		r15=[r15]		// r15 = PCB
271	;;
272	nop		0
273	add		r15=PCB_ONFAULT,r15
274	;;
275}
276{	.mmi
277	st8		[r15]=r14		// Set onfault
278	;;
279	st1.rel		[in0]=in1
280	nop		0
281	;;
282}
283{	.mib
284	st8.rel		[r15]=r0		// Clear onfault
285	mov		ret0=r0
286	br.ret.sptk	rp
287	;;
288}
2891:
290{	.mfb
291	add		ret0=-1,r0
292	nop		0
293	br.ret.sptk	rp
294	;;
295}
296END(subyte)
297
298ENTRY(suword16, 2)
299{	.mlx
300	add		r15=PC_CURTHREAD,r13
301	movl		r14=VM_MAX_ADDRESS
302	;;
303}
304{	.mib
305	ld8		r15=[r15]		// r15 = curthread
306	cmp.geu		p6,p0=in0,r14
307(p6)	br.dpnt.few	1f
308	;;
309}
310{	.mlx
311	add		r15=TD_PCB,r15
312	movl		r14=fusufault
313	;;
314}
315{	.mmi
316	ld8		r15=[r15]		// r15 = PCB
317	;;
318	nop		0
319	add		r15=PCB_ONFAULT,r15
320	;;
321}
322{	.mmi
323	st8		[r15]=r14		// Set onfault
324	;;
325	st2.rel		[in0]=in1
326	nop		0
327	;;
328}
329{	.mib
330	st8.rel		[r15]=r0		// Clear onfault
331	mov		ret0=r0
332	br.ret.sptk	rp
333	;;
334}
3351:
336{	.mfb
337	add		ret0=-1,r0
338	nop		0
339	br.ret.sptk	rp
340	;;
341}
342END(suword16)
343
344ENTRY(suword32, 2)
345{	.mlx
346	add		r15=PC_CURTHREAD,r13
347	movl		r14=VM_MAX_ADDRESS
348	;;
349}
350{	.mib
351	ld8		r15=[r15]		// r15 = curthread
352	cmp.geu		p6,p0=in0,r14
353(p6)	br.dpnt.few	1f
354	;;
355}
356{	.mlx
357	add		r15=TD_PCB,r15
358	movl		r14=fusufault
359	;;
360}
361{	.mmi
362	ld8		r15=[r15]		// r15 = PCB
363	;;
364	nop		0
365	add		r15=PCB_ONFAULT,r15
366	;;
367}
368{	.mmi
369	st8		[r15]=r14		// Set onfault
370	;;
371	st4.rel		[in0]=in1
372	nop		0
373	;;
374}
375{	.mib
376	st8.rel		[r15]=r0		// Clear onfault
377	mov		ret0=r0
378	br.ret.sptk	rp
379	;;
380}
3811:
382{	.mfb
383	add		ret0=-1,r0
384	nop		0
385	br.ret.sptk	rp
386	;;
387}
388END(suword32)
389
390ENTRY(suword64, 2)
391XENTRY(suword)
392{	.mlx
393	add		r15=PC_CURTHREAD,r13
394	movl		r14=VM_MAX_ADDRESS
395	;;
396}
397{	.mib
398	ld8		r15=[r15]		// r15 = curthread
399	cmp.geu		p6,p0=in0,r14
400(p6)	br.dpnt.few	1f
401	;;
402}
403{	.mlx
404	add		r15=TD_PCB,r15
405	movl		r14=fusufault
406	;;
407}
408{	.mmi
409	ld8		r15=[r15]		// r15 = PCB
410	;;
411	nop		0
412	add		r15=PCB_ONFAULT,r15
413	;;
414}
415{	.mmi
416	st8		[r15]=r14		// Set onfault
417	;;
418	st8.rel		[in0]=in1
419	nop		0
420	;;
421}
422{	.mib
423	st8.rel		[r15]=r0		// Clear onfault
424	mov		ret0=r0
425	br.ret.sptk	rp
426	;;
427}
4281:
429{	.mfb
430	add		ret0=-1,r0
431	nop		0
432	br.ret.sptk	rp
433	;;
434}
435END(suword64)
436
437/*
438 * fubyte(void *addr, int byte)
439 * fuword16(void *addr, int word)
440 * fuword32(void *addr, int word)
441 * fuword64|fuword(void *addr, long word)
442 *	Fetch from user space
443 */
444
445ENTRY(fubyte, 1)
446{	.mlx
447	add		r15=PC_CURTHREAD,r13
448	movl		r14=VM_MAX_ADDRESS
449	;;
450}
451{	.mib
452	ld8		r15=[r15]		// r15 = curthread
453	cmp.geu		p6,p0=in0,r14
454(p6)	br.dpnt.few	1f
455	;;
456}
457{	.mlx
458	add		r15=TD_PCB,r15
459	movl		r14=fusufault
460	;;
461}
462{	.mmi
463	ld8		r15=[r15]		// r15 = PCB
464	;;
465	nop		0
466	add		r15=PCB_ONFAULT,r15
467	;;
468}
469{	.mmi
470	st8		[r15]=r14		// Set onfault
471	;;
472	mf
473	nop		0
474	;;
475}
476{	.mmb
477	ld1		ret0=[in0]
478	st8.rel		[r15]=r0		// Clear onfault
479	br.ret.sptk	rp
480	;;
481}
4821:
483{	.mfb
484	add		ret0=-1,r0
485	nop		0
486	br.ret.sptk	rp
487	;;
488}
489END(fubyte)
490
491ENTRY(fuword16, 2)
492{	.mlx
493	add		r15=PC_CURTHREAD,r13
494	movl		r14=VM_MAX_ADDRESS
495	;;
496}
497{	.mib
498	ld8		r15=[r15]		// r15 = curthread
499	cmp.geu		p6,p0=in0,r14
500(p6)	br.dpnt.few	1f
501	;;
502}
503{	.mlx
504	add		r15=TD_PCB,r15
505	movl		r14=fusufault
506	;;
507}
508{	.mmi
509	ld8		r15=[r15]		// r15 = PCB
510	;;
511	nop		0
512	add		r15=PCB_ONFAULT,r15
513	;;
514}
515{	.mmi
516	st8		[r15]=r14		// Set onfault
517	;;
518	mf
519	nop		0
520	;;
521}
522{	.mmb
523	ld2		ret0=[in0]
524	st8.rel		[r15]=r0		// Clear onfault
525	br.ret.sptk	rp
526	;;
527}
5281:
529{	.mfb
530	add		ret0=-1,r0
531	nop		0
532	br.ret.sptk	rp
533	;;
534}
535END(fuword16)
536
537ENTRY(fuword32, 2)
538{	.mlx
539	add		r15=PC_CURTHREAD,r13
540	movl		r14=VM_MAX_ADDRESS
541	;;
542}
543{	.mib
544	ld8		r15=[r15]		// r15 = curthread
545	cmp.geu		p6,p0=in0,r14
546(p6)	br.dpnt.few	1f
547	;;
548}
549{	.mlx
550	add		r15=TD_PCB,r15
551	movl		r14=fusufault
552	;;
553}
554{	.mmi
555	ld8		r15=[r15]		// r15 = PCB
556	;;
557	nop		0
558	add		r15=PCB_ONFAULT,r15
559	;;
560}
561{	.mmi
562	st8		[r15]=r14		// Set onfault
563	;;
564	mf
565	nop		0
566	;;
567}
568{	.mmb
569	ld4		ret0=[in0]
570	st8.rel		[r15]=r0		// Clear onfault
571	br.ret.sptk	rp
572	;;
573}
5741:
575{	.mfb
576	add		ret0=-1,r0
577	nop		0
578	br.ret.sptk	rp
579	;;
580}
581END(fuword32)
582
583ENTRY(fuword64, 2)
584XENTRY(fuword)
585{	.mlx
586	add		r15=PC_CURTHREAD,r13
587	movl		r14=VM_MAX_ADDRESS
588	;;
589}
590{	.mib
591	ld8		r15=[r15]		// r15 = curthread
592	cmp.geu		p6,p0=in0,r14
593(p6)	br.dpnt.few	1f
594	;;
595}
596{	.mlx
597	add		r15=TD_PCB,r15
598	movl		r14=fusufault
599	;;
600}
601{	.mmi
602	ld8		r15=[r15]		// r15 = PCB
603	;;
604	nop		0
605	add		r15=PCB_ONFAULT,r15
606	;;
607}
608{	.mmi
609	st8		[r15]=r14		// Set onfault
610	;;
611	mf
612	nop		0
613	;;
614}
615{	.mmb
616	ld8		ret0=[in0]
617	st8.rel		[r15]=r0		// Clear onfault
618	br.ret.sptk	rp
619	;;
620}
6211:
622{	.mfb
623	add		ret0=-1,r0
624	nop		0
625	br.ret.sptk	rp
626	;;
627}
628END(fuword64)
629
630/*
631 * fuswintr(void *addr)
632 * suswintr(void *addr)
633 */
634
635ENTRY(fuswintr, 1)
636{	.mfb
637	add		ret0=-1,r0
638	nop		0
639	br.ret.sptk	rp
640	;;
641}
642END(fuswintr)
643
644ENTRY(suswintr, 0)
645{	.mfb
646	add		ret0=-1,r0
647	nop		0
648	br.ret.sptk	rp
649	;;
650}
651END(suswintr)
652
653/**************************************************************************/
654
655/*
656 * Copy a null-terminated string within the kernel's address space.
657 * If lenp is not NULL, store the number of chars copied in *lenp
658 *
659 * int copystr(char *from, char *to, size_t len, size_t *lenp);
660 */
661ENTRY(copystr, 4)
662	mov	r14=in2			// r14 = i = len
663	cmp.eq	p6,p0=r0,in2
664(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
665
6661:	ld1	r15=[in0],1		// read one byte
667	;;
668	st1	[in1]=r15,1		// write that byte
669	add	in2=-1,in2		// len--
670	;;
671	cmp.eq	p6,p0=r0,r15
672	cmp.ne	p7,p0=r0,in2
673	;;
674(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
675(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
676
6772:	cmp.eq	p6,p0=r0,in3
678(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
679	sub	r14=r14,in2		// *lenp = (i - len)
680	;;
681	st8	[in3]=r14
682
6833:	cmp.eq	p6,p0=r0,r15
684(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
685
686	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
687	br.ret.sptk.few rp
688
6894:	mov	ret0=0			// return 0.
690	br.ret.sptk.few rp
691END(copystr)
692
693ENTRY(copyinstr, 4)
694	.prologue
695	.regstk	4, 3, 4, 0
696	.save	ar.pfs,loc0
697	alloc	loc0=ar.pfs,4,3,4,0
698	.save	rp,loc1
699	mov	loc1=rp
700	.body
701
702	movl	loc2=VM_MAX_ADDRESS		// make sure that src addr
703	;;
704	cmp.geu	p6,p0=in0,loc2			// is in user space.
705	;;
706(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
707	movl	r14=copyerr			// set up fault handler.
708	add	r15=PC_CURTHREAD,r13		// find curthread
709	;;
710	ld8	r15=[r15]
711	;;
712	add	r15=TD_PCB,r15			// find pcb
713	;;
714	ld8	r15=[r15]
715	;;
716	add	loc2=PCB_ONFAULT,r15
717	;;
718	st8	[loc2]=r14
719	;;
720	mov	out0=in0
721	mov	out1=in1
722	mov	out2=in2
723	mov	out3=in3
724	;;
725	br.call.sptk.few rp=copystr		// do the copy.
726	st8	[loc2]=r0			// kill the fault handler.
727	mov	ar.pfs=loc0			// restore ar.pfs
728	mov	rp=loc1				// restore ra.
729	br.ret.sptk.few rp			// ret0 left over from copystr
730END(copyinstr)
731
732/*
733 * Not the fastest bcopy in the world.
734 */
735ENTRY(bcopy, 3)
736	mov	ret0=r0				// return zero for copy{in,out}
737	;;
738	cmp.le	p6,p0=in2,r0			// bail if len <= 0
739(p6)	br.ret.spnt.few rp
740
741	sub	r14=in1,in0 ;;			// check for overlap
742	cmp.ltu	p6,p0=r14,in2			// dst-src < len
743(p6)	br.cond.spnt.few 5f
744
745	extr.u	r14=in0,0,3			// src & 7
746	extr.u	r15=in1,0,3 ;;			// dst & 7
747	cmp.eq	p6,p0=r14,r15			// different alignment?
748(p6)	br.cond.spnt.few 2f			// branch if same alignment
749
7501:	ld1	r14=[in0],1 ;;			// copy bytewise
751	st1	[in1]=r14,1
752	add	in2=-1,in2 ;;			// len--
753	cmp.ne	p6,p0=r0,in2
754(p6)	br.cond.dptk.few 1b			// loop
755	br.ret.sptk.few rp			// done
756
7572:	cmp.eq	p6,p0=r14,r0			// aligned?
758(p6)	br.cond.sptk.few 4f
759
7603:	ld1	r14=[in0],1 ;;			// copy bytewise
761	st1	[in1]=r14,1
762	extr.u	r15=in0,0,3			// src & 7
763	add	in2=-1,in2 ;;			// len--
764	cmp.eq	p6,p0=r0,in2			// done?
765	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
766(p6)	br.ret.spnt.few rp			// return if done
767(p7)	br.cond.spnt.few 4f			// go to main copy
768	br.cond.sptk.few 3b			// more bytes to copy
769
770	// At this point, in2 is non-zero
771
7724:	mov	r14=8 ;;
773	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
774(p6)	br.cond.spnt.few 1b			// byte copy the end
775	ld8	r15=[in0],8 ;;			// copy word
776	st8	[in1]=r15,8
777	add	in2=-8,in2 ;;			// len -= 8
778	cmp.ne	p6,p0=r0,in2			// done?
779(p6)	br.cond.spnt.few 4b			// again
780
781	br.ret.sptk.few rp			// return
782
783	// Don't bother optimising overlap case
784
7855:	add	in0=in0,in2
786	add	in1=in1,in2 ;;
787	add	in0=-1,in0
788	add	in1=-1,in1 ;;
789
7906:	ld1	r14=[in0],-1 ;;
791	st1	[in1]=r14,-1
792	add	in2=-1,in2 ;;
793	cmp.ne	p6,p0=r0,in2
794(p6)	br.cond.spnt.few 6b
795
796	br.ret.sptk.few rp
797END(bcopy)
798
799ENTRY(memcpy,3)
800	mov	r14=in0 ;;
801	mov	in0=in1 ;;
802	mov	in1=r14
803	br.cond.sptk.few bcopy
804END(memcpy)
805
806ENTRY(copyin, 3)
807	.prologue
808	.regstk	3, 3, 3, 0
809	.save	ar.pfs,loc0
810	alloc	loc0=ar.pfs,3,3,3,0
811	.save	rp,loc1
812	mov	loc1=rp
813	.body
814
815	movl	loc2=VM_MAX_ADDRESS		// make sure that src addr
816	;;
817	cmp.geu	p6,p0=in0,loc2			// is in user space.
818	;;
819(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
820	movl	r14=copyerr			// set up fault handler.
821	add	r15=PC_CURTHREAD,r13		// find curthread
822	;;
823	ld8	r15=[r15]
824	;;
825	add	r15=TD_PCB,r15			// find pcb
826	;;
827	ld8	r15=[r15]
828	;;
829	add	loc2=PCB_ONFAULT,r15
830	;;
831	st8	[loc2]=r14
832	;;
833	mov	out0=in0
834	mov	out1=in1
835	mov	out2=in2
836	;;
837	br.call.sptk.few rp=bcopy		// do the copy.
838	st8	[loc2]=r0			// kill the fault handler.
839	mov	ar.pfs=loc0			// restore ar.pfs
840	mov	rp=loc1				// restore ra.
841	br.ret.sptk.few rp			// ret0 left over from bcopy
842END(copyin)
843
844ENTRY(copyout, 3)
845	.prologue
846	.regstk	3, 3, 3, 0
847	.save	ar.pfs,loc0
848	alloc	loc0=ar.pfs,3,3,3,0
849	.save	rp,loc1
850	mov	loc1=rp
851	.body
852
853	movl	loc2=VM_MAX_ADDRESS		// make sure that dest addr
854	;;
855	cmp.geu	p6,p0=in1,loc2			// is in user space.
856	;;
857(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
858	movl	r14=copyerr			// set up fault handler.
859	add	r15=PC_CURTHREAD,r13		// find curthread
860	;;
861	ld8	r15=[r15]
862	;;
863	add	r15=TD_PCB,r15			// find pcb
864	;;
865	ld8	r15=[r15]
866	;;
867	add	loc2=PCB_ONFAULT,r15
868	;;
869	st8	[loc2]=r14
870	;;
871	mov	out0=in0
872	mov	out1=in1
873	mov	out2=in2
874	;;
875	br.call.sptk.few rp=bcopy		// do the copy.
876	st8	[loc2]=r0			// kill the fault handler.
877	mov	ar.pfs=loc0			// restore ar.pfs
878	mov	rp=loc1				// restore ra.
879	br.ret.sptk.few rp			// ret0 left over from bcopy
880END(copyout)
881
882ENTRY(copyerr, 0)
883	add	r14=PC_CURTHREAD,r13 ;;		// find curthread
884	ld8	r14=[r14] ;;
885	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
886	ld8	r14=[r14] ;;
887	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
888	st8	[r14]=r0			// reset fault handler
889
890	mov	ret0=EFAULT			// return EFAULT
891	br.ret.sptk.few rp
892END(copyerr)
893
894#if defined(GPROF)
895/*
896 * Important registers:
897 *      r8      structure return address
898 *      rp      our return address
899 *      in0     caller's ar.pfs
900 *      in1     caller's gp
901 *      in2     caller's rp
902 *      in3     GOT entry
903 *      ar.pfs  our pfs
904 */
905ENTRY_NOPROFILE(_mcount, 4)
906	alloc		loc0 = ar.pfs, 4, 3, 2, 0
907	mov		loc1 = r8
908	mov		loc2 = rp
909	;;
910	mov		out0 = in2
911	mov		out1 = rp
912	br.call.sptk	rp = __mcount
913	;;
9141:
915	mov		gp = in1
916	mov		r14 = ip
917	mov		b7 = loc2
918	;;
919	add		r14 = 2f - 1b, r14
920	mov		ar.pfs = loc0
921	mov		rp = in2
922	;;
923	mov		b7 = r14
924	mov		b6 = loc2
925	mov		r8 = loc1
926	mov		r14 = in0
927	br.ret.sptk	b7
928	;;
9292:
930	mov		ar.pfs = r14
931	br.sptk		b6
932	;;
933END(_mcount)
934#endif
935