support.S revision 84114
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 84114 2001-09-29 09:54:42Z 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	alloc	loc0=ar.pfs,6,4,5,0
153	;;
154	mov	loc1=rp
155	;;
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
182END(ia64_call_efi_physical)
183
184/**************************************************************************/
185
186/*
187 * fu{byte,word} : fetch a byte (word) from user memory
188 */
189
190ENTRY(suword, 2)
191
192	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
193	cmp.geu	p6,p0=in0,r14
194(p6)	br.dpnt.few fusufault
195
196	movl	r14=fusufault			// set up fault handler.
197	add	r15=GD_CURTHREAD,r13		// find curthread
198	;;
199	ld8	r15=[r15]
200	;;
201	add	r15=TD_PCB,r15			// find pcb
202	;;
203	ld8	r15=[r15]
204	;;
205	add	r15=PCB_ONFAULT,r15
206	;;
207	st8	[r15]=r14
208	;;
209	st8.rel	[in0]=in1			// try the store
210	;;
211	st8	[r15]=r0			// clean up
212
213	mov	ret0=r0
214	br.ret.sptk.few rp
215
216END(suword)
217
218ENTRY(subyte, 2)
219
220	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
221	cmp.geu	p6,p0=in0,r14
222(p6)	br.dpnt.few fusufault
223
224	movl	r14=fusufault			// set up fault handler.
225	add	r15=GD_CURTHREAD,r13		// find curthread
226	;;
227	ld8	r15=[r15]
228	;;
229	add	r15=TD_PCB,r15			// find pcb
230	;;
231	ld8	r15=[r15]
232	;;
233	add	r15=PCB_ONFAULT,r15
234	;;
235	st8	[r15]=r14
236	;;
237	st1.rel	[in0]=in1			// try the store
238	;;
239	st8	[r15]=r0			// clean up
240
241	mov	ret0=r0
242	br.ret.sptk.few rp
243
244END(subyte)
245
246ENTRY(fuword, 1)
247
248	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
249	cmp.geu	p6,p0=in0,r14
250(p6)	br.dpnt.few fusufault
251
252	movl	r14=fusufault			// set up fault handler.
253	add	r15=GD_CURTHREAD,r13		// find curthread
254	;;
255	ld8	r15=[r15]
256	;;
257	add	r15=TD_PCB,r15			// find pcb
258	;;
259	ld8	r15=[r15]
260	;;
261	add	r15=PCB_ONFAULT,r15
262	;;
263	st8	[r15]=r14
264	;;
265	ld8.acq	ret0=[in0]			// try the fetch
266	;;
267	st8	[r15]=r0			// clean up
268
269	br.ret.sptk.few rp
270
271END(fuword)
272
273ENTRY(fubyte, 1)
274
275	movl	r14=VM_MAXUSER_ADDRESS;;	// make sure address is ok
276	cmp.geu	p6,p0=in0,r14
277(p6)	br.dpnt.few fusufault
278
279	movl	r14=fusufault			// set up fault handler.
280	add	r15=GD_CURTHREAD,r13		// find curthread
281	;;
282	ld8	r15=[r15]
283	;;
284	add	r15=TD_PCB,r15			// find pcb
285	;;
286	ld8	r15=[r15]
287	;;
288	add	r15=PCB_ONFAULT,r15
289	;;
290	st8	[r15]=r14
291	;;
292	ld1.acq	ret0=[in0]			// try the fetch
293	;;
294	st8	[r15]=r0			// clean up
295
296	br.ret.sptk.few rp
297
298END(fubyte)
299
300ENTRY(suibyte, 2)
301	mov	ret0=-1
302	br.ret.sptk.few rp
303END(suibyte)
304
305ENTRY(fusufault, 0)
306	st8	[r15]=r0 ;;			// r15 points at onfault
307	mov	ret0=r0
308	br.ret.sptk.few rp
309END(fusufault)
310
311ENTRY(fswintrberr, 0)
312XENTRY(fuswintr)					/* XXX what is a 'word'? */
313XENTRY(suswintr)					/* XXX what is a 'word'? */
314	mov	ret0=-1
315	br.ret.sptk.few rp
316END(fswintrberr)
317
318/**************************************************************************/
319
320/*
321 * Copy a null-terminated string within the kernel's address space.
322 * If lenp is not NULL, store the number of chars copied in *lenp
323 *
324 * int copystr(char *from, char *to, size_t len, size_t *lenp);
325 */
326ENTRY(copystr, 4)
327	mov	r14=in2			// r14 = i = len
328	cmp.eq	p6,p0=r0,in2
329(p6)	br.cond.spnt.few 2f		// if (len == 0), bail out
330
3311:	ld1	r15=[in0],1		// read one byte
332	;;
333	st1	[in1]=r15,1		// write that byte
334	add	in2=-1,in2		// len--
335	;;
336	cmp.eq	p6,p0=r0,r15
337	cmp.ne	p7,p0=r0,in2
338	;;
339(p6)	br.cond.spnt.few 2f		// if (*from == 0), bail out
340(p7)	br.cond.sptk.few 1b		// if (len != 0) copy more
341
3422:	cmp.eq	p6,p0=r0,in3
343(p6)	br.cond.dpnt.few 3f		// if (lenp != NULL)
344	sub	r14=r14,in2		// *lenp = (i - len)
345	;;
346	st8	[in3]=r14
347
3483:	cmp.eq	p6,p0=r0,r15
349(p6)	br.cond.spnt.few 4f		// *from == '\0'; leave quietly
350
351	mov	ret0=ENAMETOOLONG	// *from != '\0'; error.
352	br.ret.sptk.few rp
353
3544:	mov	ret0=0			// return 0.
355	br.ret.sptk.few rp
356
357END(copystr)
358
359ENTRY(copyinstr, 4)
360	alloc	loc0=ar.pfs,4,3,4,0
361	mov	loc1=rp
362
363	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
364	;;
365	cmp.geu	p6,p0=in0,loc2			// is in user space.
366	;;
367(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
368	movl	r14=copyerr			// set up fault handler.
369	add	r15=GD_CURTHREAD,r13		// find curthread
370	;;
371	ld8	r15=[r15]
372	;;
373	add	r15=TD_PCB,r15			// find pcb
374	;;
375	ld8	r15=[r15]
376	;;
377	add	loc2=PCB_ONFAULT,r15
378	;;
379	st8	[loc2]=r14
380	;;
381	mov	out0=in0
382	mov	out1=in1
383	mov	out2=in2
384	mov	out3=in3
385	;;
386	br.call.sptk.few rp=copystr		// do the copy.
387	st8	[loc2]=r0			// kill the fault handler.
388	mov	ar.pfs=loc0			// restore ar.pfs
389	mov	rp=loc1				// restore ra.
390	br.ret.sptk.few rp			// ret0 left over from copystr
391
392END(copyinstr)
393
394ENTRY(copyoutstr, 4)
395	alloc	loc0=ar.pfs,4,3,4,0
396	mov	loc1=rp
397
398	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
399	;;
400	cmp.geu	p6,p0=in1,loc2			// is in user space.
401	;;
402(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
403	movl	r14=copyerr			// set up fault handler.
404	add	r15=GD_CURTHREAD,r13		// find curthread
405	;;
406	ld8	r15=[r15]
407	;;
408	add	r15=TD_PCB,r15			// find pcb
409	;;
410	ld8	r15=[r15]
411	;;
412	add	loc2=PCB_ONFAULT,r15
413	;;
414	st8	[loc2]=r14
415	;;
416	mov	out0=in0
417	mov	out1=in1
418	mov	out2=in2
419	mov	out3=in3
420	;;
421	br.call.sptk.few rp=copystr		// do the copy.
422	st8	[loc2]=r0			// kill the fault handler.
423	mov	ar.pfs=loc0			// restore ar.pfs
424	mov	rp=loc1				// restore ra.
425	br.ret.sptk.few rp			// ret0 left over from copystr
426
427END(copyoutstr)
428
429/*
430 * Not the fastest bcopy in the world.
431 */
432ENTRY(bcopy, 3)
433XENTRY(ovbcopy)
434
435	mov	ret0=r0				// return zero for copy{in,out}
436	;;
437	cmp.le	p6,p0=in2,r0			// bail if len <= 0
438(p6)	br.ret.spnt.few rp
439
440	sub	r14=in1,in0 ;;			// check for overlap
441	cmp.ltu	p6,p0=r14,in2			// dst-src < len
442(p6)	br.cond.spnt.few 5f
443
444	extr.u	r14=in0,0,3			// src & 7
445	extr.u	r15=in1,0,3 ;;			// dst & 7
446	cmp.eq	p6,p0=r14,r15			// different alignment?
447(p6)	br.cond.spnt.few 2f			// branch if same alignment
448
4491:	ld1	r14=[in0],1 ;;			// copy bytewise
450	st1	[in1]=r14,1
451	add	in2=-1,in2 ;;			// len--
452	cmp.ne	p6,p0=r0,in2
453(p6)	br.cond.dptk.few 1b			// loop
454	br.ret.sptk.few rp			// done
455
4562:	cmp.eq	p6,p0=r14,r0			// aligned?
457(p6)	br.cond.sptk.few 4f
458
4593:	ld1	r14=[in0],1 ;;			// copy bytewise
460	st1	[in1]=r14,1
461	extr.u	r15=in0,0,3			// src & 7
462	add	in2=-1,in2 ;;			// len--
463	cmp.eq	p6,p0=r0,in2			// done?
464	cmp.eq	p7,p0=r0,r15 ;;			// aligned now?
465(p6)	br.ret.spnt.few rp			// return if done
466(p7)	br.cond.spnt.few 4f			// go to main copy
467	br.cond.sptk.few 3b			// more bytes to copy
468
469	// At this point, in2 is non-zero
470
4714:	mov	r14=8 ;;
472	cmp.ltu	p6,p0=in2,r14 ;;		// len < 8?
473(p6)	br.cond.spnt.few 1b			// byte copy the end
474	ld8	r15=[in0],8 ;;			// copy word
475	st8	[in1]=r15,8
476	add	in2=-8,in2 ;;			// len -= 8
477	cmp.ne	p6,p0=r0,in2			// done?
478(p6)	br.cond.spnt.few 4b			// again
479
480	br.ret.sptk.few rp			// return
481
482	// Don't bother optimising overlap case
483
4845:	add	in0=in0,in2
485	add	in1=in1,in2 ;;
486	add	in0=-1,in0
487	add	in1=-1,in1 ;;
488
4896:	ld1	r14=[in0],-1 ;;
490	st1	[in1]=r14,-1
491	add	in2=-1,in2 ;;
492	cmp.ne	p6,p0=r0,in2
493(p6)	br.cond.spnt.few 6b
494
495	br.ret.sptk.few rp
496
497END(bcopy)
498
499ENTRY(memcpy,3)
500
501	mov	r14=in0 ;;
502	mov	in0=in1 ;;
503	mov	in1=r14
504	br.cond.sptk.few bcopy
505
506END(memcpy)
507
508ENTRY(copyin, 3)
509
510	alloc	loc0=ar.pfs,3,3,3,0
511	mov	loc1=rp
512
513	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that src addr
514	;;
515	cmp.geu	p6,p0=in0,loc2			// is in user space.
516	;;
517(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
518	movl	r14=copyerr			// set up fault handler.
519	add	r15=GD_CURTHREAD,r13		// find curthread
520	;;
521	ld8	r15=[r15]
522	;;
523	add	r15=TD_PCB,r15			// find pcb
524	;;
525	ld8	r15=[r15]
526	;;
527	add	loc2=PCB_ONFAULT,r15
528	;;
529	st8	[loc2]=r14
530	;;
531	mov	out0=in0
532	mov	out1=in1
533	mov	out2=in2
534	;;
535	br.call.sptk.few rp=bcopy		// do the copy.
536	st8	[loc2]=r0			// kill the fault handler.
537	mov	ar.pfs=loc0			// restore ar.pfs
538	mov	rp=loc1				// restore ra.
539	br.ret.sptk.few rp			// ret0 left over from bcopy
540
541END(copyin)
542
543ENTRY(copyout, 3)
544
545	alloc	loc0=ar.pfs,3,3,3,0
546	mov	loc1=rp
547
548	movl	loc2=VM_MAXUSER_ADDRESS		// make sure that dest addr
549	;;
550	cmp.geu	p6,p0=in1,loc2			// is in user space.
551	;;
552(p6)	br.cond.spnt.few copyerr		// if it's not, error out.
553	movl	r14=copyerr			// set up fault handler.
554	add	r15=GD_CURTHREAD,r13		// find curthread
555	;;
556	ld8	r15=[r15]
557	;;
558	add	r15=TD_PCB,r15			// find pcb
559	;;
560	ld8	r15=[r15]
561	;;
562	add	loc2=PCB_ONFAULT,r15
563	;;
564	st8	[loc2]=r14
565	;;
566	mov	out0=in0
567	mov	out1=in1
568	mov	out2=in2
569	;;
570	br.call.sptk.few rp=bcopy		// do the copy.
571	st8	[loc2]=r0			// kill the fault handler.
572	mov	ar.pfs=loc0			// restore ar.pfs
573	mov	rp=loc1				// restore ra.
574	br.ret.sptk.few rp			// ret0 left over from bcopy
575
576END(copyout)
577
578ENTRY(copyerr, 0)
579
580	add	r14=GD_CURTHREAD,r13 ;;		// find curthread
581	ld8	r14=[r14] ;;
582	add	r14=TD_PCB,r14 ;;		// curthread->td_addr
583	ld8	r14=[r14] ;;
584	add	r14=PCB_ONFAULT,r14 ;;		// &curthread->td_pcb->pcb_onfault
585	st8	[r14]=r0			// reset fault handler
586
587	mov	ret0=EFAULT			// return EFAULT
588	br.ret.sptk.few rp
589
590END(copyerr)
591