support.S revision 94377
1/*-
2 * Copyright (c) 1998 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/ia64/ia64/support.S 94377 2002-04-10 19:26:49Z dfr $
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 */
71ENTRY(ia64_change_mode, 0)
72
73	rsm	psr.i | psr.ic
74	mov	r19=ar.rsc		// save rsc while we change mode
75	tbit.nz	p6,p7=r14,17		// physical or virtual ?
76	;;
77	mov	ar.rsc=0		// turn off RSE
78(p6)	mov	r15=7			// RR base for virtual addresses
79(p7)	mov	r15=0			// RR base for physical addresses
80	flushrs				// no dirty registers please
81	srlz.i
82	;;
83	mov	r16=ar.bsp
84	mov	r17=rp
85	mov	r18=ar.rnat
86	;;
87	dep	r16=r15,r16,61,3	// new address of ar.bsp
88	dep	r17=r15,r17,61,3	// new address of rp
89	dep	sp=r15,sp,61,3		// new address of sp
90	;;
91	mov	ar.bspstore=r16
92	mov	rp=r17
93	;;
941:	mov	r16=ip
95	mov	ar.rnat=r18
96	mov	cr.ipsr=r14		// psr for new mode
97	;;
98	add	r16=2f-1b,r16		// address to rfi to
99	;;
100	dep	r16=r15,r16,61,3	// new mode address for rfi
101	;;
102	mov	cr.iip=r16		// setup for rfi
103	mov	cr.ifs=r0
104	;;
105	rfi
106
1072:	mov	ar.rsc=r19		// restore ar.rsc
108	br.ret.sptk.few rp		// now in new mode
109
110END(ia64_change_mode)
111
112/*
113 * ia64_physical_mode:	change mode to physical mode
114 *
115 * Return:
116 *	ret0	psr to restore
117 *
118 * Modifies:
119 *	r15-r18	scratch
120 *	ar.bsp	tranlated to physical mode
121 *	psr.i	cleared
122 */
123ENTRY(ia64_physical_mode, 0)
124
125	mov	r14=psr
126	mov	ret0=psr
127	movl	r15=(IA64_PSR_I|IA64_PSR_IT|IA64_PSR_DT|IA64_PSR_RT|IA64_PSR_DFL|IA64_PSR_DFH)
128	movl	r16=IA64_PSR_BN
129	;;
130	andcm	r14=r14,r15		// clear various xT bits
131	;;
132	or	r14=r14,r16		// make sure BN=1
133	or	ret0=ret0,r16		// make sure BN=1
134
135	br.cond.sptk.many ia64_change_mode
136
137END(ia64_physical_mode)
138
139/*
140 * ia64_call_efi_physical:	call an EFI procedure in physical mode
141 *
142 * Arguments:
143 *	in0		Address of EFI procedure descriptor
144 *	in1-in5		Arguments to EFI procedure
145 *
146 * Return:
147 *	ret0-ret3	return values from EFI
148 *
149 */
150ENTRY(ia64_call_efi_physical, 6)
151
152	.prologue
153	.regstk	6,4,5,0
154	.save	ar.pfs,loc0
155	alloc	loc0=ar.pfs,6,4,5,0
156	;;
157	.save	rp,loc1
158	mov	loc1=rp
159	;;
160	.body
161	br.call.sptk.many rp=ia64_physical_mode
162	;;
163	mov	loc2=r8			// psr to restore mode
164	mov	loc3=gp			// save kernel gp
165	ld8	r14=[in0],8		// function address
166	;;
167	mov	out0=in1
168	mov	out1=in2
169	mov	out2=in3
170	mov	out3=in4
171	mov	out4=in5
172	ld8	gp=[in0]		// function gp value
173	;;
174	mov	b6=r14
175	;;
176	br.call.sptk.many rp=b6		// call EFI procedure
177	mov	gp=loc3			// restore kernel gp
178	;;
179	mov	r14=loc2		// psr to restore mode
180	br.call.sptk.many rp=ia64_change_mode
181	;;
182	mov	rp=loc1
183	mov	ar.pfs=loc0
184	;;
185	br.ret.sptk.many rp
186
187END(ia64_call_efi_physical)
188
189/**************************************************************************/
190
191/*
192 * fu{byte,word} : fetch a byte (word) from user memory
193 */
194
195ENTRY(suword, 2)
196
197	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
198	cmp.geu	p6,p0=in0,r14
199(p6)	br.dpnt.few fusufault
200
201	movl	r14=fusufault			// set up fault handler.
202	add	r15=PC_CURTHREAD,r13		// find curthread
203	;;
204	ld8	r15=[r15]
205	;;
206	add	r15=TD_PCB,r15			// find pcb
207	;;
208	ld8	r15=[r15]
209	;;
210	add	r15=PCB_ONFAULT,r15
211	;;
212	st8	[r15]=r14
213	;;
214	st8.rel	[in0]=in1			// try the store
215	;;
216	st8	[r15]=r0			// clean up
217
218	mov	ret0=r0
219	br.ret.sptk.few rp
220
221END(suword)
222
223ENTRY(suhword, 2)
224
225	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
226	cmp.geu	p6,p0=in0,r14
227(p6)	br.dpnt.few fusufault
228
229	movl	r14=fusufault			// set up fault handler.
230	add	r15=PC_CURTHREAD,r13		// find curthread
231	;;
232	ld8	r15=[r15]
233	;;
234	add	r15=TD_PCB,r15			// find pcb
235	;;
236	ld8	r15=[r15]
237	;;
238	add	r15=PCB_ONFAULT,r15
239	;;
240	st8	[r15]=r14
241	;;
242	st4.rel	[in0]=in1			// try the store
243	;;
244	st8	[r15]=r0			// clean up
245
246	mov	ret0=r0
247	br.ret.sptk.few rp
248
249END(suhword)
250
251ENTRY(subyte, 2)
252
253	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
254	cmp.geu	p6,p0=in0,r14
255(p6)	br.dpnt.few fusufault
256
257	movl	r14=fusufault			// set up fault handler.
258	add	r15=PC_CURTHREAD,r13		// find curthread
259	;;
260	ld8	r15=[r15]
261	;;
262	add	r15=TD_PCB,r15			// find pcb
263	;;
264	ld8	r15=[r15]
265	;;
266	add	r15=PCB_ONFAULT,r15
267	;;
268	st8	[r15]=r14
269	;;
270	st1.rel	[in0]=in1			// try the store
271	;;
272	st8	[r15]=r0			// clean up
273
274	mov	ret0=r0
275	br.ret.sptk.few rp
276
277END(subyte)
278
279ENTRY(fuword, 1)
280
281	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
282	cmp.geu	p6,p0=in0,r14
283(p6)	br.dpnt.few fusufault
284
285	movl	r14=fusufault			// set up fault handler.
286	add	r15=PC_CURTHREAD,r13		// find curthread
287	;;
288	ld8	r15=[r15]
289	;;
290	add	r15=TD_PCB,r15			// find pcb
291	;;
292	ld8	r15=[r15]
293	;;
294	add	r15=PCB_ONFAULT,r15
295	;;
296	st8	[r15]=r14
297	;;
298	ld8.acq	ret0=[in0]			// try the fetch
299	;;
300	st8	[r15]=r0			// clean up
301
302	br.ret.sptk.few rp
303
304END(fuword)
305
306ENTRY(fuhword, 1)
307
308	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
309	cmp.geu	p6,p0=in0,r14
310(p6)	br.dpnt.few fusufault
311
312	movl	r14=fusufault			// set up fault handler.
313	add	r15=PC_CURTHREAD,r13		// find curthread
314	;;
315	ld8	r15=[r15]
316	;;
317	add	r15=TD_PCB,r15			// find pcb
318	;;
319	ld8	r15=[r15]
320	;;
321	add	r15=PCB_ONFAULT,r15
322	;;
323	st8	[r15]=r14
324	;;
325	ld4.acq	ret0=[in0]			// try the fetch
326	;;
327	st8	[r15]=r0			// clean up
328
329	br.ret.sptk.few rp
330
331END(fuhword)
332
333ENTRY(fubyte, 1)
334
335	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
336	cmp.geu	p6,p0=in0,r14
337(p6)	br.dpnt.few fusufault
338
339	movl	r14=fusufault			// set up fault handler.
340	add	r15=PC_CURTHREAD,r13		// find curthread
341	;;
342	ld8	r15=[r15]
343	;;
344	add	r15=TD_PCB,r15			// find pcb
345	;;
346	ld8	r15=[r15]
347	;;
348	add	r15=PCB_ONFAULT,r15
349	;;
350	st8	[r15]=r14
351	;;
352	ld1.acq	ret0=[in0]			// try the fetch
353	;;
354	st8	[r15]=r0			// clean up
355
356	br.ret.sptk.few rp
357
358END(fubyte)
359
360ENTRY(suibyte, 2)
361	mov	ret0=-1
362	br.ret.sptk.few rp
363END(suibyte)
364
365ENTRY(fusufault, 0)
366	st8	[r15]=r0 ;;			// r15 points at onfault
367	mov	ret0=r0
368	br.ret.sptk.few rp
369END(fusufault)
370
371ENTRY(fswintrberr, 0)
372XENTRY(fuswintr)					/* XXX what is a 'word'? */
373XENTRY(suswintr)					/* XXX what is a 'word'? */
374	mov	ret0=-1
375	br.ret.sptk.few rp
376END(fswintrberr)
377
378/**************************************************************************/
379
380/*
381 * Copy a null-terminated string within the kernel's address space.
382 * If lenp is not NULL, store the number of chars copied in *lenp
383 *
384 * int copystr(char *from, char *to, size_t len, size_t *lenp);
385 */
386ENTRY(copystr, 4)
387	mov	r14=in2			// r14 = i = len
388	cmp.eq	p6,p0=r0,in2
389(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
390
3911:	ld1	r15=[in0],1		// read one byte
392	;;
393	st1	[in1]=r15,1		// write that byte
394	add	in2=-1,in2		// len--
395	;;
396	cmp.eq	p6,p0=r0,r15
397	cmp.ne	p7,p0=r0,in2
398	;;
399(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
400(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
401
4022:	cmp.eq	p6,p0=r0,in3
403(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
404	sub	r14=r14,in2		// *lenp = (i - len)
405	;;
406	st8	[in3]=r14
407
4083:	cmp.eq	p6,p0=r0,r15
409(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
410
411	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
412	br.ret.sptk.few rp
413
4144:	mov	ret0=0			// return 0.
415	br.ret.sptk.few rp
416
417END(copystr)
418
419ENTRY(copyinstr, 4)
420	.prologue
421	.regstk	4, 3, 4, 0
422	.save	ar.pfs,loc0
423	alloc	loc0=ar.pfs,4,3,4,0
424	.save	rp,loc1
425	mov	loc1=rp
426	.body
427
428	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
429	;;
430	cmp.geu	p6,p0=in0,loc2			// is in user space.
431	;;
432(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
433	movl	r14=copyerr			// set up fault handler.
434	add	r15=PC_CURTHREAD,r13		// find curthread
435	;;
436	ld8	r15=[r15]
437	;;
438	add	r15=TD_PCB,r15			// find pcb
439	;;
440	ld8	r15=[r15]
441	;;
442	add	loc2=PCB_ONFAULT,r15
443	;;
444	st8	[loc2]=r14
445	;;
446	mov	out0=in0
447	mov	out1=in1
448	mov	out2=in2
449	mov	out3=in3
450	;;
451	br.call.sptk.few rp=copystr		// do the copy.
452	st8	[loc2]=r0			// kill the fault handler.
453	mov	ar.pfs=loc0			// restore ar.pfs
454	mov	rp=loc1				// restore ra.
455	br.ret.sptk.few rp			// ret0 left over from copystr
456
457END(copyinstr)
458
459ENTRY(copyoutstr, 4)
460	.prologue
461	.regstk	4, 3, 4, 0
462	.save	ar.pfs,loc0
463	alloc	loc0=ar.pfs,4,3,4,0
464	.save	rp,loc1
465	mov	loc1=rp
466	.body
467
468	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
469	;;
470	cmp.geu	p6,p0=in1,loc2			// is in user space.
471	;;
472(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
473	movl	r14=copyerr			// set up fault handler.
474	add	r15=PC_CURTHREAD,r13		// find curthread
475	;;
476	ld8	r15=[r15]
477	;;
478	add	r15=TD_PCB,r15			// find pcb
479	;;
480	ld8	r15=[r15]
481	;;
482	add	loc2=PCB_ONFAULT,r15
483	;;
484	st8	[loc2]=r14
485	;;
486	mov	out0=in0
487	mov	out1=in1
488	mov	out2=in2
489	mov	out3=in3
490	;;
491	br.call.sptk.few rp=copystr		// do the copy.
492	st8	[loc2]=r0			// kill the fault handler.
493	mov	ar.pfs=loc0			// restore ar.pfs
494	mov	rp=loc1				// restore ra.
495	br.ret.sptk.few rp			// ret0 left over from copystr
496
497END(copyoutstr)
498
499/*
500 * Not the fastest bcopy in the world.
501 */
502ENTRY(bcopy, 3)
503XENTRY(ovbcopy)
504
505	mov	ret0=r0				// return zero for copy{in,out}
506	;;
507	cmp.le	p6,p0=in2,r0			// bail if len <= 0
508(p6)	br.ret.spnt.few rp
509
510	sub	r14=in1,in0 ;;			// check for overlap
511	cmp.ltu	p6,p0=r14,in2			// dst-src < len
512(p6)	br.cond.spnt.few 5f
513
514	extr.u	r14=in0,0,3			// src & 7
515	extr.u	r15=in1,0,3 ;;			// dst & 7
516	cmp.eq	p6,p0=r14,r15			// different alignment?
517(p6)	br.cond.spnt.few 2f			// branch if same alignment
518
5191:	ld1	r14=[in0],1 ;;			// copy bytewise
520	st1	[in1]=r14,1
521	add	in2=-1,in2 ;;			// len--
522	cmp.ne	p6,p0=r0,in2
523(p6)	br.cond.dptk.few 1b			// loop
524	br.ret.sptk.few rp			// done
525
5262:	cmp.eq	p6,p0=r14,r0			// aligned?
527(p6)	br.cond.sptk.few 4f
528
5293:	ld1	r14=[in0],1 ;;			// copy bytewise
530	st1	[in1]=r14,1
531	extr.u	r15=in0,0,3			// src & 7
532	add	in2=-1,in2 ;;			// len--
533	cmp.eq	p6,p0=r0,in2			// done?
534	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
535(p6)	br.ret.spnt.few rp			// return if done
536(p7)	br.cond.spnt.few 4f			// go to main copy
537	br.cond.sptk.few 3b			// more bytes to copy
538
539	// At this point, in2 is non-zero
540
5414:	mov	r14=8 ;;
542	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
543(p6)	br.cond.spnt.few 1b			// byte copy the end
544	ld8	r15=[in0],8 ;;			// copy word
545	st8	[in1]=r15,8
546	add	in2=-8,in2 ;;			// len -= 8
547	cmp.ne	p6,p0=r0,in2			// done?
548(p6)	br.cond.spnt.few 4b			// again
549
550	br.ret.sptk.few rp			// return
551
552	// Don't bother optimising overlap case
553
5545:	add	in0=in0,in2
555	add	in1=in1,in2 ;;
556	add	in0=-1,in0
557	add	in1=-1,in1 ;;
558
5596:	ld1	r14=[in0],-1 ;;
560	st1	[in1]=r14,-1
561	add	in2=-1,in2 ;;
562	cmp.ne	p6,p0=r0,in2
563(p6)	br.cond.spnt.few 6b
564
565	br.ret.sptk.few rp
566
567END(bcopy)
568
569ENTRY(memcpy,3)
570
571	mov	r14=in0 ;;
572	mov	in0=in1 ;;
573	mov	in1=r14
574	br.cond.sptk.few bcopy
575
576END(memcpy)
577
578ENTRY(copyin, 3)
579
580	.prologue
581	.regstk	4, 3, 4, 0
582	.save	ar.pfs,loc0
583	alloc	loc0=ar.pfs,4,3,4,0
584	.save	rp,loc1
585	mov	loc1=rp
586	.body
587
588	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
589	;;
590	cmp.geu	p6,p0=in0,loc2			// is in user space.
591	;;
592(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
593	movl	r14=copyerr			// set up fault handler.
594	add	r15=PC_CURTHREAD,r13		// find curthread
595	;;
596	ld8	r15=[r15]
597	;;
598	add	r15=TD_PCB,r15			// find pcb
599	;;
600	ld8	r15=[r15]
601	;;
602	add	loc2=PCB_ONFAULT,r15
603	;;
604	st8	[loc2]=r14
605	;;
606	mov	out0=in0
607	mov	out1=in1
608	mov	out2=in2
609	;;
610	br.call.sptk.few rp=bcopy		// do the copy.
611	st8	[loc2]=r0			// kill the fault handler.
612	mov	ar.pfs=loc0			// restore ar.pfs
613	mov	rp=loc1				// restore ra.
614	br.ret.sptk.few rp			// ret0 left over from bcopy
615
616END(copyin)
617
618ENTRY(copyout, 3)
619
620	.prologue
621	.regstk	4, 3, 4, 0
622	.save	ar.pfs,loc0
623	alloc	loc0=ar.pfs,4,3,4,0
624	.save	rp,loc1
625	mov	loc1=rp
626	.body
627
628	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
629	;;
630	cmp.geu	p6,p0=in1,loc2			// is in user space.
631	;;
632(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
633	movl	r14=copyerr			// set up fault handler.
634	add	r15=PC_CURTHREAD,r13		// find curthread
635	;;
636	ld8	r15=[r15]
637	;;
638	add	r15=TD_PCB,r15			// find pcb
639	;;
640	ld8	r15=[r15]
641	;;
642	add	loc2=PCB_ONFAULT,r15
643	;;
644	st8	[loc2]=r14
645	;;
646	mov	out0=in0
647	mov	out1=in1
648	mov	out2=in2
649	;;
650	br.call.sptk.few rp=bcopy		// do the copy.
651	st8	[loc2]=r0			// kill the fault handler.
652	mov	ar.pfs=loc0			// restore ar.pfs
653	mov	rp=loc1				// restore ra.
654	br.ret.sptk.few rp			// ret0 left over from bcopy
655
656END(copyout)
657
658ENTRY(copyerr, 0)
659
660	add	r14=PC_CURTHREAD,r13 ;;		// find curthread
661	ld8	r14=[r14] ;;
662	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
663	ld8	r14=[r14] ;;
664	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
665	st8	[r14]=r0			// reset fault handler
666
667	mov	ret0=EFAULT			// return EFAULT
668	br.ret.sptk.few rp
669
670END(copyerr)
671