support.S revision 85682
166458Sdfr/*-
266458Sdfr * Copyright (c) 1998 Doug Rabson
366458Sdfr * All rights reserved.
466458Sdfr *
566458Sdfr * Redistribution and use in source and binary forms, with or without
666458Sdfr * modification, are permitted provided that the following conditions
766458Sdfr * are met:
866458Sdfr * 1. Redistributions of source code must retain the above copyright
966458Sdfr *    notice, this list of conditions and the following disclaimer.
1066458Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1166458Sdfr *    notice, this list of conditions and the following disclaimer in the
1266458Sdfr *    documentation and/or other materials provided with the distribution.
1366458Sdfr *
1466458Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1566458Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1666458Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1766458Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1866458Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1966458Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2066458Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2166458Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2266458Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2366458Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2466458Sdfr * SUCH DAMAGE.
2566458Sdfr *
2666458Sdfr * $FreeBSD: head/sys/ia64/ia64/support.S 85682 2001-10-29 11:30:54Z dfr $
2766458Sdfr */
2866458Sdfr/*
2966458Sdfr * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
3066458Sdfr * All rights reserved.
3166458Sdfr *
3266458Sdfr * Author: Chris G. Demetriou
3366458Sdfr *
3466458Sdfr * Permission to use, copy, modify and distribute this software and
3566458Sdfr * its documentation is hereby granted, provided that both the copyright
3666458Sdfr * notice and this permission notice appear in all copies of the
3766458Sdfr * software, derivative works or modified versions, and any portions
3866458Sdfr * thereof, and that both notices appear in supporting documentation.
3966458Sdfr *
4066458Sdfr * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
4166458Sdfr * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
4266458Sdfr * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
4366458Sdfr *
4466458Sdfr * Carnegie Mellon requests users of this software to return to
4566458Sdfr *
4666458Sdfr *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
4766458Sdfr *  School of Computer Science
4866458Sdfr *  Carnegie Mellon University
4966458Sdfr *  Pittsburgh PA 15213-3890
5066458Sdfr *
5166458Sdfr * any improvements or extensions that they make and grant Carnegie the
5266458Sdfr * rights to redistribute these changes.
5366458Sdfr */
5466458Sdfr
5566458Sdfr#include <machine/asm.h>
5683893Sdfr#include <machine/ia64_cpu.h>
5766458Sdfr#include <assym.s>
5866458Sdfr
5966458Sdfr	.text
6066458Sdfr
6183893Sdfr/*
6283893Sdfr * ia64_change_mode:	change mode to/from physical mode
6383893Sdfr *
6483893Sdfr * Arguments:
6583893Sdfr *	r14	psr for desired mode
6684114Sdfr *
6784114Sdfr * Modifies:
6884114Sdfr *	r15-r19	scratch
6984114Sdfr *	ar.bsp	tranlated to new mode
7083893Sdfr */
7183893SdfrENTRY(ia64_change_mode, 0)
7283893Sdfr
7383893Sdfr	rsm	psr.i | psr.ic
7484114Sdfr	mov	r19=ar.rsc		// save rsc while we change mode
7583893Sdfr	tbit.nz	p6,p7=r14,17		// physical or virtual ?
7683893Sdfr	;;
7784114Sdfr	mov	ar.rsc=0		// turn off RSE
7883893Sdfr(p6)	mov	r15=7			// RR base for virtual addresses
7983893Sdfr(p7)	mov	r15=0			// RR base for physical addresses
8083893Sdfr	flushrs				// no dirty registers please
8183893Sdfr	srlz.i
8283893Sdfr	;;
8383893Sdfr	mov	r16=ar.bsp
8483893Sdfr	mov	r17=rp
8583893Sdfr	mov	r18=ar.rnat
8683893Sdfr	;;
8783893Sdfr	dep	r16=r15,r16,61,3	// new address of ar.bsp
8883893Sdfr	dep	r17=r15,r17,61,3	// new address of rp
8984114Sdfr	dep	sp=r15,sp,61,3		// new address of sp
9083893Sdfr	;;
9183893Sdfr	mov	ar.bspstore=r16
9283893Sdfr	mov	rp=r17
9383893Sdfr	;;
9483893Sdfr1:	mov	r16=ip
9583893Sdfr	mov	ar.rnat=r18
9683895Sdfr	mov	cr.ipsr=r14		// psr for new mode
9783893Sdfr	;;
9883893Sdfr	add	r16=2f-1b,r16		// address to rfi to
9983893Sdfr	;;
10083895Sdfr	dep	r16=r15,r16,61,3	// new mode address for rfi
10183893Sdfr	;;
10283893Sdfr	mov	cr.iip=r16		// setup for rfi
10383893Sdfr	mov	cr.ifs=r0
10483893Sdfr	;;
10583893Sdfr	rfi
10683893Sdfr
10784114Sdfr2:	mov	ar.rsc=r19		// restore ar.rsc
10884114Sdfr	br.ret.sptk.few rp		// now in new mode
10983893Sdfr
11083893SdfrEND(ia64_change_mode)
11183893Sdfr
11283893Sdfr/*
11383893Sdfr * ia64_physical_mode:	change mode to physical mode
11483893Sdfr *
11583893Sdfr * Return:
11683893Sdfr *	ret0	psr to restore
11784114Sdfr *
11884114Sdfr * Modifies:
11984114Sdfr *	r15-r18	scratch
12084114Sdfr *	ar.bsp	tranlated to physical mode
12184114Sdfr *	psr.i	cleared
12283893Sdfr */
12383893SdfrENTRY(ia64_physical_mode, 0)
12483893Sdfr
12583893Sdfr	mov	r14=psr
12683893Sdfr	mov	ret0=psr
12784114Sdfr	movl	r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH)
12883893Sdfr	movl	r16=IA64_PSR_BN
12983893Sdfr	;;
13083893Sdfr	andcm	r14=r14,r15		// clear various xT bits
13183893Sdfr	;;
13283893Sdfr	or	r14=r14,r16		// make sure BN=1
13383893Sdfr	or	ret0=ret0,r16		// make sure BN=1
13483893Sdfr
13583893Sdfr	br.cond.sptk.many ia64_change_mode
13683893Sdfr
13783893SdfrEND(ia64_physical_mode)
13883893Sdfr
13984114Sdfr/*
14084114Sdfr * ia64_call_efi_physical:	call an EFI procedure in physical mode
14184114Sdfr *
14284114Sdfr * Arguments:
14384114Sdfr *	in0		Address of EFI procedure descriptor
14484114Sdfr *	in1-in5		Arguments to EFI procedure
14584114Sdfr *
14684114Sdfr * Return:
14784114Sdfr *	ret0-ret3	return values from EFI
14884114Sdfr *
14984114Sdfr */
15084114SdfrENTRY(ia64_call_efi_physical, 6)
15184114Sdfr
15285682Sdfr	.prologue
15385682Sdfr	.regstk	6,4,5,0
15485682Sdfr	.save	ar.pfs,loc0
15584114Sdfr	alloc	loc0=ar.pfs,6,4,5,0
15684114Sdfr	;;
15785682Sdfr	.save	rp,loc1
15884114Sdfr	mov	loc1=rp
15984114Sdfr	;;
16085682Sdfr	.body
16184114Sdfr	br.call.sptk.many rp=ia64_physical_mode
16284114Sdfr	;;
16384114Sdfr	mov	loc2=r8			// psr to restore mode
16484114Sdfr	mov	loc3=gp			// save kernel gp
16584114Sdfr	ld8	r14=[in0],8		// function address
16684114Sdfr	;;
16784114Sdfr	mov	out0=in1
16884114Sdfr	mov	out1=in2
16984114Sdfr	mov	out2=in3
17084114Sdfr	mov	out3=in4
17184114Sdfr	mov	out4=in5
17284114Sdfr	ld8	gp=[in0]		// function gp value
17384114Sdfr	;;
17484114Sdfr	mov	b6=r14
17584114Sdfr	;;
17684114Sdfr	br.call.sptk.many rp=b6		// call EFI procedure
17784114Sdfr	mov	gp=loc3			// restore kernel gp
17884114Sdfr	;;
17984114Sdfr	mov	r14=loc2		// psr to restore mode
18084114Sdfr	br.call.sptk.many rp=ia64_change_mode
18184114Sdfr	;;
18284114Sdfr	mov	rp=loc1
18384114Sdfr	mov	ar.pfs=loc0
18484114Sdfr	;;
18584114Sdfr	br.ret.sptk.many rp
18684114Sdfr
18784114SdfrEND(ia64_call_efi_physical)
18884114Sdfr
18966458Sdfr/**************************************************************************/
19066458Sdfr
19166458Sdfr/*
19266458Sdfr * fu{byte,word} : fetch a byte (word) from user memory
19366458Sdfr */
19466458Sdfr
19566633SdfrENTRY(suword, 2)
19666458Sdfr
19766633Sdfr	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
19866633Sdfr	cmp.geu	p6,p0=in0,r14
19966633Sdfr(p6)	br.dpnt.few fusufault
20066458Sdfr
20166633Sdfr	movl	r14=fusufault			// set up fault handler.
20283366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
20366633Sdfr	;;
20466633Sdfr	ld8	r15=[r15]
20566633Sdfr	;;
20683366Sjulian	add	r15=TD_PCB,r15			// find pcb
20766633Sdfr	;;
20866633Sdfr	ld8	r15=[r15]
20966633Sdfr	;;
21083366Sjulian	add	r15=PCB_ONFAULT,r15
21166633Sdfr	;;
21266633Sdfr	st8	[r15]=r14
21366633Sdfr	;;
21466633Sdfr	st8.rel	[in0]=in1			// try the store
21566633Sdfr	;;
21666633Sdfr	st8	[r15]=r0			// clean up
21766458Sdfr
21866633Sdfr	mov	ret0=r0
21966633Sdfr	br.ret.sptk.few rp
22066458Sdfr
22166486SdfrEND(suword)
22266458Sdfr
22366633SdfrENTRY(subyte, 2)
22466458Sdfr
22566633Sdfr	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
22666633Sdfr	cmp.geu	p6,p0=in0,r14
22766633Sdfr(p6)	br.dpnt.few fusufault
22866458Sdfr
22966633Sdfr	movl	r14=fusufault			// set up fault handler.
23083366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
23166633Sdfr	;;
23266633Sdfr	ld8	r15=[r15]
23366633Sdfr	;;
23483366Sjulian	add	r15=TD_PCB,r15			// find pcb
23566633Sdfr	;;
23666633Sdfr	ld8	r15=[r15]
23766633Sdfr	;;
23883366Sjulian	add	r15=PCB_ONFAULT,r15
23966633Sdfr	;;
24066633Sdfr	st8	[r15]=r14
24166633Sdfr	;;
24266633Sdfr	st1.rel	[in0]=in1			// try the store
24366633Sdfr	;;
24466633Sdfr	st8	[r15]=r0			// clean up
24566458Sdfr
24666633Sdfr	mov	ret0=r0
24766633Sdfr	br.ret.sptk.few rp
24866458Sdfr
24966486SdfrEND(subyte)
25066458Sdfr
25166633SdfrENTRY(fuword, 1)
25266458Sdfr
25366633Sdfr	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
25466633Sdfr	cmp.geu	p6,p0=in0,r14
25566633Sdfr(p6)	br.dpnt.few fusufault
25666458Sdfr
25766633Sdfr	movl	r14=fusufault			// set up fault handler.
25883366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
25966633Sdfr	;;
26066633Sdfr	ld8	r15=[r15]
26166633Sdfr	;;
26283366Sjulian	add	r15=TD_PCB,r15			// find pcb
26366633Sdfr	;;
26466633Sdfr	ld8	r15=[r15]
26566633Sdfr	;;
26683366Sjulian	add	r15=PCB_ONFAULT,r15
26766633Sdfr	;;
26866633Sdfr	st8	[r15]=r14
26966633Sdfr	;;
27066633Sdfr	ld8.acq	ret0=[in0]			// try the fetch
27166633Sdfr	;;
27266633Sdfr	st8	[r15]=r0			// clean up
27366458Sdfr
27466633Sdfr	br.ret.sptk.few rp
27566458Sdfr
27666486SdfrEND(fuword)
27766458Sdfr
27866633SdfrENTRY(fubyte, 1)
27966458Sdfr
28066633Sdfr	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
28166633Sdfr	cmp.geu	p6,p0=in0,r14
28266633Sdfr(p6)	br.dpnt.few fusufault
28366458Sdfr
28466633Sdfr	movl	r14=fusufault			// set up fault handler.
28583366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
28666633Sdfr	;;
28766633Sdfr	ld8	r15=[r15]
28866633Sdfr	;;
28983366Sjulian	add	r15=TD_PCB,r15			// find pcb
29066633Sdfr	;;
29166633Sdfr	ld8	r15=[r15]
29266633Sdfr	;;
29383366Sjulian	add	r15=PCB_ONFAULT,r15
29466633Sdfr	;;
29566633Sdfr	st8	[r15]=r14
29666633Sdfr	;;
29766633Sdfr	ld1.acq	ret0=[in0]			// try the fetch
29866633Sdfr	;;
29966633Sdfr	st8	[r15]=r0			// clean up
30066458Sdfr
30166633Sdfr	br.ret.sptk.few rp
30266458Sdfr
30366486SdfrEND(fubyte)
30466458Sdfr
30566633SdfrENTRY(suibyte, 2)
30666633Sdfr	mov	ret0=-1
30766633Sdfr	br.ret.sptk.few rp
30866633SdfrEND(suibyte)
30966458Sdfr
31066633SdfrENTRY(fusufault, 0)
31166633Sdfr	st8	[r15]=r0 ;;			// r15 points at onfault
31266633Sdfr	mov	ret0=r0
31366633Sdfr	br.ret.sptk.few rp
31466486SdfrEND(fusufault)
31566458Sdfr
31666633SdfrENTRY(fswintrberr, 0)
31766633SdfrXENTRY(fuswintr)					/* XXX what is a 'word'? */
31866633SdfrXENTRY(suswintr)					/* XXX what is a 'word'? */
31966633Sdfr	mov	ret0=-1
32066633Sdfr	br.ret.sptk.few rp
32166486SdfrEND(fswintrberr)
32266458Sdfr
32366458Sdfr/**************************************************************************/
32466458Sdfr
32566458Sdfr/*
32666458Sdfr * Copy a null-terminated string within the kernel's address space.
32766458Sdfr * If lenp is not NULL, store the number of chars copied in *lenp
32866458Sdfr *
32966458Sdfr * int copystr(char *from, char *to, size_t len, size_t *lenp);
33066458Sdfr */
33166633SdfrENTRY(copystr, 4)
33266486Sdfr	mov	r14=in2			// r14 = i = len
33366486Sdfr	cmp.eq	p6,p0=r0,in2
33466486Sdfr(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
33566458Sdfr
33666486Sdfr1:	ld1	r15=[in0],1		// read one byte
33766486Sdfr	;;
33866486Sdfr	st1	[in1]=r15,1		// write that byte
33966486Sdfr	add	in2=-1,in2		// len--
34066486Sdfr	;;
34166486Sdfr	cmp.eq	p6,p0=r0,r15
34266486Sdfr	cmp.ne	p7,p0=r0,in2
34366486Sdfr	;;
34466486Sdfr(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
34566486Sdfr(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
34666458Sdfr
34766486Sdfr2:	cmp.eq	p6,p0=r0,in3
34866486Sdfr(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
34967020Sdfr	sub	r14=r14,in2		// *lenp = (i - len)
35066486Sdfr	;;
35166486Sdfr	st8	[in3]=r14
35266486Sdfr
35366486Sdfr3:	cmp.eq	p6,p0=r0,r15
35466486Sdfr(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
35566458Sdfr
35666486Sdfr	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
35766486Sdfr	br.ret.sptk.few rp
35866458Sdfr
35966486Sdfr4:	mov	ret0=0			// return 0.
36066486Sdfr	br.ret.sptk.few rp
36166486Sdfr
36266486SdfrEND(copystr)
36366458Sdfr
36466633SdfrENTRY(copyinstr, 4)
36585682Sdfr	.prologue
36685682Sdfr	.regstk	4, 3, 4, 0
36785682Sdfr	.save	ar.pfs,loc0
36866486Sdfr	alloc	loc0=ar.pfs,4,3,4,0
36985682Sdfr	.save	rp,loc1
37066486Sdfr	mov	loc1=rp
37185682Sdfr	.body
37266458Sdfr
37366486Sdfr	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
37466486Sdfr	;;
37566633Sdfr	cmp.geu	p6,p0=in0,loc2			// is in user space.
37666486Sdfr	;;
37766486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
37866486Sdfr	movl	r14=copyerr			// set up fault handler.
37983366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
38066486Sdfr	;;
38166486Sdfr	ld8	r15=[r15]
38266486Sdfr	;;
38383366Sjulian	add	r15=TD_PCB,r15			// find pcb
38466486Sdfr	;;
38566486Sdfr	ld8	r15=[r15]
38666486Sdfr	;;
38783366Sjulian	add	loc2=PCB_ONFAULT,r15
38866486Sdfr	;;
38966486Sdfr	st8	[loc2]=r14
39066486Sdfr	;;
39166486Sdfr	mov	out0=in0
39266486Sdfr	mov	out1=in1
39366486Sdfr	mov	out2=in2
39466486Sdfr	mov	out3=in3
39566486Sdfr	;;
39666486Sdfr	br.call.sptk.few rp=copystr		// do the copy.
39766486Sdfr	st8	[loc2]=r0			// kill the fault handler.
39867020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
39966486Sdfr	mov	rp=loc1				// restore ra.
40066486Sdfr	br.ret.sptk.few rp			// ret0 left over from copystr
40166458Sdfr
40266486SdfrEND(copyinstr)
40366458Sdfr
40466633SdfrENTRY(copyoutstr, 4)
40585682Sdfr	.prologue
40685682Sdfr	.regstk	4, 3, 4, 0
40785682Sdfr	.save	ar.pfs,loc0
40866486Sdfr	alloc	loc0=ar.pfs,4,3,4,0
40985682Sdfr	.save	rp,loc1
41066486Sdfr	mov	loc1=rp
41185682Sdfr	.body
41266458Sdfr
41366486Sdfr	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
41466486Sdfr	;;
41566633Sdfr	cmp.geu	p6,p0=in1,loc2			// is in user space.
41666486Sdfr	;;
41766486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
41866486Sdfr	movl	r14=copyerr			// set up fault handler.
41983366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
42066486Sdfr	;;
42166486Sdfr	ld8	r15=[r15]
42266486Sdfr	;;
42383366Sjulian	add	r15=TD_PCB,r15			// find pcb
42466486Sdfr	;;
42566486Sdfr	ld8	r15=[r15]
42666486Sdfr	;;
42783366Sjulian	add	loc2=PCB_ONFAULT,r15
42866486Sdfr	;;
42966486Sdfr	st8	[loc2]=r14
43066486Sdfr	;;
43166486Sdfr	mov	out0=in0
43266486Sdfr	mov	out1=in1
43366486Sdfr	mov	out2=in2
43466486Sdfr	mov	out3=in3
43566486Sdfr	;;
43666486Sdfr	br.call.sptk.few rp=copystr		// do the copy.
43766486Sdfr	st8	[loc2]=r0			// kill the fault handler.
43867020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
43966486Sdfr	mov	rp=loc1				// restore ra.
44066486Sdfr	br.ret.sptk.few rp			// ret0 left over from copystr
44166486Sdfr
44266486SdfrEND(copyoutstr)
44366486Sdfr
44466458Sdfr/*
44566486Sdfr * Not the fastest bcopy in the world.
44666458Sdfr */
44766633SdfrENTRY(bcopy, 3)
44866633SdfrXENTRY(ovbcopy)
44966458Sdfr
45066486Sdfr	mov	ret0=r0				// return zero for copy{in,out}
45166486Sdfr	;;
45266486Sdfr	cmp.le	p6,p0=in2,r0			// bail if len <= 0
45366486Sdfr(p6)	br.ret.spnt.few rp
45466458Sdfr
45566486Sdfr	sub	r14=in1,in0 ;;			// check for overlap
45666486Sdfr	cmp.ltu	p6,p0=r14,in2			// dst-src < len
45766486Sdfr(p6)	br.cond.spnt.few 5f
45866458Sdfr
45966486Sdfr	extr.u	r14=in0,0,3			// src & 7
46066486Sdfr	extr.u	r15=in1,0,3 ;;			// dst & 7
46166486Sdfr	cmp.eq	p6,p0=r14,r15			// different alignment?
46266486Sdfr(p6)	br.cond.spnt.few 2f			// branch if same alignment
46366458Sdfr
46466486Sdfr1:	ld1	r14=[in0],1 ;;			// copy bytewise
46566486Sdfr	st1	[in1]=r14,1
46666486Sdfr	add	in2=-1,in2 ;;			// len--
46766486Sdfr	cmp.ne	p6,p0=r0,in2
46866486Sdfr(p6)	br.cond.dptk.few 1b			// loop
46966486Sdfr	br.ret.sptk.few rp			// done
47066458Sdfr
47166486Sdfr2:	cmp.eq	p6,p0=r14,r0			// aligned?
47266486Sdfr(p6)	br.cond.sptk.few 4f
47366458Sdfr
47466486Sdfr3:	ld1	r14=[in0],1 ;;			// copy bytewise
47566486Sdfr	st1	[in1]=r14,1
47666486Sdfr	extr.u	r15=in0,0,3			// src & 7
47766486Sdfr	add	in2=-1,in2 ;;			// len--
47866486Sdfr	cmp.eq	p6,p0=r0,in2			// done?
47966486Sdfr	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
48066486Sdfr(p6)	br.ret.spnt.few rp			// return if done
48166486Sdfr(p7)	br.cond.spnt.few 4f			// go to main copy
48266486Sdfr	br.cond.sptk.few 3b			// more bytes to copy
48366458Sdfr
48466486Sdfr	// At this point, in2 is non-zero
48566458Sdfr
48666486Sdfr4:	mov	r14=8 ;;
48766486Sdfr	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
48866486Sdfr(p6)	br.cond.spnt.few 1b			// byte copy the end
48966486Sdfr	ld8	r15=[in0],8 ;;			// copy word
49066486Sdfr	st8	[in1]=r15,8
49166486Sdfr	add	in2=-8,in2 ;;			// len -= 8
49266486Sdfr	cmp.ne	p6,p0=r0,in2			// done?
49366486Sdfr(p6)	br.cond.spnt.few 4b			// again
49466458Sdfr
49566486Sdfr	br.ret.sptk.few rp			// return
49666458Sdfr
49766486Sdfr	// Don't bother optimising overlap case
49866458Sdfr
49966486Sdfr5:	add	in0=in0,in2
50066486Sdfr	add	in1=in1,in2 ;;
50166486Sdfr	add	in0=-1,in0
50266486Sdfr	add	in1=-1,in1 ;;
50366458Sdfr
50466486Sdfr6:	ld1	r14=[in0],-1 ;;
50566486Sdfr	st1	[in1]=r14,-1
50666486Sdfr	add	in2=-1,in2 ;;
50766486Sdfr	cmp.ne	p6,p0=r0,in2
50866486Sdfr(p6)	br.cond.spnt.few 6b
50966458Sdfr
51066486Sdfr	br.ret.sptk.few rp
51166458Sdfr
51266486SdfrEND(bcopy)
51366458Sdfr
51466633SdfrENTRY(memcpy,3)
51566486Sdfr
51666486Sdfr	mov	r14=in0 ;;
51766486Sdfr	mov	in0=in1 ;;
51866486Sdfr	mov	in1=r14
51966486Sdfr	br.cond.sptk.few bcopy
52066486Sdfr
52166486SdfrEND(memcpy)
52266486Sdfr
52366633SdfrENTRY(copyin, 3)
52466486Sdfr
52585682Sdfr	.prologue
52685682Sdfr	.regstk	4, 3, 4, 0
52785682Sdfr	.save	ar.pfs,loc0
52885682Sdfr	alloc	loc0=ar.pfs,4,3,4,0
52985682Sdfr	.save	rp,loc1
53066486Sdfr	mov	loc1=rp
53185682Sdfr	.body
53266458Sdfr
53366486Sdfr	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
53466486Sdfr	;;
53567020Sdfr	cmp.geu	p6,p0=in0,loc2			// is in user space.
53666486Sdfr	;;
53766486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
53866486Sdfr	movl	r14=copyerr			// set up fault handler.
53983366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
54066486Sdfr	;;
54166486Sdfr	ld8	r15=[r15]
54266486Sdfr	;;
54383366Sjulian	add	r15=TD_PCB,r15			// find pcb
54466486Sdfr	;;
54566486Sdfr	ld8	r15=[r15]
54666486Sdfr	;;
54783366Sjulian	add	loc2=PCB_ONFAULT,r15
54866486Sdfr	;;
54966486Sdfr	st8	[loc2]=r14
55066486Sdfr	;;
55166486Sdfr	mov	out0=in0
55266486Sdfr	mov	out1=in1
55366486Sdfr	mov	out2=in2
55466486Sdfr	;;
55566486Sdfr	br.call.sptk.few rp=bcopy		// do the copy.
55666486Sdfr	st8	[loc2]=r0			// kill the fault handler.
55767020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
55866486Sdfr	mov	rp=loc1				// restore ra.
55966486Sdfr	br.ret.sptk.few rp			// ret0 left over from bcopy
56066486Sdfr
56166486SdfrEND(copyin)
56266458Sdfr
56366633SdfrENTRY(copyout, 3)
56466486Sdfr
56585682Sdfr	.prologue
56685682Sdfr	.regstk	4, 3, 4, 0
56785682Sdfr	.save	ar.pfs,loc0
56885682Sdfr	alloc	loc0=ar.pfs,4,3,4,0
56985682Sdfr	.save	rp,loc1
57066486Sdfr	mov	loc1=rp
57185682Sdfr	.body
57266458Sdfr
57366486Sdfr	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
57466486Sdfr	;;
57567020Sdfr	cmp.geu	p6,p0=in1,loc2			// is in user space.
57666486Sdfr	;;
57766486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
57866486Sdfr	movl	r14=copyerr			// set up fault handler.
57983366Sjulian	add	r15=GD_CURTHREAD,r13		// find curthread
58066486Sdfr	;;
58166486Sdfr	ld8	r15=[r15]
58266486Sdfr	;;
58383366Sjulian	add	r15=TD_PCB,r15			// find pcb
58466486Sdfr	;;
58566486Sdfr	ld8	r15=[r15]
58666486Sdfr	;;
58783366Sjulian	add	loc2=PCB_ONFAULT,r15
58866486Sdfr	;;
58966486Sdfr	st8	[loc2]=r14
59066486Sdfr	;;
59166486Sdfr	mov	out0=in0
59266486Sdfr	mov	out1=in1
59366486Sdfr	mov	out2=in2
59466486Sdfr	;;
59566486Sdfr	br.call.sptk.few rp=bcopy		// do the copy.
59666486Sdfr	st8	[loc2]=r0			// kill the fault handler.
59767020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
59866486Sdfr	mov	rp=loc1				// restore ra.
59966486Sdfr	br.ret.sptk.few rp			// ret0 left over from bcopy
60066486Sdfr
60166486SdfrEND(copyout)
60266458Sdfr
60366633SdfrENTRY(copyerr, 0)
60466458Sdfr
60583366Sjulian	add	r14=GD_CURTHREAD,r13 ;;		// find curthread
60666486Sdfr	ld8	r14=[r14] ;;
60783366Sjulian	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
60866486Sdfr	ld8	r14=[r14] ;;
60983366Sjulian	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
61066486Sdfr	st8	[r14]=r0			// reset fault handler
61166458Sdfr
61266486Sdfr	mov	ret0=EFAULT			// return EFAULT
61366486Sdfr	br.ret.sptk.few rp
61466458Sdfr
61566486SdfrEND(copyerr)
616