support.S revision 219841
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 219841 2011-03-21 18:20:53Z marcel $
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
61ENTRY(fusufault, 0)
62{	.mib
63	st8.rel		[r15]=r0		// Clear onfault.
64	add		ret0=-1,r0
65	br.ret.sptk	rp
66	;;
67}
68END(fusufault)
69
70/*
71 * casuword(u_long *p, u_long old, u_long new)
72 *	Perform a compare-exchange in user space.
73 */
74ENTRY(casuword, 3)
75{	.mlx
76	add		r15=PC_CURTHREAD,r13
77	movl		r14=VM_MAXUSER_ADDRESS
78	;;
79}
80{	.mib
81	ld8		r15=[r15]		// r15 = curthread
82	cmp.geu		p6,p0=in0,r14
83(p6)	br.dpnt.few	1f
84	;;
85}
86{	.mlx
87	add		r15=TD_PCB,r15
88	movl		r14=fusufault
89	;;
90}
91{	.mmi
92	ld8		r15=[r15]		// r15 = PCB
93	;;
94	mov		ar.ccv=in1
95	add		r15=PCB_ONFAULT,r15
96	;;
97}
98{	.mmi
99	st8		[r15]=r14		// Set onfault
100	;;
101	cmpxchg8.rel	ret0=[in0],in2,ar.ccv
102	nop		0
103	;;
104}
105{	.mib
106	st8.rel		[r15]=r0		// Clear onfault
107	nop		0
108	br.ret.sptk	rp
109	;;
110}
1111:
112{	.mib
113	add		ret0=-1,r0
114	nop		0
115	br.ret.sptk	rp
116	;;
117}
118END(casuword)
119
120/*
121 * casuword32(uint32_t *p, uint32_t old, uint32_t new)
122 *	Perform a 32-bit compare-exchange in user space.
123 */
124ENTRY(casuword32, 3)
125{	.mlx
126	add		r15=PC_CURTHREAD,r13
127	movl		r14=VM_MAXUSER_ADDRESS
128	;;
129}
130{	.mib
131	ld8		r15=[r15]		// r15 = curthread
132	cmp.geu		p6,p0=in0,r14
133(p6)	br.dpnt.few	1f
134	;;
135}
136{	.mlx
137	add		r15=TD_PCB,r15
138	movl		r14=fusufault
139	;;
140}
141{	.mmi
142	ld8		r15=[r15]		// r15 = PCB
143	;;
144	mov		ar.ccv=in1
145	add		r15=PCB_ONFAULT,r15
146	;;
147}
148{	.mmi
149	st8		[r15]=r14		// Set onfault
150	;;
151	cmpxchg4.rel	ret0=[in0],in2,ar.ccv
152	nop		0
153	;;
154}
155{	.mib
156	st8.rel		[r15]=r0		// Clear onfault
157	nop		0
158	br.ret.sptk	rp
159	;;
160}
1611:
162{	.mib
163	add		ret0=-1,r0
164	nop		0
165	br.ret.sptk	rp
166	;;
167}
168END(casuword32)
169
170/*
171 * subyte(void *addr, int byte)
172 * suword16(void *addr, int word)
173 * suword32(void *addr, int word)
174 * suword64|suword(void *addr, long word)
175 *	Store in user space
176 */
177
178ENTRY(subyte, 2)
179{	.mlx
180	add		r15=PC_CURTHREAD,r13
181	movl		r14=VM_MAXUSER_ADDRESS
182	;;
183}
184{	.mib
185	ld8		r15=[r15]		// r15 = curthread
186	cmp.geu		p6,p0=in0,r14
187(p6)	br.dpnt.few	1f
188	;;
189}
190{	.mlx
191	add		r15=TD_PCB,r15
192	movl		r14=fusufault
193	;;
194}
195{	.mmi
196	ld8		r15=[r15]		// r15 = PCB
197	;;
198	nop		0
199	add		r15=PCB_ONFAULT,r15
200	;;
201}
202{	.mmi
203	st8		[r15]=r14		// Set onfault
204	;;
205	st1.rel		[in0]=in1
206	nop		0
207	;;
208}
209{	.mib
210	st8.rel		[r15]=r0		// Clear onfault
211	mov		ret0=r0
212	br.ret.sptk	rp
213	;;
214}
2151:
216{	.mib
217	add		ret0=-1,r0
218	nop		0
219	br.ret.sptk	rp
220	;;
221}
222END(subyte)
223
224ENTRY(suword16, 2)
225{	.mlx
226	add		r15=PC_CURTHREAD,r13
227	movl		r14=VM_MAXUSER_ADDRESS
228	;;
229}
230{	.mib
231	ld8		r15=[r15]		// r15 = curthread
232	cmp.geu		p6,p0=in0,r14
233(p6)	br.dpnt.few	1f
234	;;
235}
236{	.mlx
237	add		r15=TD_PCB,r15
238	movl		r14=fusufault
239	;;
240}
241{	.mmi
242	ld8		r15=[r15]		// r15 = PCB
243	;;
244	nop		0
245	add		r15=PCB_ONFAULT,r15
246	;;
247}
248{	.mmi
249	st8		[r15]=r14		// Set onfault
250	;;
251	st2.rel		[in0]=in1
252	nop		0
253	;;
254}
255{	.mib
256	st8.rel		[r15]=r0		// Clear onfault
257	mov		ret0=r0
258	br.ret.sptk	rp
259	;;
260}
2611:
262{	.mib
263	add		ret0=-1,r0
264	nop		0
265	br.ret.sptk	rp
266	;;
267}
268END(suword16)
269
270ENTRY(suword32, 2)
271{	.mlx
272	add		r15=PC_CURTHREAD,r13
273	movl		r14=VM_MAXUSER_ADDRESS
274	;;
275}
276{	.mib
277	ld8		r15=[r15]		// r15 = curthread
278	cmp.geu		p6,p0=in0,r14
279(p6)	br.dpnt.few	1f
280	;;
281}
282{	.mlx
283	add		r15=TD_PCB,r15
284	movl		r14=fusufault
285	;;
286}
287{	.mmi
288	ld8		r15=[r15]		// r15 = PCB
289	;;
290	nop		0
291	add		r15=PCB_ONFAULT,r15
292	;;
293}
294{	.mmi
295	st8		[r15]=r14		// Set onfault
296	;;
297	st4.rel		[in0]=in1
298	nop		0
299	;;
300}
301{	.mib
302	st8.rel		[r15]=r0		// Clear onfault
303	mov		ret0=r0
304	br.ret.sptk	rp
305	;;
306}
3071:
308{	.mib
309	add		ret0=-1,r0
310	nop		0
311	br.ret.sptk	rp
312	;;
313}
314END(suword32)
315
316ENTRY(suword64, 2)
317XENTRY(suword)
318{	.mlx
319	add		r15=PC_CURTHREAD,r13
320	movl		r14=VM_MAXUSER_ADDRESS
321	;;
322}
323{	.mib
324	ld8		r15=[r15]		// r15 = curthread
325	cmp.geu		p6,p0=in0,r14
326(p6)	br.dpnt.few	1f
327	;;
328}
329{	.mlx
330	add		r15=TD_PCB,r15
331	movl		r14=fusufault
332	;;
333}
334{	.mmi
335	ld8		r15=[r15]		// r15 = PCB
336	;;
337	nop		0
338	add		r15=PCB_ONFAULT,r15
339	;;
340}
341{	.mmi
342	st8		[r15]=r14		// Set onfault
343	;;
344	st8.rel		[in0]=in1
345	nop		0
346	;;
347}
348{	.mib
349	st8.rel		[r15]=r0		// Clear onfault
350	mov		ret0=r0
351	br.ret.sptk	rp
352	;;
353}
3541:
355{	.mib
356	add		ret0=-1,r0
357	nop		0
358	br.ret.sptk	rp
359	;;
360}
361END(suword64)
362
363/*
364 * fubyte(void *addr, int byte)
365 * fuword16(void *addr, int word)
366 * fuword32(void *addr, int word)
367 * fuword64|fuword(void *addr, long word)
368 *	Fetch from user space
369 */
370
371ENTRY(fubyte, 1)
372{	.mlx
373	add		r15=PC_CURTHREAD,r13
374	movl		r14=VM_MAXUSER_ADDRESS
375	;;
376}
377{	.mib
378	ld8		r15=[r15]		// r15 = curthread
379	cmp.geu		p6,p0=in0,r14
380(p6)	br.dpnt.few	1f
381	;;
382}
383{	.mlx
384	add		r15=TD_PCB,r15
385	movl		r14=fusufault
386	;;
387}
388{	.mmi
389	ld8		r15=[r15]		// r15 = PCB
390	;;
391	nop		0
392	add		r15=PCB_ONFAULT,r15
393	;;
394}
395{	.mmi
396	st8		[r15]=r14		// Set onfault
397	;;
398	mf
399	nop		0
400	;;
401}
402{	.mmb
403	ld1		ret0=[in0]
404	st8.rel		[r15]=r0		// Clear onfault
405	br.ret.sptk	rp
406	;;
407}
4081:
409{	.mib
410	add		ret0=-1,r0
411	nop		0
412	br.ret.sptk	rp
413	;;
414}
415END(fubyte)
416
417ENTRY(fuword16, 2)
418{	.mlx
419	add		r15=PC_CURTHREAD,r13
420	movl		r14=VM_MAXUSER_ADDRESS
421	;;
422}
423{	.mib
424	ld8		r15=[r15]		// r15 = curthread
425	cmp.geu		p6,p0=in0,r14
426(p6)	br.dpnt.few	1f
427	;;
428}
429{	.mlx
430	add		r15=TD_PCB,r15
431	movl		r14=fusufault
432	;;
433}
434{	.mmi
435	ld8		r15=[r15]		// r15 = PCB
436	;;
437	nop		0
438	add		r15=PCB_ONFAULT,r15
439	;;
440}
441{	.mmi
442	st8		[r15]=r14		// Set onfault
443	;;
444	mf
445	nop		0
446	;;
447}
448{	.mmb
449	ld2		ret0=[in0]
450	st8.rel		[r15]=r0		// Clear onfault
451	br.ret.sptk	rp
452	;;
453}
4541:
455{	.mib
456	add		ret0=-1,r0
457	nop		0
458	br.ret.sptk	rp
459	;;
460}
461END(fuword16)
462
463ENTRY(fuword32, 2)
464{	.mlx
465	add		r15=PC_CURTHREAD,r13
466	movl		r14=VM_MAXUSER_ADDRESS
467	;;
468}
469{	.mib
470	ld8		r15=[r15]		// r15 = curthread
471	cmp.geu		p6,p0=in0,r14
472(p6)	br.dpnt.few	1f
473	;;
474}
475{	.mlx
476	add		r15=TD_PCB,r15
477	movl		r14=fusufault
478	;;
479}
480{	.mmi
481	ld8		r15=[r15]		// r15 = PCB
482	;;
483	nop		0
484	add		r15=PCB_ONFAULT,r15
485	;;
486}
487{	.mmi
488	st8		[r15]=r14		// Set onfault
489	;;
490	mf
491	nop		0
492	;;
493}
494{	.mmb
495	ld4		ret0=[in0]
496	st8.rel		[r15]=r0		// Clear onfault
497	br.ret.sptk	rp
498	;;
499}
5001:
501{	.mib
502	add		ret0=-1,r0
503	nop		0
504	br.ret.sptk	rp
505	;;
506}
507END(fuword32)
508
509ENTRY(fuword64, 2)
510XENTRY(fuword)
511{	.mlx
512	add		r15=PC_CURTHREAD,r13
513	movl		r14=VM_MAXUSER_ADDRESS
514	;;
515}
516{	.mib
517	ld8		r15=[r15]		// r15 = curthread
518	cmp.geu		p6,p0=in0,r14
519(p6)	br.dpnt.few	1f
520	;;
521}
522{	.mlx
523	add		r15=TD_PCB,r15
524	movl		r14=fusufault
525	;;
526}
527{	.mmi
528	ld8		r15=[r15]		// r15 = PCB
529	;;
530	nop		0
531	add		r15=PCB_ONFAULT,r15
532	;;
533}
534{	.mmi
535	st8		[r15]=r14		// Set onfault
536	;;
537	mf
538	nop		0
539	;;
540}
541{	.mmb
542	ld8		ret0=[in0]
543	st8.rel		[r15]=r0		// Clear onfault
544	br.ret.sptk	rp
545	;;
546}
5471:
548{	.mib
549	add		ret0=-1,r0
550	nop		0
551	br.ret.sptk	rp
552	;;
553}
554END(fuword64)
555
556/*
557 * fuswintr(void *addr)
558 * suswintr(void *addr)
559 */
560
561ENTRY(fuswintr, 1)
562{	.mib
563	add		ret0=-1,r0
564	nop		0
565	br.ret.sptk	rp
566	;;
567}
568END(fuswintr)
569
570ENTRY(suswintr, 0)
571{	.mib
572	add		ret0=-1,r0
573	nop		0
574	br.ret.sptk	rp
575	;;
576}
577END(suswintr)
578
579/**************************************************************************/
580
581/*
582 * Copy a null-terminated string within the kernel's address space.
583 * If lenp is not NULL, store the number of chars copied in *lenp
584 *
585 * int copystr(char *from, char *to, size_t len, size_t *lenp);
586 */
587ENTRY(copystr, 4)
588	mov	r14=in2			// r14 = i = len
589	cmp.eq	p6,p0=r0,in2
590(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
591
5921:	ld1	r15=[in0],1		// read one byte
593	;;
594	st1	[in1]=r15,1		// write that byte
595	add	in2=-1,in2		// len--
596	;;
597	cmp.eq	p6,p0=r0,r15
598	cmp.ne	p7,p0=r0,in2
599	;;
600(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
601(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
602
6032:	cmp.eq	p6,p0=r0,in3
604(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
605	sub	r14=r14,in2		// *lenp = (i - len)
606	;;
607	st8	[in3]=r14
608
6093:	cmp.eq	p6,p0=r0,r15
610(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
611
612	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
613	br.ret.sptk.few rp
614
6154:	mov	ret0=0			// return 0.
616	br.ret.sptk.few rp
617END(copystr)
618
619ENTRY(copyinstr, 4)
620	.prologue
621	.regstk	4, 3, 4, 0
622	.save	ar.pfs,loc0
623	alloc	loc0=ar.pfs,4,3,4,0
624	.save	rp,loc1
625	mov	loc1=rp
626	.body
627
628	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
629	;;
630	cmp.geu	p6,p0=in0,loc2			// is in user space.
631	;;
632(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
633	movl	r14=copyerr			// set up fault handler.
634	add	r15=PC_CURTHREAD,r13		// find curthread
635	;;
636	ld8	r15=[r15]
637	;;
638	add	r15=TD_PCB,r15			// find pcb
639	;;
640	ld8	r15=[r15]
641	;;
642	add	loc2=PCB_ONFAULT,r15
643	;;
644	st8	[loc2]=r14
645	;;
646	mov	out0=in0
647	mov	out1=in1
648	mov	out2=in2
649	mov	out3=in3
650	;;
651	br.call.sptk.few rp=copystr		// do the copy.
652	st8	[loc2]=r0			// kill the fault handler.
653	mov	ar.pfs=loc0			// restore ar.pfs
654	mov	rp=loc1				// restore ra.
655	br.ret.sptk.few rp			// ret0 left over from copystr
656END(copyinstr)
657
658/*
659 * Not the fastest bcopy in the world.
660 */
661ENTRY(bcopy, 3)
662	mov	ret0=r0				// return zero for copy{in,out}
663	;;
664	cmp.le	p6,p0=in2,r0			// bail if len <= 0
665(p6)	br.ret.spnt.few rp
666
667	sub	r14=in1,in0 ;;			// check for overlap
668	cmp.ltu	p6,p0=r14,in2			// dst-src < len
669(p6)	br.cond.spnt.few 5f
670
671	extr.u	r14=in0,0,3			// src & 7
672	extr.u	r15=in1,0,3 ;;			// dst & 7
673	cmp.eq	p6,p0=r14,r15			// different alignment?
674(p6)	br.cond.spnt.few 2f			// branch if same alignment
675
6761:	ld1	r14=[in0],1 ;;			// copy bytewise
677	st1	[in1]=r14,1
678	add	in2=-1,in2 ;;			// len--
679	cmp.ne	p6,p0=r0,in2
680(p6)	br.cond.dptk.few 1b			// loop
681	br.ret.sptk.few rp			// done
682
6832:	cmp.eq	p6,p0=r14,r0			// aligned?
684(p6)	br.cond.sptk.few 4f
685
6863:	ld1	r14=[in0],1 ;;			// copy bytewise
687	st1	[in1]=r14,1
688	extr.u	r15=in0,0,3			// src & 7
689	add	in2=-1,in2 ;;			// len--
690	cmp.eq	p6,p0=r0,in2			// done?
691	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
692(p6)	br.ret.spnt.few rp			// return if done
693(p7)	br.cond.spnt.few 4f			// go to main copy
694	br.cond.sptk.few 3b			// more bytes to copy
695
696	// At this point, in2 is non-zero
697
6984:	mov	r14=8 ;;
699	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
700(p6)	br.cond.spnt.few 1b			// byte copy the end
701	ld8	r15=[in0],8 ;;			// copy word
702	st8	[in1]=r15,8
703	add	in2=-8,in2 ;;			// len -= 8
704	cmp.ne	p6,p0=r0,in2			// done?
705(p6)	br.cond.spnt.few 4b			// again
706
707	br.ret.sptk.few rp			// return
708
709	// Don't bother optimising overlap case
710
7115:	add	in0=in0,in2
712	add	in1=in1,in2 ;;
713	add	in0=-1,in0
714	add	in1=-1,in1 ;;
715
7166:	ld1	r14=[in0],-1 ;;
717	st1	[in1]=r14,-1
718	add	in2=-1,in2 ;;
719	cmp.ne	p6,p0=r0,in2
720(p6)	br.cond.spnt.few 6b
721
722	br.ret.sptk.few rp
723END(bcopy)
724
725ENTRY(memcpy,3)
726	mov	r14=in0 ;;
727	mov	in0=in1 ;;
728	mov	in1=r14
729	br.cond.sptk.few bcopy
730END(memcpy)
731
732ENTRY(copyin, 3)
733	.prologue
734	.regstk	3, 3, 3, 0
735	.save	ar.pfs,loc0
736	alloc	loc0=ar.pfs,3,3,3,0
737	.save	rp,loc1
738	mov	loc1=rp
739	.body
740
741	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
742	;;
743	cmp.geu	p6,p0=in0,loc2			// is in user space.
744	;;
745(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
746	movl	r14=copyerr			// set up fault handler.
747	add	r15=PC_CURTHREAD,r13		// find curthread
748	;;
749	ld8	r15=[r15]
750	;;
751	add	r15=TD_PCB,r15			// find pcb
752	;;
753	ld8	r15=[r15]
754	;;
755	add	loc2=PCB_ONFAULT,r15
756	;;
757	st8	[loc2]=r14
758	;;
759	mov	out0=in0
760	mov	out1=in1
761	mov	out2=in2
762	;;
763	br.call.sptk.few rp=bcopy		// do the copy.
764	st8	[loc2]=r0			// kill the fault handler.
765	mov	ar.pfs=loc0			// restore ar.pfs
766	mov	rp=loc1				// restore ra.
767	br.ret.sptk.few rp			// ret0 left over from bcopy
768END(copyin)
769
770ENTRY(copyout, 3)
771	.prologue
772	.regstk	3, 3, 3, 0
773	.save	ar.pfs,loc0
774	alloc	loc0=ar.pfs,3,3,3,0
775	.save	rp,loc1
776	mov	loc1=rp
777	.body
778
779	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
780	;;
781	cmp.geu	p6,p0=in1,loc2			// is in user space.
782	;;
783(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
784	movl	r14=copyerr			// set up fault handler.
785	add	r15=PC_CURTHREAD,r13		// find curthread
786	;;
787	ld8	r15=[r15]
788	;;
789	add	r15=TD_PCB,r15			// find pcb
790	;;
791	ld8	r15=[r15]
792	;;
793	add	loc2=PCB_ONFAULT,r15
794	;;
795	st8	[loc2]=r14
796	;;
797	mov	out0=in0
798	mov	out1=in1
799	mov	out2=in2
800	;;
801	br.call.sptk.few rp=bcopy		// do the copy.
802	st8	[loc2]=r0			// kill the fault handler.
803	mov	ar.pfs=loc0			// restore ar.pfs
804	mov	rp=loc1				// restore ra.
805	br.ret.sptk.few rp			// ret0 left over from bcopy
806END(copyout)
807
808ENTRY(copyerr, 0)
809	add	r14=PC_CURTHREAD,r13 ;;		// find curthread
810	ld8	r14=[r14] ;;
811	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
812	ld8	r14=[r14] ;;
813	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
814	st8	[r14]=r0			// reset fault handler
815
816	mov	ret0=EFAULT			// return EFAULT
817	br.ret.sptk.few rp
818END(copyerr)
819
820#if defined(GPROF)
821/*
822 * Important registers:
823 *      r8      structure return address
824 *      rp      our return address
825 *      in0     caller's ar.pfs
826 *      in1     caller's gp
827 *      in2     caller's rp
828 *      in3     GOT entry
829 *      ar.pfs  our pfs
830 */
831ENTRY_NOPROFILE(_mcount, 4)
832	alloc		loc0 = ar.pfs, 4, 3, 2, 0
833	mov		loc1 = r8
834	mov		loc2 = rp
835	;;
836	mov		out0 = in2
837	mov		out1 = rp
838	br.call.sptk	rp = __mcount
839	;;
8401:
841	mov		gp = in1
842	mov		r14 = ip
843	mov		b7 = loc2
844	;;
845	add		r14 = 2f - 1b, r14
846	mov		ar.pfs = loc0
847	mov		rp = in2
848	;;
849	mov		b7 = r14
850	mov		b6 = loc2
851	mov		r8 = loc1
852	mov		r14 = in0
853	br.ret.sptk	b7
854	;;
8552:
856	mov		ar.pfs = r14
857	br.sptk		b6
858	;;
859END(_mcount)
860#endif
861