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