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