support.S revision 121410
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 121410 2003-10-23 06:19:06Z marcel $
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	rsm	psr.i | psr.ic
7384114Sdfr	mov	r19=ar.rsc		// save rsc while we change mode
7483893Sdfr	tbit.nz	p6,p7=r14,17		// physical or virtual ?
7583893Sdfr	;;
7684114Sdfr	mov	ar.rsc=0		// turn off RSE
7783893Sdfr(p6)	mov	r15=7			// RR base for virtual addresses
7883893Sdfr(p7)	mov	r15=0			// RR base for physical addresses
7983893Sdfr	flushrs				// no dirty registers please
8083893Sdfr	srlz.i
8183893Sdfr	;;
8283893Sdfr	mov	r16=ar.bsp
8383893Sdfr	mov	r17=rp
8483893Sdfr	mov	r18=ar.rnat
8583893Sdfr	;;
8683893Sdfr	dep	r16=r15,r16,61,3	// new address of ar.bsp
8783893Sdfr	dep	r17=r15,r17,61,3	// new address of rp
8884114Sdfr	dep	sp=r15,sp,61,3		// new address of sp
8983893Sdfr	;;
9083893Sdfr	mov	ar.bspstore=r16
9183893Sdfr	mov	rp=r17
9283893Sdfr	;;
9383893Sdfr1:	mov	r16=ip
9483893Sdfr	mov	ar.rnat=r18
9583895Sdfr	mov	cr.ipsr=r14		// psr for new mode
9683893Sdfr	;;
9783893Sdfr	add	r16=2f-1b,r16		// address to rfi to
9883893Sdfr	;;
9983895Sdfr	dep	r16=r15,r16,61,3	// new mode address for rfi
10083893Sdfr	;;
10183893Sdfr	mov	cr.iip=r16		// setup for rfi
10283893Sdfr	mov	cr.ifs=r0
10383893Sdfr	;;
10483893Sdfr	rfi
10583893Sdfr
10684114Sdfr2:	mov	ar.rsc=r19		// restore ar.rsc
10784114Sdfr	br.ret.sptk.few rp		// now in new mode
10883893SdfrEND(ia64_change_mode)
10983893Sdfr
11083893Sdfr/*
11183893Sdfr * ia64_physical_mode:	change mode to physical mode
11283893Sdfr *
11383893Sdfr * Return:
11483893Sdfr *	ret0	psr to restore
11584114Sdfr *
11684114Sdfr * Modifies:
11784114Sdfr *	r15-r18	scratch
11884114Sdfr *	ar.bsp	tranlated to physical mode
11984114Sdfr *	psr.i	cleared
12083893Sdfr */
12183893SdfrENTRY(ia64_physical_mode, 0)
12283893Sdfr	mov	r14=psr
12383893Sdfr	mov	ret0=psr
12484114Sdfr	movl	r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH)
12583893Sdfr	movl	r16=IA64_PSR_BN
12683893Sdfr	;;
12783893Sdfr	andcm	r14=r14,r15		// clear various xT bits
12883893Sdfr	;;
12983893Sdfr	or	r14=r14,r16		// make sure BN=1
13083893Sdfr	or	ret0=ret0,r16		// make sure BN=1
13183893Sdfr
13283893Sdfr	br.cond.sptk.many ia64_change_mode
13383893SdfrEND(ia64_physical_mode)
13483893Sdfr
13584114Sdfr/*
13684114Sdfr * ia64_call_efi_physical:	call an EFI procedure in physical mode
13784114Sdfr *
13884114Sdfr * Arguments:
13984114Sdfr *	in0		Address of EFI procedure descriptor
14084114Sdfr *	in1-in5		Arguments to EFI procedure
14184114Sdfr *
14284114Sdfr * Return:
14384114Sdfr *	ret0-ret3	return values from EFI
14484114Sdfr *
14584114Sdfr */
14684114SdfrENTRY(ia64_call_efi_physical, 6)
14785682Sdfr	.prologue
14885682Sdfr	.regstk	6,4,5,0
14985682Sdfr	.save	ar.pfs,loc0
15084114Sdfr	alloc	loc0=ar.pfs,6,4,5,0
15184114Sdfr	;;
15285682Sdfr	.save	rp,loc1
15384114Sdfr	mov	loc1=rp
15484114Sdfr	;;
15585682Sdfr	.body
15684114Sdfr	br.call.sptk.many rp=ia64_physical_mode
15784114Sdfr	;;
15884114Sdfr	mov	loc2=r8			// psr to restore mode
15984114Sdfr	mov	loc3=gp			// save kernel gp
16084114Sdfr	ld8	r14=[in0],8		// function address
16184114Sdfr	;;
16284114Sdfr	mov	out0=in1
16384114Sdfr	mov	out1=in2
16484114Sdfr	mov	out2=in3
16584114Sdfr	mov	out3=in4
16684114Sdfr	mov	out4=in5
16784114Sdfr	ld8	gp=[in0]		// function gp value
16884114Sdfr	;;
16984114Sdfr	mov	b6=r14
17084114Sdfr	;;
17184114Sdfr	br.call.sptk.many rp=b6		// call EFI procedure
17284114Sdfr	mov	gp=loc3			// restore kernel gp
17384114Sdfr	;;
17484114Sdfr	mov	r14=loc2		// psr to restore mode
17584114Sdfr	br.call.sptk.many rp=ia64_change_mode
17684114Sdfr	;;
17784114Sdfr	mov	rp=loc1
17884114Sdfr	mov	ar.pfs=loc0
17984114Sdfr	;;
18084114Sdfr	br.ret.sptk.many rp
18184114SdfrEND(ia64_call_efi_physical)
18284114Sdfr
18366458Sdfr/**************************************************************************/
184115341Smarcel
185115341SmarcelENTRY(fusufault, 0)
186115341Smarcel{	.mib
187115341Smarcel	st8.rel		[r15]=r0		// Clear onfault.
188115341Smarcel	add		ret0=-1,r0
189115341Smarcel	br.ret.sptk	rp
190115341Smarcel	;;
191115341Smarcel}
192115341SmarcelEND(fusufault)
193115341Smarcel
19466458Sdfr/*
195115341Smarcel * casuptr(intptr_t *p, intptr_t old, intptr_t new)
196115341Smarcel *	Perform a compare-exchange in user space.
19766458Sdfr */
198115341SmarcelENTRY(casuptr, 3)
199115341Smarcel{	.mlx
200115341Smarcel	add		r15=PC_CURTHREAD,r13
201115341Smarcel	movl		r14=VM_MAX_ADDRESS
202115341Smarcel	;;
203115341Smarcel}
204115341Smarcel{	.mib
205115341Smarcel	ld8		r15=[r15]		// r15 = curthread
206115341Smarcel	cmp.geu		p6,p0=in0,r14
207115341Smarcel(p6)	br.dpnt.few	1f
208115341Smarcel	;;
209115341Smarcel}
210115341Smarcel{	.mlx
211115341Smarcel	add		r15=TD_PCB,r15
212115341Smarcel	movl		r14=fusufault
213115341Smarcel	;;
214115341Smarcel}
215115341Smarcel{	.mmi
216115341Smarcel	ld8		r15=[r15]		// r15 = PCB
217115341Smarcel	;;
218115341Smarcel	mov		ar.ccv=in1
219115341Smarcel	add		r15=PCB_ONFAULT,r15
220115341Smarcel	;;
221115341Smarcel}
222115341Smarcel{	.mmi
223115341Smarcel	st8		[r15]=r14		// Set onfault
224115341Smarcel	;;
225115341Smarcel	cmpxchg8.rel	ret0=[in0],in2,ar.ccv
226115341Smarcel	nop		0
227115341Smarcel	;;
228115341Smarcel}
229115341Smarcel{	.mfb
230115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
231115341Smarcel	nop		0
232115341Smarcel	br.ret.sptk	rp
233115341Smarcel	;;
234115341Smarcel}
235115341Smarcel1:
236115341Smarcel{	.mfb
237115341Smarcel	add		ret0=-1,r0
238115341Smarcel	nop		0
239115341Smarcel	br.ret.sptk	rp
240115341Smarcel	;;
241115341Smarcel}
242115341SmarcelEND(casuptr)
24366458Sdfr
244115341Smarcel/*
245115341Smarcel * subyte(void *addr, int byte)
246115341Smarcel * suword16(void *addr, int word)
247115341Smarcel * suword32(void *addr, int word)
248115341Smarcel * suword64|suword(void *addr, long word)
249115341Smarcel *	Store in user space
250115341Smarcel */
251115341Smarcel
252115341SmarcelENTRY(subyte, 2)
253115341Smarcel{	.mlx
254115341Smarcel	add		r15=PC_CURTHREAD,r13
255115341Smarcel	movl		r14=VM_MAX_ADDRESS
25666633Sdfr	;;
257115341Smarcel}
258115341Smarcel{	.mib
259115341Smarcel	ld8		r15=[r15]		// r15 = curthread
260115341Smarcel	cmp.geu		p6,p0=in0,r14
261115341Smarcel(p6)	br.dpnt.few	1f
26266633Sdfr	;;
263115341Smarcel}
264115341Smarcel{	.mlx
265115341Smarcel	add		r15=TD_PCB,r15
266115341Smarcel	movl		r14=fusufault
26766633Sdfr	;;
268115341Smarcel}
269115341Smarcel{	.mmi
270115341Smarcel	ld8		r15=[r15]		// r15 = PCB
27166633Sdfr	;;
272115341Smarcel	nop		0
273115341Smarcel	add		r15=PCB_ONFAULT,r15
27466633Sdfr	;;
275115341Smarcel}
276115341Smarcel{	.mmi
277115341Smarcel	st8		[r15]=r14		// Set onfault
27866633Sdfr	;;
279115341Smarcel	st1.rel		[in0]=in1
280115341Smarcel	nop		0
28166633Sdfr	;;
282115341Smarcel}
283115341Smarcel{	.mib
284115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
285115341Smarcel	mov		ret0=r0
286115341Smarcel	br.ret.sptk	rp
287115341Smarcel	;;
288115341Smarcel}
289115341Smarcel1:
290115341Smarcel{	.mfb
291115341Smarcel	add		ret0=-1,r0
292115341Smarcel	nop		0
293115341Smarcel	br.ret.sptk	rp
294115341Smarcel	;;
295115341Smarcel}
296115341SmarcelEND(subyte)
29766458Sdfr
298115341SmarcelENTRY(suword16, 2)
299115341Smarcel{	.mlx
300115341Smarcel	add		r15=PC_CURTHREAD,r13
301115341Smarcel	movl		r14=VM_MAX_ADDRESS
302115341Smarcel	;;
303115341Smarcel}
304115341Smarcel{	.mib
305115341Smarcel	ld8		r15=[r15]		// r15 = curthread
306115341Smarcel	cmp.geu		p6,p0=in0,r14
307115341Smarcel(p6)	br.dpnt.few	1f
308115341Smarcel	;;
309115341Smarcel}
310115341Smarcel{	.mlx
311115341Smarcel	add		r15=TD_PCB,r15
312115341Smarcel	movl		r14=fusufault
313115341Smarcel	;;
314115341Smarcel}
315115341Smarcel{	.mmi
316115341Smarcel	ld8		r15=[r15]		// r15 = PCB
317115341Smarcel	;;
318115341Smarcel	nop		0
319115341Smarcel	add		r15=PCB_ONFAULT,r15
320115341Smarcel	;;
321115341Smarcel}
322115341Smarcel{	.mmi
323115341Smarcel	st8		[r15]=r14		// Set onfault
324115341Smarcel	;;
325115341Smarcel	st2.rel		[in0]=in1
326115341Smarcel	nop		0
327115341Smarcel	;;
328115341Smarcel}
329115341Smarcel{	.mib
330115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
331115341Smarcel	mov		ret0=r0
332115341Smarcel	br.ret.sptk	rp
333115341Smarcel	;;
334115341Smarcel}
335115341Smarcel1:
336115341Smarcel{	.mfb
337115341Smarcel	add		ret0=-1,r0
338115341Smarcel	nop		0
339115341Smarcel	br.ret.sptk	rp
340115341Smarcel	;;
341115341Smarcel}
342115341SmarcelEND(suword16)
343115341Smarcel
34498473SpeterENTRY(suword32, 2)
345115341Smarcel{	.mlx
346115341Smarcel	add		r15=PC_CURTHREAD,r13
347115341Smarcel	movl		r14=VM_MAX_ADDRESS
34894377Sdfr	;;
349115341Smarcel}
350115341Smarcel{	.mib
351115341Smarcel	ld8		r15=[r15]		// r15 = curthread
352115341Smarcel	cmp.geu		p6,p0=in0,r14
353115341Smarcel(p6)	br.dpnt.few	1f
35494377Sdfr	;;
355115341Smarcel}
356115341Smarcel{	.mlx
357115341Smarcel	add		r15=TD_PCB,r15
358115341Smarcel	movl		r14=fusufault
35994377Sdfr	;;
360115341Smarcel}
361115341Smarcel{	.mmi
362115341Smarcel	ld8		r15=[r15]		// r15 = PCB
36394377Sdfr	;;
364115341Smarcel	nop		0
365115341Smarcel	add		r15=PCB_ONFAULT,r15
36694377Sdfr	;;
367115341Smarcel}
368115341Smarcel{	.mmi
369115341Smarcel	st8		[r15]=r14		// Set onfault
37094377Sdfr	;;
371115341Smarcel	st4.rel		[in0]=in1
372115341Smarcel	nop		0
37394377Sdfr	;;
374115341Smarcel}
375115341Smarcel{	.mib
376115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
377115341Smarcel	mov		ret0=r0
378115341Smarcel	br.ret.sptk	rp
379115341Smarcel	;;
380115341Smarcel}
381115341Smarcel1:
382115341Smarcel{	.mfb
383115341Smarcel	add		ret0=-1,r0
384115341Smarcel	nop		0
385115341Smarcel	br.ret.sptk	rp
386115341Smarcel	;;
387115341Smarcel}
38898473SpeterEND(suword32)
38966458Sdfr
390115341SmarcelENTRY(suword64, 2)
391115341SmarcelXENTRY(suword)
392115341Smarcel{	.mlx
393115341Smarcel	add		r15=PC_CURTHREAD,r13
394115341Smarcel	movl		r14=VM_MAX_ADDRESS
39566633Sdfr	;;
396115341Smarcel}
397115341Smarcel{	.mib
398115341Smarcel	ld8		r15=[r15]		// r15 = curthread
399115341Smarcel	cmp.geu		p6,p0=in0,r14
400115341Smarcel(p6)	br.dpnt.few	1f
40166633Sdfr	;;
402115341Smarcel}
403115341Smarcel{	.mlx
404115341Smarcel	add		r15=TD_PCB,r15
405115341Smarcel	movl		r14=fusufault
40666633Sdfr	;;
407115341Smarcel}
408115341Smarcel{	.mmi
409115341Smarcel	ld8		r15=[r15]		// r15 = PCB
41066633Sdfr	;;
411115341Smarcel	nop		0
412115341Smarcel	add		r15=PCB_ONFAULT,r15
41366633Sdfr	;;
414115341Smarcel}
415115341Smarcel{	.mmi
416115341Smarcel	st8		[r15]=r14		// Set onfault
41766633Sdfr	;;
418115341Smarcel	st8.rel		[in0]=in1
419115341Smarcel	nop		0
42066633Sdfr	;;
421115341Smarcel}
422115341Smarcel{	.mib
423115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
424115341Smarcel	mov		ret0=r0
425115341Smarcel	br.ret.sptk	rp
426115341Smarcel	;;
427115341Smarcel}
428115341Smarcel1:
429115341Smarcel{	.mfb
430115341Smarcel	add		ret0=-1,r0
431115341Smarcel	nop		0
432115341Smarcel	br.ret.sptk	rp
433115341Smarcel	;;
434115341Smarcel}
435115341SmarcelEND(suword64)
43666458Sdfr
437115341Smarcel/*
438115341Smarcel * fubyte(void *addr, int byte)
439115341Smarcel * fuword16(void *addr, int word)
440115341Smarcel * fuword32(void *addr, int word)
441115341Smarcel * fuword64|fuword(void *addr, long word)
442115341Smarcel *	Fetch from user space
443115341Smarcel */
44466458Sdfr
445115341SmarcelENTRY(fubyte, 1)
446115341Smarcel{	.mlx
447115341Smarcel	add		r15=PC_CURTHREAD,r13
448115341Smarcel	movl		r14=VM_MAX_ADDRESS
449115341Smarcel	;;
450115341Smarcel}
451115341Smarcel{	.mib
452115341Smarcel	ld8		r15=[r15]		// r15 = curthread
453115341Smarcel	cmp.geu		p6,p0=in0,r14
454115341Smarcel(p6)	br.dpnt.few	1f
455115341Smarcel	;;
456115341Smarcel}
457115341Smarcel{	.mlx
458115341Smarcel	add		r15=TD_PCB,r15
459115341Smarcel	movl		r14=fusufault
460115341Smarcel	;;
461115341Smarcel}
462115341Smarcel{	.mmi
463115341Smarcel	ld8		r15=[r15]		// r15 = PCB
464115341Smarcel	;;
465115341Smarcel	nop		0
466115341Smarcel	add		r15=PCB_ONFAULT,r15
467115341Smarcel	;;
468115341Smarcel}
469115341Smarcel{	.mmi
470115341Smarcel	st8		[r15]=r14		// Set onfault
471115341Smarcel	;;
472115341Smarcel	mf
473115341Smarcel	nop		0
474115341Smarcel	;;
475115341Smarcel}
476115341Smarcel{	.mmb
477115341Smarcel	ld1		ret0=[in0]
478115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
479115341Smarcel	br.ret.sptk	rp
480115341Smarcel	;;
481115341Smarcel}
482115341Smarcel1:
483115341Smarcel{	.mfb
484115341Smarcel	add		ret0=-1,r0
485115341Smarcel	nop		0
486115341Smarcel	br.ret.sptk	rp
487115341Smarcel	;;
488115341Smarcel}
489115341SmarcelEND(fubyte)
49066458Sdfr
491115341SmarcelENTRY(fuword16, 2)
492115341Smarcel{	.mlx
493115341Smarcel	add		r15=PC_CURTHREAD,r13
494115341Smarcel	movl		r14=VM_MAX_ADDRESS
49566633Sdfr	;;
496115341Smarcel}
497115341Smarcel{	.mib
498115341Smarcel	ld8		r15=[r15]		// r15 = curthread
499115341Smarcel	cmp.geu		p6,p0=in0,r14
500115341Smarcel(p6)	br.dpnt.few	1f
50166633Sdfr	;;
502115341Smarcel}
503115341Smarcel{	.mlx
504115341Smarcel	add		r15=TD_PCB,r15
505115341Smarcel	movl		r14=fusufault
50666633Sdfr	;;
507115341Smarcel}
508115341Smarcel{	.mmi
509115341Smarcel	ld8		r15=[r15]		// r15 = PCB
51066633Sdfr	;;
511115341Smarcel	nop		0
512115341Smarcel	add		r15=PCB_ONFAULT,r15
51366633Sdfr	;;
514115341Smarcel}
515115341Smarcel{	.mmi
516115341Smarcel	st8		[r15]=r14		// Set onfault
51766633Sdfr	;;
518115341Smarcel	mf
519115341Smarcel	nop		0
52066633Sdfr	;;
521115341Smarcel}
522115341Smarcel{	.mmb
523115341Smarcel	ld2		ret0=[in0]
524115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
525115341Smarcel	br.ret.sptk	rp
526115341Smarcel	;;
527115341Smarcel}
528115341Smarcel1:
529115341Smarcel{	.mfb
530115341Smarcel	add		ret0=-1,r0
531115341Smarcel	nop		0
532115341Smarcel	br.ret.sptk	rp
533115341Smarcel	;;
534115341Smarcel}
535115341SmarcelEND(fuword16)
53666458Sdfr
537115341SmarcelENTRY(fuword32, 2)
538115341Smarcel{	.mlx
539115341Smarcel	add		r15=PC_CURTHREAD,r13
540115341Smarcel	movl		r14=VM_MAX_ADDRESS
54194377Sdfr	;;
542115341Smarcel}
543115341Smarcel{	.mib
544115341Smarcel	ld8		r15=[r15]		// r15 = curthread
545115341Smarcel	cmp.geu		p6,p0=in0,r14
546115341Smarcel(p6)	br.dpnt.few	1f
54794377Sdfr	;;
548115341Smarcel}
549115341Smarcel{	.mlx
550115341Smarcel	add		r15=TD_PCB,r15
551115341Smarcel	movl		r14=fusufault
55294377Sdfr	;;
553115341Smarcel}
554115341Smarcel{	.mmi
555115341Smarcel	ld8		r15=[r15]		// r15 = PCB
55694377Sdfr	;;
557115341Smarcel	nop		0
558115341Smarcel	add		r15=PCB_ONFAULT,r15
55994377Sdfr	;;
560115341Smarcel}
561115341Smarcel{	.mmi
562115341Smarcel	st8		[r15]=r14		// Set onfault
56394377Sdfr	;;
564115341Smarcel	mf
565115341Smarcel	nop		0
56694377Sdfr	;;
567115341Smarcel}
568115341Smarcel{	.mmb
569115341Smarcel	ld4		ret0=[in0]
570115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
571115341Smarcel	br.ret.sptk	rp
572115341Smarcel	;;
573115341Smarcel}
574115341Smarcel1:
575115341Smarcel{	.mfb
576115341Smarcel	add		ret0=-1,r0
577115341Smarcel	nop		0
578115341Smarcel	br.ret.sptk	rp
579115341Smarcel	;;
580115341Smarcel}
58198473SpeterEND(fuword32)
58294377Sdfr
583115341SmarcelENTRY(fuword64, 2)
584115341SmarcelXENTRY(fuword)
585115341Smarcel{	.mlx
586115341Smarcel	add		r15=PC_CURTHREAD,r13
587115341Smarcel	movl		r14=VM_MAX_ADDRESS
58866633Sdfr	;;
589115341Smarcel}
590115341Smarcel{	.mib
591115341Smarcel	ld8		r15=[r15]		// r15 = curthread
592115341Smarcel	cmp.geu		p6,p0=in0,r14
593115341Smarcel(p6)	br.dpnt.few	1f
59466633Sdfr	;;
595115341Smarcel}
596115341Smarcel{	.mlx
597115341Smarcel	add		r15=TD_PCB,r15
598115341Smarcel	movl		r14=fusufault
59966633Sdfr	;;
600115341Smarcel}
601115341Smarcel{	.mmi
602115341Smarcel	ld8		r15=[r15]		// r15 = PCB
60366633Sdfr	;;
604115341Smarcel	nop		0
605115341Smarcel	add		r15=PCB_ONFAULT,r15
60666633Sdfr	;;
607115341Smarcel}
608115341Smarcel{	.mmi
609115341Smarcel	st8		[r15]=r14		// Set onfault
61066633Sdfr	;;
611115341Smarcel	mf
612115341Smarcel	nop		0
61366633Sdfr	;;
614115341Smarcel}
615115341Smarcel{	.mmb
616115341Smarcel	ld8		ret0=[in0]
617115341Smarcel	st8.rel		[r15]=r0		// Clear onfault
618115341Smarcel	br.ret.sptk	rp
619115341Smarcel	;;
620115341Smarcel}
621115341Smarcel1:
622115341Smarcel{	.mfb
623115341Smarcel	add		ret0=-1,r0
624115341Smarcel	nop		0
625115341Smarcel	br.ret.sptk	rp
626115341Smarcel	;;
627115341Smarcel}
628115341SmarcelEND(fuword64)
62966458Sdfr
630115341Smarcel/*
631115341Smarcel * fuswintr(void *addr)
632115341Smarcel * suswintr(void *addr)
633115341Smarcel */
634115341Smarcel
635115341SmarcelENTRY(fuswintr, 1)
636115341Smarcel{	.mfb
637115341Smarcel	add		ret0=-1,r0
638115341Smarcel	nop		0
639115341Smarcel	br.ret.sptk	rp
640115341Smarcel	;;
641115341Smarcel}
642115341SmarcelEND(fuswintr)
643115341Smarcel
644115341SmarcelENTRY(suswintr, 0)
645115341Smarcel{	.mfb
646115341Smarcel	add		ret0=-1,r0
647115341Smarcel	nop		0
648115341Smarcel	br.ret.sptk	rp
649115341Smarcel	;;
650115341Smarcel}
651115341SmarcelEND(suswintr)
652115341Smarcel
65366458Sdfr/**************************************************************************/
65466458Sdfr
65566458Sdfr/*
65666458Sdfr * Copy a null-terminated string within the kernel's address space.
65766458Sdfr * If lenp is not NULL, store the number of chars copied in *lenp
65866458Sdfr *
65966458Sdfr * int copystr(char *from, char *to, size_t len, size_t *lenp);
66066458Sdfr */
66166633SdfrENTRY(copystr, 4)
66266486Sdfr	mov	r14=in2			// r14 = i = len
66366486Sdfr	cmp.eq	p6,p0=r0,in2
66466486Sdfr(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
66566458Sdfr
66666486Sdfr1:	ld1	r15=[in0],1		// read one byte
66766486Sdfr	;;
66866486Sdfr	st1	[in1]=r15,1		// write that byte
66966486Sdfr	add	in2=-1,in2		// len--
67066486Sdfr	;;
67166486Sdfr	cmp.eq	p6,p0=r0,r15
67266486Sdfr	cmp.ne	p7,p0=r0,in2
67366486Sdfr	;;
67466486Sdfr(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
67566486Sdfr(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
67666458Sdfr
67766486Sdfr2:	cmp.eq	p6,p0=r0,in3
67866486Sdfr(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
67967020Sdfr	sub	r14=r14,in2		// *lenp = (i - len)
68066486Sdfr	;;
68166486Sdfr	st8	[in3]=r14
68266486Sdfr
68366486Sdfr3:	cmp.eq	p6,p0=r0,r15
68466486Sdfr(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
68566458Sdfr
68666486Sdfr	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
68766486Sdfr	br.ret.sptk.few rp
68866458Sdfr
68966486Sdfr4:	mov	ret0=0			// return 0.
69066486Sdfr	br.ret.sptk.few rp
69166486SdfrEND(copystr)
69266458Sdfr
69366633SdfrENTRY(copyinstr, 4)
69485682Sdfr	.prologue
69585682Sdfr	.regstk	4, 3, 4, 0
69685682Sdfr	.save	ar.pfs,loc0
69766486Sdfr	alloc	loc0=ar.pfs,4,3,4,0
69885682Sdfr	.save	rp,loc1
69966486Sdfr	mov	loc1=rp
70085682Sdfr	.body
70166458Sdfr
702115084Smarcel	movl	loc2=VM_MAX_ADDRESS		// make sure that src addr
70366486Sdfr	;;
70466633Sdfr	cmp.geu	p6,p0=in0,loc2			// is in user space.
70566486Sdfr	;;
70666486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
70766486Sdfr	movl	r14=copyerr			// set up fault handler.
70887702Sjhb	add	r15=PC_CURTHREAD,r13		// find curthread
70966486Sdfr	;;
71066486Sdfr	ld8	r15=[r15]
71166486Sdfr	;;
71283366Sjulian	add	r15=TD_PCB,r15			// find pcb
71366486Sdfr	;;
71466486Sdfr	ld8	r15=[r15]
71566486Sdfr	;;
71683366Sjulian	add	loc2=PCB_ONFAULT,r15
71766486Sdfr	;;
71866486Sdfr	st8	[loc2]=r14
71966486Sdfr	;;
72066486Sdfr	mov	out0=in0
72166486Sdfr	mov	out1=in1
72266486Sdfr	mov	out2=in2
72366486Sdfr	mov	out3=in3
72466486Sdfr	;;
72566486Sdfr	br.call.sptk.few rp=copystr		// do the copy.
72666486Sdfr	st8	[loc2]=r0			// kill the fault handler.
72767020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
72866486Sdfr	mov	rp=loc1				// restore ra.
72966486Sdfr	br.ret.sptk.few rp			// ret0 left over from copystr
73066486SdfrEND(copyinstr)
73166458Sdfr
73266458Sdfr/*
73366486Sdfr * Not the fastest bcopy in the world.
73466458Sdfr */
73566633SdfrENTRY(bcopy, 3)
73666486Sdfr	mov	ret0=r0				// return zero for copy{in,out}
73766486Sdfr	;;
73866486Sdfr	cmp.le	p6,p0=in2,r0			// bail if len <= 0
73966486Sdfr(p6)	br.ret.spnt.few rp
74066458Sdfr
74166486Sdfr	sub	r14=in1,in0 ;;			// check for overlap
74266486Sdfr	cmp.ltu	p6,p0=r14,in2			// dst-src < len
74366486Sdfr(p6)	br.cond.spnt.few 5f
74466458Sdfr
74566486Sdfr	extr.u	r14=in0,0,3			// src & 7
74666486Sdfr	extr.u	r15=in1,0,3 ;;			// dst & 7
74766486Sdfr	cmp.eq	p6,p0=r14,r15			// different alignment?
74866486Sdfr(p6)	br.cond.spnt.few 2f			// branch if same alignment
74966458Sdfr
75066486Sdfr1:	ld1	r14=[in0],1 ;;			// copy bytewise
75166486Sdfr	st1	[in1]=r14,1
75266486Sdfr	add	in2=-1,in2 ;;			// len--
75366486Sdfr	cmp.ne	p6,p0=r0,in2
75466486Sdfr(p6)	br.cond.dptk.few 1b			// loop
75566486Sdfr	br.ret.sptk.few rp			// done
75666458Sdfr
75766486Sdfr2:	cmp.eq	p6,p0=r14,r0			// aligned?
75866486Sdfr(p6)	br.cond.sptk.few 4f
75966458Sdfr
76066486Sdfr3:	ld1	r14=[in0],1 ;;			// copy bytewise
76166486Sdfr	st1	[in1]=r14,1
76266486Sdfr	extr.u	r15=in0,0,3			// src & 7
76366486Sdfr	add	in2=-1,in2 ;;			// len--
76466486Sdfr	cmp.eq	p6,p0=r0,in2			// done?
76566486Sdfr	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
76666486Sdfr(p6)	br.ret.spnt.few rp			// return if done
76766486Sdfr(p7)	br.cond.spnt.few 4f			// go to main copy
76866486Sdfr	br.cond.sptk.few 3b			// more bytes to copy
76966458Sdfr
77066486Sdfr	// At this point, in2 is non-zero
77166458Sdfr
77266486Sdfr4:	mov	r14=8 ;;
77366486Sdfr	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
77466486Sdfr(p6)	br.cond.spnt.few 1b			// byte copy the end
77566486Sdfr	ld8	r15=[in0],8 ;;			// copy word
77666486Sdfr	st8	[in1]=r15,8
77766486Sdfr	add	in2=-8,in2 ;;			// len -= 8
77866486Sdfr	cmp.ne	p6,p0=r0,in2			// done?
77966486Sdfr(p6)	br.cond.spnt.few 4b			// again
78066458Sdfr
78166486Sdfr	br.ret.sptk.few rp			// return
78266458Sdfr
78366486Sdfr	// Don't bother optimising overlap case
78466458Sdfr
78566486Sdfr5:	add	in0=in0,in2
78666486Sdfr	add	in1=in1,in2 ;;
78766486Sdfr	add	in0=-1,in0
78866486Sdfr	add	in1=-1,in1 ;;
78966458Sdfr
79066486Sdfr6:	ld1	r14=[in0],-1 ;;
79166486Sdfr	st1	[in1]=r14,-1
79266486Sdfr	add	in2=-1,in2 ;;
79366486Sdfr	cmp.ne	p6,p0=r0,in2
79466486Sdfr(p6)	br.cond.spnt.few 6b
79566458Sdfr
79666486Sdfr	br.ret.sptk.few rp
79766486SdfrEND(bcopy)
79866458Sdfr
79966633SdfrENTRY(memcpy,3)
80066486Sdfr	mov	r14=in0 ;;
80166486Sdfr	mov	in0=in1 ;;
80266486Sdfr	mov	in1=r14
80366486Sdfr	br.cond.sptk.few bcopy
80466486SdfrEND(memcpy)
80566486Sdfr
80666633SdfrENTRY(copyin, 3)
80785682Sdfr	.prologue
808115084Smarcel	.regstk	3, 3, 3, 0
80985682Sdfr	.save	ar.pfs,loc0
810115084Smarcel	alloc	loc0=ar.pfs,3,3,3,0
81185682Sdfr	.save	rp,loc1
81266486Sdfr	mov	loc1=rp
81385682Sdfr	.body
81466458Sdfr
815115084Smarcel	movl	loc2=VM_MAX_ADDRESS		// make sure that src addr
81666486Sdfr	;;
81767020Sdfr	cmp.geu	p6,p0=in0,loc2			// is in user space.
81866486Sdfr	;;
81966486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
82066486Sdfr	movl	r14=copyerr			// set up fault handler.
82187702Sjhb	add	r15=PC_CURTHREAD,r13		// find curthread
82266486Sdfr	;;
82366486Sdfr	ld8	r15=[r15]
82466486Sdfr	;;
82583366Sjulian	add	r15=TD_PCB,r15			// find pcb
82666486Sdfr	;;
82766486Sdfr	ld8	r15=[r15]
82866486Sdfr	;;
82983366Sjulian	add	loc2=PCB_ONFAULT,r15
83066486Sdfr	;;
83166486Sdfr	st8	[loc2]=r14
83266486Sdfr	;;
83366486Sdfr	mov	out0=in0
83466486Sdfr	mov	out1=in1
83566486Sdfr	mov	out2=in2
83666486Sdfr	;;
83766486Sdfr	br.call.sptk.few rp=bcopy		// do the copy.
83866486Sdfr	st8	[loc2]=r0			// kill the fault handler.
83967020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
84066486Sdfr	mov	rp=loc1				// restore ra.
84166486Sdfr	br.ret.sptk.few rp			// ret0 left over from bcopy
84266486SdfrEND(copyin)
84366458Sdfr
84466633SdfrENTRY(copyout, 3)
84585682Sdfr	.prologue
846115084Smarcel	.regstk	3, 3, 3, 0
84785682Sdfr	.save	ar.pfs,loc0
848115084Smarcel	alloc	loc0=ar.pfs,3,3,3,0
84985682Sdfr	.save	rp,loc1
85066486Sdfr	mov	loc1=rp
85185682Sdfr	.body
85266458Sdfr
853115084Smarcel	movl	loc2=VM_MAX_ADDRESS		// make sure that dest addr
85466486Sdfr	;;
85567020Sdfr	cmp.geu	p6,p0=in1,loc2			// is in user space.
85666486Sdfr	;;
85766486Sdfr(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
85866486Sdfr	movl	r14=copyerr			// set up fault handler.
85987702Sjhb	add	r15=PC_CURTHREAD,r13		// find curthread
86066486Sdfr	;;
86166486Sdfr	ld8	r15=[r15]
86266486Sdfr	;;
86383366Sjulian	add	r15=TD_PCB,r15			// find pcb
86466486Sdfr	;;
86566486Sdfr	ld8	r15=[r15]
86666486Sdfr	;;
86783366Sjulian	add	loc2=PCB_ONFAULT,r15
86866486Sdfr	;;
86966486Sdfr	st8	[loc2]=r14
87066486Sdfr	;;
87166486Sdfr	mov	out0=in0
87266486Sdfr	mov	out1=in1
87366486Sdfr	mov	out2=in2
87466486Sdfr	;;
87566486Sdfr	br.call.sptk.few rp=bcopy		// do the copy.
87666486Sdfr	st8	[loc2]=r0			// kill the fault handler.
87767020Sdfr	mov	ar.pfs=loc0			// restore ar.pfs
87866486Sdfr	mov	rp=loc1				// restore ra.
87966486Sdfr	br.ret.sptk.few rp			// ret0 left over from bcopy
88066486SdfrEND(copyout)
88166458Sdfr
88266633SdfrENTRY(copyerr, 0)
88387702Sjhb	add	r14=PC_CURTHREAD,r13 ;;		// find curthread
88466486Sdfr	ld8	r14=[r14] ;;
88583366Sjulian	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
88666486Sdfr	ld8	r14=[r14] ;;
88783366Sjulian	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
88866486Sdfr	st8	[r14]=r0			// reset fault handler
88966458Sdfr
89066486Sdfr	mov	ret0=EFAULT			// return EFAULT
89166486Sdfr	br.ret.sptk.few rp
89266486SdfrEND(copyerr)
893121410Smarcel
894121410Smarcel/*
895121410Smarcel * Support functions for handling of unaligned memory accesses.
896121410Smarcel */
897121410SmarcelENTRY(spillfd, 2)
898121410Smarcel	ldfd		f6 = [r32]
899121410Smarcel	;;
900121410Smarcel	stf.spill	[r33] = f6
901121410Smarcel	br.ret.sptk	rp
902121410SmarcelEND(spillfd)
903