]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/ia64/ia64/support.S
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 /*
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  */
71 ENTRY_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         ;;
93 1:      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         
106 2:      mov     ar.rsc=r19              // restore ar.rsc
107         br.ret.sptk.few rp              // now in new mode
108 END(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  */
121 ENTRY(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
133 END(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  */
146 ENTRY(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
181 END(ia64_call_efi_physical)
182         
183 /**************************************************************************/
184
185 ENTRY(fusufault, 0)
186 {       .mib
187         st8.rel         [r15]=r0                // Clear onfault.
188         add             ret0=-1,r0
189         br.ret.sptk     rp
190         ;;
191 }
192 END(fusufault)
193
194 /*
195  * casuword(u_long *p, u_long old, u_long new)
196  *      Perform a compare-exchange in user space.
197  */
198 ENTRY(casuword, 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 }
235 1:
236 {       .mfb
237         add             ret0=-1,r0
238         nop             0
239         br.ret.sptk     rp
240         ;;
241 }
242 END(casuword)
243
244 /*
245  * casuword32(uint32_t *p, uint32_t old, uint32_t new)
246  *      Perform a 32-bit compare-exchange in user space.
247  */
248 ENTRY(casuword32, 3)
249 {       .mlx
250         add             r15=PC_CURTHREAD,r13
251         movl            r14=VM_MAX_ADDRESS
252         ;;
253 }
254 {       .mib
255         ld8             r15=[r15]               // r15 = curthread
256         cmp.geu         p6,p0=in0,r14
257 (p6)    br.dpnt.few     1f
258         ;;
259 }
260 {       .mlx
261         add             r15=TD_PCB,r15
262         movl            r14=fusufault
263         ;;
264 }
265 {       .mmi
266         ld8             r15=[r15]               // r15 = PCB
267         ;;
268         mov             ar.ccv=in1
269         add             r15=PCB_ONFAULT,r15
270         ;;
271 }
272 {       .mmi
273         st8             [r15]=r14               // Set onfault
274         ;;
275         cmpxchg4.rel    ret0=[in0],in2,ar.ccv
276         nop             0
277         ;;
278 }
279 {       .mfb
280         st8.rel         [r15]=r0                // Clear onfault
281         nop             0
282         br.ret.sptk     rp
283         ;;
284 }
285 1:
286 {       .mfb
287         add             ret0=-1,r0
288         nop             0
289         br.ret.sptk     rp
290         ;;
291 }
292 END(casuword32)
293
294 /*
295  * subyte(void *addr, int byte)
296  * suword16(void *addr, int word)
297  * suword32(void *addr, int word)
298  * suword64|suword(void *addr, long word)
299  *      Store in user space
300  */
301
302 ENTRY(subyte, 2)
303 {       .mlx
304         add             r15=PC_CURTHREAD,r13
305         movl            r14=VM_MAX_ADDRESS
306         ;;
307 }
308 {       .mib
309         ld8             r15=[r15]               // r15 = curthread
310         cmp.geu         p6,p0=in0,r14
311 (p6)    br.dpnt.few     1f
312         ;;
313 }
314 {       .mlx
315         add             r15=TD_PCB,r15
316         movl            r14=fusufault
317         ;;
318 }
319 {       .mmi
320         ld8             r15=[r15]               // r15 = PCB
321         ;;
322         nop             0
323         add             r15=PCB_ONFAULT,r15
324         ;;
325 }
326 {       .mmi
327         st8             [r15]=r14               // Set onfault
328         ;;
329         st1.rel         [in0]=in1
330         nop             0
331         ;;
332 }
333 {       .mib
334         st8.rel         [r15]=r0                // Clear onfault
335         mov             ret0=r0
336         br.ret.sptk     rp
337         ;;
338 }
339 1:
340 {       .mfb
341         add             ret0=-1,r0
342         nop             0
343         br.ret.sptk     rp
344         ;;
345 }
346 END(subyte)
347
348 ENTRY(suword16, 2)
349 {       .mlx
350         add             r15=PC_CURTHREAD,r13
351         movl            r14=VM_MAX_ADDRESS
352         ;;
353 }
354 {       .mib
355         ld8             r15=[r15]               // r15 = curthread
356         cmp.geu         p6,p0=in0,r14
357 (p6)    br.dpnt.few     1f
358         ;;
359 }
360 {       .mlx
361         add             r15=TD_PCB,r15
362         movl            r14=fusufault
363         ;;
364 }
365 {       .mmi
366         ld8             r15=[r15]               // r15 = PCB
367         ;;
368         nop             0
369         add             r15=PCB_ONFAULT,r15
370         ;;
371 }
372 {       .mmi
373         st8             [r15]=r14               // Set onfault
374         ;;
375         st2.rel         [in0]=in1
376         nop             0
377         ;;
378 }
379 {       .mib
380         st8.rel         [r15]=r0                // Clear onfault
381         mov             ret0=r0
382         br.ret.sptk     rp
383         ;;
384 }
385 1:
386 {       .mfb
387         add             ret0=-1,r0
388         nop             0
389         br.ret.sptk     rp
390         ;;
391 }
392 END(suword16)
393
394 ENTRY(suword32, 2)
395 {       .mlx
396         add             r15=PC_CURTHREAD,r13
397         movl            r14=VM_MAX_ADDRESS
398         ;;
399 }
400 {       .mib
401         ld8             r15=[r15]               // r15 = curthread
402         cmp.geu         p6,p0=in0,r14
403 (p6)    br.dpnt.few     1f
404         ;;
405 }
406 {       .mlx
407         add             r15=TD_PCB,r15
408         movl            r14=fusufault
409         ;;
410 }
411 {       .mmi
412         ld8             r15=[r15]               // r15 = PCB
413         ;;
414         nop             0
415         add             r15=PCB_ONFAULT,r15
416         ;;
417 }
418 {       .mmi
419         st8             [r15]=r14               // Set onfault
420         ;;
421         st4.rel         [in0]=in1
422         nop             0
423         ;;
424 }
425 {       .mib
426         st8.rel         [r15]=r0                // Clear onfault
427         mov             ret0=r0
428         br.ret.sptk     rp
429         ;;
430 }
431 1:
432 {       .mfb
433         add             ret0=-1,r0
434         nop             0
435         br.ret.sptk     rp
436         ;;
437 }
438 END(suword32)
439
440 ENTRY(suword64, 2)
441 XENTRY(suword)
442 {       .mlx
443         add             r15=PC_CURTHREAD,r13
444         movl            r14=VM_MAX_ADDRESS
445         ;;
446 }
447 {       .mib
448         ld8             r15=[r15]               // r15 = curthread
449         cmp.geu         p6,p0=in0,r14
450 (p6)    br.dpnt.few     1f
451         ;;
452 }
453 {       .mlx
454         add             r15=TD_PCB,r15
455         movl            r14=fusufault
456         ;;
457 }
458 {       .mmi
459         ld8             r15=[r15]               // r15 = PCB
460         ;;
461         nop             0
462         add             r15=PCB_ONFAULT,r15
463         ;;
464 }
465 {       .mmi
466         st8             [r15]=r14               // Set onfault
467         ;;
468         st8.rel         [in0]=in1
469         nop             0
470         ;;
471 }
472 {       .mib
473         st8.rel         [r15]=r0                // Clear onfault
474         mov             ret0=r0
475         br.ret.sptk     rp
476         ;;
477 }
478 1:
479 {       .mfb
480         add             ret0=-1,r0
481         nop             0
482         br.ret.sptk     rp
483         ;;
484 }
485 END(suword64)
486
487 /*
488  * fubyte(void *addr, int byte)
489  * fuword16(void *addr, int word)
490  * fuword32(void *addr, int word)
491  * fuword64|fuword(void *addr, long word)
492  *      Fetch from user space
493  */
494
495 ENTRY(fubyte, 1)
496 {       .mlx
497         add             r15=PC_CURTHREAD,r13
498         movl            r14=VM_MAX_ADDRESS
499         ;;
500 }
501 {       .mib
502         ld8             r15=[r15]               // r15 = curthread
503         cmp.geu         p6,p0=in0,r14
504 (p6)    br.dpnt.few     1f
505         ;;
506 }
507 {       .mlx
508         add             r15=TD_PCB,r15
509         movl            r14=fusufault
510         ;;
511 }
512 {       .mmi
513         ld8             r15=[r15]               // r15 = PCB
514         ;;
515         nop             0
516         add             r15=PCB_ONFAULT,r15
517         ;;
518 }
519 {       .mmi
520         st8             [r15]=r14               // Set onfault
521         ;;
522         mf
523         nop             0
524         ;;
525 }
526 {       .mmb
527         ld1             ret0=[in0]
528         st8.rel         [r15]=r0                // Clear onfault
529         br.ret.sptk     rp
530         ;;
531 }
532 1:
533 {       .mfb
534         add             ret0=-1,r0
535         nop             0
536         br.ret.sptk     rp
537         ;;
538 }
539 END(fubyte)
540
541 ENTRY(fuword16, 2)
542 {       .mlx
543         add             r15=PC_CURTHREAD,r13
544         movl            r14=VM_MAX_ADDRESS
545         ;;
546 }
547 {       .mib
548         ld8             r15=[r15]               // r15 = curthread
549         cmp.geu         p6,p0=in0,r14
550 (p6)    br.dpnt.few     1f
551         ;;
552 }
553 {       .mlx
554         add             r15=TD_PCB,r15
555         movl            r14=fusufault
556         ;;
557 }
558 {       .mmi
559         ld8             r15=[r15]               // r15 = PCB
560         ;;
561         nop             0
562         add             r15=PCB_ONFAULT,r15
563         ;;
564 }
565 {       .mmi
566         st8             [r15]=r14               // Set onfault
567         ;;
568         mf
569         nop             0
570         ;;
571 }
572 {       .mmb
573         ld2             ret0=[in0]
574         st8.rel         [r15]=r0                // Clear onfault
575         br.ret.sptk     rp
576         ;;
577 }
578 1:
579 {       .mfb
580         add             ret0=-1,r0
581         nop             0
582         br.ret.sptk     rp
583         ;;
584 }
585 END(fuword16)
586
587 ENTRY(fuword32, 2)
588 {       .mlx
589         add             r15=PC_CURTHREAD,r13
590         movl            r14=VM_MAX_ADDRESS
591         ;;
592 }
593 {       .mib
594         ld8             r15=[r15]               // r15 = curthread
595         cmp.geu         p6,p0=in0,r14
596 (p6)    br.dpnt.few     1f
597         ;;
598 }
599 {       .mlx
600         add             r15=TD_PCB,r15
601         movl            r14=fusufault
602         ;;
603 }
604 {       .mmi
605         ld8             r15=[r15]               // r15 = PCB
606         ;;
607         nop             0
608         add             r15=PCB_ONFAULT,r15
609         ;;
610 }
611 {       .mmi
612         st8             [r15]=r14               // Set onfault
613         ;;
614         mf
615         nop             0
616         ;;
617 }
618 {       .mmb
619         ld4             ret0=[in0]
620         st8.rel         [r15]=r0                // Clear onfault
621         br.ret.sptk     rp
622         ;;
623 }
624 1:
625 {       .mfb
626         add             ret0=-1,r0
627         nop             0
628         br.ret.sptk     rp
629         ;;
630 }
631 END(fuword32)
632
633 ENTRY(fuword64, 2)
634 XENTRY(fuword)
635 {       .mlx
636         add             r15=PC_CURTHREAD,r13
637         movl            r14=VM_MAX_ADDRESS
638         ;;
639 }
640 {       .mib
641         ld8             r15=[r15]               // r15 = curthread
642         cmp.geu         p6,p0=in0,r14
643 (p6)    br.dpnt.few     1f
644         ;;
645 }
646 {       .mlx
647         add             r15=TD_PCB,r15
648         movl            r14=fusufault
649         ;;
650 }
651 {       .mmi
652         ld8             r15=[r15]               // r15 = PCB
653         ;;
654         nop             0
655         add             r15=PCB_ONFAULT,r15
656         ;;
657 }
658 {       .mmi
659         st8             [r15]=r14               // Set onfault
660         ;;
661         mf
662         nop             0
663         ;;
664 }
665 {       .mmb
666         ld8             ret0=[in0]
667         st8.rel         [r15]=r0                // Clear onfault
668         br.ret.sptk     rp
669         ;;
670 }
671 1:
672 {       .mfb
673         add             ret0=-1,r0
674         nop             0
675         br.ret.sptk     rp
676         ;;
677 }
678 END(fuword64)
679
680 /*
681  * fuswintr(void *addr)
682  * suswintr(void *addr)
683  */
684
685 ENTRY(fuswintr, 1)
686 {       .mfb
687         add             ret0=-1,r0
688         nop             0
689         br.ret.sptk     rp
690         ;;
691 }
692 END(fuswintr)
693
694 ENTRY(suswintr, 0)
695 {       .mfb
696         add             ret0=-1,r0
697         nop             0
698         br.ret.sptk     rp
699         ;;
700 }
701 END(suswintr)
702
703 /**************************************************************************/
704
705 /*
706  * Copy a null-terminated string within the kernel's address space.
707  * If lenp is not NULL, store the number of chars copied in *lenp
708  *
709  * int copystr(char *from, char *to, size_t len, size_t *lenp);
710  */
711 ENTRY(copystr, 4)
712         mov     r14=in2                 // r14 = i = len
713         cmp.eq  p6,p0=r0,in2
714 (p6)    br.cond.spnt.few 2f             // if (len == 0), bail out
715
716 1:      ld1     r15=[in0],1             // read one byte
717         ;;
718         st1     [in1]=r15,1             // write that byte
719         add     in2=-1,in2              // len--
720         ;;
721         cmp.eq  p6,p0=r0,r15
722         cmp.ne  p7,p0=r0,in2
723         ;; 
724 (p6)    br.cond.spnt.few 2f             // if (*from == 0), bail out
725 (p7)    br.cond.sptk.few 1b             // if (len != 0) copy more
726
727 2:      cmp.eq  p6,p0=r0,in3
728 (p6)    br.cond.dpnt.few 3f             // if (lenp != NULL)
729         sub     r14=r14,in2             // *lenp = (i - len)
730         ;;
731         st8     [in3]=r14
732         
733 3:      cmp.eq  p6,p0=r0,r15
734 (p6)    br.cond.spnt.few 4f             // *from == '\0'; leave quietly
735
736         mov     ret0=ENAMETOOLONG       // *from != '\0'; error.
737         br.ret.sptk.few rp
738
739 4:      mov     ret0=0                  // return 0.
740         br.ret.sptk.few rp
741 END(copystr)
742
743 ENTRY(copyinstr, 4)
744         .prologue
745         .regstk 4, 3, 4, 0
746         .save   ar.pfs,loc0
747         alloc   loc0=ar.pfs,4,3,4,0
748         .save   rp,loc1
749         mov     loc1=rp
750         .body
751
752         movl    loc2=VM_MAX_ADDRESS             // make sure that src addr
753         ;; 
754         cmp.geu p6,p0=in0,loc2                  // is in user space.
755         ;; 
756 (p6)    br.cond.spnt.few copyerr                // if it's not, error out.
757         movl    r14=copyerr                     // set up fault handler.
758         add     r15=PC_CURTHREAD,r13            // find curthread
759         ;;
760         ld8     r15=[r15]
761         ;;
762         add     r15=TD_PCB,r15                  // find pcb
763         ;;
764         ld8     r15=[r15]
765         ;;
766         add     loc2=PCB_ONFAULT,r15
767         ;;
768         st8     [loc2]=r14
769         ;;
770         mov     out0=in0
771         mov     out1=in1
772         mov     out2=in2
773         mov     out3=in3
774         ;;
775         br.call.sptk.few rp=copystr             // do the copy.
776         st8     [loc2]=r0                       // kill the fault handler.
777         mov     ar.pfs=loc0                     // restore ar.pfs
778         mov     rp=loc1                         // restore ra.
779         br.ret.sptk.few rp                      // ret0 left over from copystr
780 END(copyinstr)
781
782 /*
783  * Not the fastest bcopy in the world.
784  */
785 ENTRY(bcopy, 3)
786         mov     ret0=r0                         // return zero for copy{in,out}
787         ;; 
788         cmp.le  p6,p0=in2,r0                    // bail if len <= 0
789 (p6)    br.ret.spnt.few rp
790
791         sub     r14=in1,in0 ;;                  // check for overlap
792         cmp.ltu p6,p0=r14,in2                   // dst-src < len
793 (p6)    br.cond.spnt.few 5f
794
795         extr.u  r14=in0,0,3                     // src & 7
796         extr.u  r15=in1,0,3 ;;                  // dst & 7
797         cmp.eq  p6,p0=r14,r15                   // different alignment?
798 (p6)    br.cond.spnt.few 2f                     // branch if same alignment
799
800 1:      ld1     r14=[in0],1 ;;                  // copy bytewise
801         st1     [in1]=r14,1
802         add     in2=-1,in2 ;;                   // len--
803         cmp.ne  p6,p0=r0,in2
804 (p6)    br.cond.dptk.few 1b                     // loop
805         br.ret.sptk.few rp                      // done
806
807 2:      cmp.eq  p6,p0=r14,r0                    // aligned?
808 (p6)    br.cond.sptk.few 4f
809
810 3:      ld1     r14=[in0],1 ;;                  // copy bytewise
811         st1     [in1]=r14,1
812         extr.u  r15=in0,0,3                     // src & 7
813         add     in2=-1,in2 ;;                   // len--
814         cmp.eq  p6,p0=r0,in2                    // done?
815         cmp.eq  p7,p0=r0,r15 ;;                 // aligned now?
816 (p6)    br.ret.spnt.few rp                      // return if done
817 (p7)    br.cond.spnt.few 4f                     // go to main copy
818         br.cond.sptk.few 3b                     // more bytes to copy
819
820         // At this point, in2 is non-zero
821
822 4:      mov     r14=8 ;;
823         cmp.ltu p6,p0=in2,r14 ;;                // len < 8?
824 (p6)    br.cond.spnt.few 1b                     // byte copy the end
825         ld8     r15=[in0],8 ;;                  // copy word
826         st8     [in1]=r15,8
827         add     in2=-8,in2 ;;                   // len -= 8
828         cmp.ne  p6,p0=r0,in2                    // done?
829 (p6)    br.cond.spnt.few 4b                     // again
830
831         br.ret.sptk.few rp                      // return
832
833         // Don't bother optimising overlap case
834
835 5:      add     in0=in0,in2
836         add     in1=in1,in2 ;;
837         add     in0=-1,in0
838         add     in1=-1,in1 ;;
839
840 6:      ld1     r14=[in0],-1 ;;
841         st1     [in1]=r14,-1
842         add     in2=-1,in2 ;;
843         cmp.ne  p6,p0=r0,in2
844 (p6)    br.cond.spnt.few 6b
845
846         br.ret.sptk.few rp
847 END(bcopy)
848
849 ENTRY(memcpy,3)
850         mov     r14=in0 ;;
851         mov     in0=in1 ;;
852         mov     in1=r14
853         br.cond.sptk.few bcopy
854 END(memcpy)
855         
856 ENTRY(copyin, 3)
857         .prologue
858         .regstk 3, 3, 3, 0
859         .save   ar.pfs,loc0
860         alloc   loc0=ar.pfs,3,3,3,0
861         .save   rp,loc1
862         mov     loc1=rp
863         .body
864
865         movl    loc2=VM_MAX_ADDRESS             // make sure that src addr
866         ;; 
867         cmp.geu p6,p0=in0,loc2                  // is in user space.
868         ;; 
869 (p6)    br.cond.spnt.few copyerr                // if it's not, error out.
870         movl    r14=copyerr                     // set up fault handler.
871         add     r15=PC_CURTHREAD,r13            // find curthread
872         ;;
873         ld8     r15=[r15]
874         ;;
875         add     r15=TD_PCB,r15                  // find pcb
876         ;;
877         ld8     r15=[r15]
878         ;;
879         add     loc2=PCB_ONFAULT,r15
880         ;;
881         st8     [loc2]=r14
882         ;;
883         mov     out0=in0
884         mov     out1=in1
885         mov     out2=in2
886         ;;
887         br.call.sptk.few rp=bcopy               // do the copy.
888         st8     [loc2]=r0                       // kill the fault handler.
889         mov     ar.pfs=loc0                     // restore ar.pfs
890         mov     rp=loc1                         // restore ra.
891         br.ret.sptk.few rp                      // ret0 left over from bcopy
892 END(copyin)
893
894 ENTRY(copyout, 3)
895         .prologue
896         .regstk 3, 3, 3, 0
897         .save   ar.pfs,loc0
898         alloc   loc0=ar.pfs,3,3,3,0
899         .save   rp,loc1
900         mov     loc1=rp
901         .body
902
903         movl    loc2=VM_MAX_ADDRESS             // make sure that dest addr
904         ;; 
905         cmp.geu p6,p0=in1,loc2                  // is in user space.
906         ;; 
907 (p6)    br.cond.spnt.few copyerr                // if it's not, error out.
908         movl    r14=copyerr                     // set up fault handler.
909         add     r15=PC_CURTHREAD,r13            // find curthread
910         ;;
911         ld8     r15=[r15]
912         ;;
913         add     r15=TD_PCB,r15                  // find pcb
914         ;;
915         ld8     r15=[r15]
916         ;;
917         add     loc2=PCB_ONFAULT,r15
918         ;;
919         st8     [loc2]=r14
920         ;;
921         mov     out0=in0
922         mov     out1=in1
923         mov     out2=in2
924         ;;
925         br.call.sptk.few rp=bcopy               // do the copy.
926         st8     [loc2]=r0                       // kill the fault handler.
927         mov     ar.pfs=loc0                     // restore ar.pfs
928         mov     rp=loc1                         // restore ra.
929         br.ret.sptk.few rp                      // ret0 left over from bcopy
930 END(copyout)
931
932 ENTRY(copyerr, 0)
933         add     r14=PC_CURTHREAD,r13 ;;         // find curthread
934         ld8     r14=[r14] ;;
935         add     r14=TD_PCB,r14 ;;               // curthread->td_addr
936         ld8     r14=[r14] ;;
937         add     r14=PCB_ONFAULT,r14 ;;          // &curthread->td_pcb->pcb_onfault
938         st8     [r14]=r0                        // reset fault handler
939         
940         mov     ret0=EFAULT                     // return EFAULT
941         br.ret.sptk.few rp
942 END(copyerr)
943
944 #if defined(GPROF)
945 /*
946  * Important registers:
947  *      r8      structure return address
948  *      rp      our return address
949  *      in0     caller's ar.pfs
950  *      in1     caller's gp
951  *      in2     caller's rp
952  *      in3     GOT entry
953  *      ar.pfs  our pfs
954  */
955 ENTRY_NOPROFILE(_mcount, 4)
956         alloc           loc0 = ar.pfs, 4, 3, 2, 0
957         mov             loc1 = r8
958         mov             loc2 = rp
959         ;;
960         mov             out0 = in2
961         mov             out1 = rp
962         br.call.sptk    rp = __mcount
963         ;;
964 1:
965         mov             gp = in1
966         mov             r14 = ip
967         mov             b7 = loc2
968         ;;
969         add             r14 = 2f - 1b, r14
970         mov             ar.pfs = loc0
971         mov             rp = in2
972         ;;
973         mov             b7 = r14
974         mov             b6 = loc2
975         mov             r8 = loc1
976         mov             r14 = in0
977         br.ret.sptk     b7
978         ;;
979 2:
980         mov             ar.pfs = r14
981         br.sptk         b6
982         ;;
983 END(_mcount)
984 #endif