locore.S revision 205234
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/locore.S 205234 2010-03-17 00:37:15Z marcel $
27 */
28
29#include <sys/syscall.h>
30#include <machine/asm.h>
31#include <machine/ia64_cpu.h>
32#include <machine/intrcnt.h>
33#include <machine/pte.h>
34#include <machine/intrcnt.h>
35#include <assym.s>
36
37	.section .data.proc0,"aw"
38	.global	kstack
39	.align	PAGE_SIZE
40kstack:	.space KSTACK_PAGES * PAGE_SIZE
41
42	.text
43
44/*
45 * Not really a leaf but we can't return.
46 * The EFI loader passes the physical address of the bootinfo block in
47 * register r8.
48 */
49ENTRY_NOPROFILE(__start, 1)
50	.prologue
51	.save	rp,r0
52	.body
53{	.mlx
54	mov	ar.rsc=0
55	movl	r16=ia64_vector_table	// set up IVT early
56	;;
57}
58{	.mlx
59	mov	cr.iva=r16
60	movl	r16=kstack
61	;;
62}
63{	.mmi
64	srlz.i
65	;;
66	ssm	IA64_PSR_DFH
67	mov	r17=KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
68	;;
69}
70{	.mlx
71	add	sp=r16,r17		// proc0's stack
72	movl	gp=__gp			// find kernel globals
73	;;
74}
75{	.mlx
76	mov	ar.bspstore=r16		// switch backing store
77	movl	r16=pa_bootinfo
78	;;
79}
80{	.mmi
81	st8	[r16]=r8		// save the PA of the bootinfo block
82	loadrs				// invalidate regs
83	mov	r17=IA64_DCR_DEFAULT
84	;;
85}
86{	.mmi
87	mov	cr.dcr=r17
88	mov	ar.rsc=3		// turn rse back on
89	nop	0
90	;;
91}
92{	.mmi
93	srlz.d
94	alloc	r16=ar.pfs,0,0,1,0
95	mov	out0=r0			// we are linked at the right address
96	;;				// we just need to process fptrs
97}
98{	.mib
99	nop	0
100	nop	0
101	br.call.sptk.many rp=_reloc
102	;;
103}
104{	.mib
105	nop	0
106	nop	0
107	br.call.sptk.many rp=ia64_init
108	;;
109}
110	// We have the new bspstore in r8 and the new sp in r9.
111	// Switch onto the new stack and call mi_startup().
112{	.mmi
113	mov	ar.rsc = 0
114	;;
115	mov	ar.bspstore = r8
116	mov	sp = r9
117	;;
118}
119{	.mmi
120	loadrs
121	;;
122	mov	ar.rsc = 3
123	nop	0
124	;;
125}
126{	.mib
127	nop	0
128	nop	0
129	br.call.sptk.many rp=mi_startup
130	;;
131}
132	/* NOTREACHED */
1331:	br.cond.sptk.few 1b
134END(__start)
135
136/*
137 * fork_trampoline()
138 *
139 * Arrange for a function to be invoked neatly, after a cpu_switch().
140 *
141 * Invokes fork_exit() passing in three arguments: a callout function, an
142 * argument to the callout, and a trapframe pointer.  For child processes
143 * returning from fork(2), the argument is a pointer to the child process.
144 *
145 * The callout function and its argument is in the trapframe in scratch
146 * registers r2 and r3.
147 */
148ENTRY(fork_trampoline, 0)
149	.prologue
150	.save	rp,r0
151	.body
152{	.mmi
153	alloc		r14=ar.pfs,0,0,3,0
154	add		r15=32+SIZEOF_SPECIAL+8,sp
155	add		r16=32+SIZEOF_SPECIAL+16,sp
156	;;
157}
158{	.mmi
159	ld8		out0=[r15]
160	ld8		out1=[r16]
161	nop		0
162}
163{	.mib
164	add		out2=16,sp
165	nop		0
166	br.call.sptk	rp=fork_exit
167	;;
168}
169	// If we get back here, it means we're a user space process that's
170	// the immediate result of fork(2).
171	.global		enter_userland
172	.type		enter_userland, @function
173enter_userland:
174{	.mib
175	nop		0
176	nop		0
177	br.sptk		epc_syscall_return
178	;;
179}
180END(fork_trampoline)
181
182#ifdef SMP
183/*
184 * AP wake-up entry point. The handoff state is similar as for the BSP,
185 * as described on page 3-9 of the IPF SAL Specification. The difference
186 * lies in the contents of register b0. For APs this register holds the
187 * return address into the SAL rendezvous routine.
188 *
189 * Note that we're responsible for clearing the IRR bit by reading cr.ivr
190 * and issuing the EOI to the local SAPIC.
191 */
192	.align	32
193ENTRY_NOPROFILE(os_boot_rendez,0)
194	mov	r16=cr.ivr	// clear IRR bit
195	;;
196	srlz.d
197	mov	cr.eoi=r0	// ACK the wake-up
198	;;
199	srlz.d
200	rsm	IA64_PSR_IC|IA64_PSR_I
201	;;
202	mov	r16 = (5<<8)|(PAGE_SHIFT<<2)|1
203	movl	r17 = 5<<61
204	;;
205	mov	rr[r17] = r16
206	;;
207	srlz.d
208	mov	r16 = (6<<8)|(IA64_ID_PAGE_SHIFT<<2)
209	movl	r17 = 6<<61
210	;;
211	mov	rr[r17] = r16
212	;;
213	srlz.d
214	mov	r16 = (7<<8)|(IA64_ID_PAGE_SHIFT<<2)
215	movl	r17 = 7<<61
216	;;
217	mov	rr[r17] = r16
218	;;
219	srlz.d
220	mov	r18 = 28<<2
221	movl	r16 = PTE_PRESENT+PTE_MA_WB+PTE_ACCESSED+PTE_DIRTY+ \
222			PTE_PL_KERN+PTE_AR_RWX+PTE_ED
223	;;
224	mov	cr.ifa = r17
225	mov	cr.itir = r18
226	ptr.d	r17, r18
227	ptr.i	r17, r18
228	;;
229	srlz.i
230	;;
231	itr.d	dtr[r0] = r16
232	mov	r18 = IA64_DCR_DEFAULT
233	;;
234	itr.i	itr[r0] = r16
235	mov	cr.dcr = r18
236	;;
237	srlz.i
238	;;
2391:	mov	r16 = ip
240	add	r17 = 2f-1b, r17
241	movl	r18 = (IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_DFH|IA64_PSR_DT|IA64_PSR_IC|IA64_PSR_IT|IA64_PSR_RT)
242	;;
243	add	r17 = r17, r16
244	mov	cr.ipsr = r18
245	mov	cr.ifs = r0
246	;;
247	mov	cr.iip = r17
248	;;
249	rfi
250
251	.align	32
2522:
253{	.mlx
254	mov	ar.rsc = 0
255	movl	r16 = ia64_vector_table			// set up IVT early
256	;;
257}
258{	.mlx
259	mov	cr.iva = r16
260	movl	r16 = ap_stack
261	;;
262}
263{	.mmi
264	srlz.i
265	;;
266	ld8	r16 = [r16]
267	mov	r18 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
268	;;
269}
270{	.mlx
271	mov	ar.bspstore = r16
272	movl	gp = __gp
273	;;
274}
275{	.mmi
276	loadrs
277	;;
278	alloc	r17 = ar.pfs, 0, 0, 0, 0
279	add	sp = r18, r16
280	;;
281}
282{	.mib
283	mov	ar.rsc = 3
284	nop	0
285	br.call.sptk.few rp = ia64_ap_startup
286	;;
287}
288	/* NOT REACHED */
2899:
290{	.mib
291	nop	0
292	nop	0
293	br.sptk	9b
294	;;
295}
296END(os_boot_rendez)
297
298#endif /* !SMP */
299
300/*
301 * Create a default interrupt name table. The first entry (vector 0) is
302 * hardwaired to the clock interrupt.
303 */
304	.data
305	.align 8
306EXPORT(intrnames)
307	.ascii "clock"
308	.fill INTRNAME_LEN - 5 - 1, 1, ' '
309	.byte 0
310intr_n = 1
311.rept INTRCNT_COUNT - 1
312	.ascii "#"
313	.byte intr_n / 100 + '0'
314	.byte (intr_n % 100) / 10 + '0'
315	.byte intr_n % 10 + '0'
316	.fill INTRNAME_LEN - 1 - 3 - 1, 1, ' '
317	.byte 0
318	intr_n = intr_n + 1
319.endr
320EXPORT(eintrnames)
321	.align 8
322EXPORT(intrcnt)
323	.fill INTRCNT_COUNT, 8, 0
324EXPORT(eintrcnt)
325
326	.text
327	// in0:	image base
328STATIC_ENTRY(_reloc, 1)
329	alloc	loc0=ar.pfs,1,2,0,0
330	mov	loc1=rp
331	;;
332	movl	r15=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
333	movl	r2=@gprel(fptr_storage)
334	movl	r3=@gprel(fptr_storage_end)
335	;;
336	add	r15=r15,gp		// relocate _DYNAMIC etc.
337	add	r2=r2,gp
338	add	r3=r3,gp
339	;;
3401:	ld8	r16=[r15],8		// read r15->d_tag
341	;;
342	ld8	r17=[r15],8		// and r15->d_val
343	;;
344	cmp.eq	p6,p0=DT_NULL,r16	// done?
345(p6)	br.cond.dpnt.few 2f
346	;;
347	cmp.eq	p6,p0=DT_RELA,r16
348	;;
349(p6)	add	r18=r17,in0		// found rela section
350	;;
351	cmp.eq	p6,p0=DT_RELASZ,r16
352	;;
353(p6)	mov	r19=r17			// found rela size
354	;;
355	cmp.eq	p6,p0=DT_SYMTAB,r16
356	;;
357(p6)	add	r20=r17,in0		// found symbol table
358	;;
359(p6)	setf.sig f8=r20
360	;;
361	cmp.eq	p6,p0=DT_SYMENT,r16
362	;;
363(p6)	setf.sig f9=r17			// found symbol entry size
364	;;
365	cmp.eq	p6,p0=DT_RELAENT,r16
366	;;
367(p6)	mov	r22=r17			// found rela entry size
368	;;
369	br.sptk.few 1b
370
3712:
372	ld8	r15=[r18],8		// read r_offset
373	;;
374	ld8	r16=[r18],8		// read r_info
375	add	r15=r15,in0		// relocate r_offset
376	;;
377	ld8	r17=[r18],8		// read r_addend
378	sub	r19=r19,r22		// update relasz
379
380	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
381	;;
382	cmp.eq	p6,p0=R_IA_64_NONE,r23
383(p6)	br.cond.dpnt.few 3f
384	;;
385	cmp.eq	p6,p0=R_IA_64_REL64LSB,r23
386(p6)	br.cond.dptk.few 4f
387	;;
388
389	extr.u	r16=r16,32,32		// ELF64_R_SYM(r16)
390	;;
391	setf.sig f10=r16		// so we can multiply
392	;;
393	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
394	;;
395	getf.sig r16=f10
396	;;
397	add	r16=8,r16		// address of st_value
398	;;
399	ld8	r16=[r16]		// read symbol value
400	;;
401	add	r16=r16,in0		// relocate symbol value
402	;;
403
404	cmp.eq	p6,p0=R_IA_64_DIR64LSB,r23
405(p6)	br.cond.dptk.few 5f
406	;;
407	cmp.eq	p6,p0=R_IA_64_FPTR64LSB,r23
408(p6)	br.cond.dptk.few 6f
409	;;
410
4113:
412	cmp.ltu	p6,p0=0,r19		// more?
413(p6)	br.cond.dptk.few 2b		// loop
414	mov	r8=0			// success return value
415	br.cond.sptk.few 9f		// done
416
4174:
418	add	r16=in0,r17		// BD + A
419	;;
420	st8	[r15]=r16		// word64 (LSB)
421	br.cond.sptk.few 3b
422
4235:
424	add	r16=r16,r17		// S + A
425	;;
426	st8	[r15]=r16		// word64 (LSB)
427	br.cond.sptk.few 3b
428
4296:
430	movl	r17=@gprel(fptr_storage)
431	;;
432	add	r17=r17,gp		// start of fptrs
433	;;
4347:	cmp.geu	p6,p0=r17,r2		// end of fptrs?
435(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
436	ld8	r20=[r17]		// read function from fptr
437	;;
438	cmp.eq	p6,p0=r16,r20		// same function?
439	;;
440(p6)	st8	[r15]=r17		// reuse fptr
441(p6)	br.cond.sptk.few 3b		// done
442	add	r17=16,r17		// next fptr
443	br.cond.sptk.few 7b
444
4458:					// allocate new fptr
446	mov	r8=1			// failure return value
447	cmp.geu	p6,p0=r2,r3		// space left?
448(p6)	br.cond.dpnt.few 9f		// bail out
449
450	st8	[r15]=r2		// install fptr
451	st8	[r2]=r16,8		// write fptr address
452	;;
453	st8	[r2]=gp,8		// write fptr gp
454	br.cond.sptk.few 3b
455
4569:
457	mov	ar.pfs=loc0
458	mov	rp=loc1
459	;;
460	br.ret.sptk.few rp
461
462END(_reloc)
463
464	.data
465	.align	16
466	.global fptr_storage
467fptr_storage:
468	.space	4096*16			// XXX
469fptr_storage_end:
470