1/*	$NetBSD: locore.S,v 1.3 2009/07/20 04:41:37 kiyohara Exp $	*/
2
3/*-
4 * Copyright (c) 1998 Doug Rabson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30
31#include "opt_multiprocessor.h"
32
33#include <machine/asm.h>
34#include <machine/ia64_cpu.h>
35#include <machine/pte.h>
36#include <machine/elf_machdep.h>
37#include <sys/syscall.h>
38
39#include <machine/intrcnt.h>
40
41#include "assym.h"
42
43	.section .data.proc0,"aw"
44	.global	kstack
45	.align	PAGE_SIZE
46kstack:	.space KSTACK_PAGES * PAGE_SIZE
47
48	.text
49
50/*
51 * Not really a leaf but we can't return.
52 * The EFI loader passes the physical address of the bootinfo block in
53 * register r8.
54 */
55ENTRY_NOPROFILE(start, 1)
56	.prologue
57	.save	rp,r0
58	.body
59{	.mlx
60	mov	ar.rsc=0
61	movl	r16=ia64_vector_table	// set up IVT early
62	;;
63}
64{	.mlx
65	mov	cr.iva=r16
66	movl	r16=kstack
67	;;
68}
69{	.mmi
70	srlz.i
71	;;
72	ssm	IA64_PSR_DFH
73	mov	r17=KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
74	;;
75}
76{	.mlx
77	add	sp=r16,r17		// proc0's stack
78	movl	gp=__gp			// find kernel globals
79	;;
80}
81{	.mlx
82	mov	ar.bspstore=r16		// switch backing store
83	movl	r16=pa_bootinfo
84	;;
85}
86	st8	[r16]=r8		// save the PA of the bootinfo block
87	loadrs				// invalidate regs
88	;;
89	mov	ar.rsc=3		// turn rse back on
90	;;
91	alloc	r16=ar.pfs,0,0,1,0
92	;;
93	movl	out0=0			// we are linked at the right address
94	;;				// we just need to process fptrs
95//	br.call.sptk.many rp=_reloc	// XXX:	Look into relocs
96	;;
97	br.call.sptk.many rp=ia64_init
98	;;
99	/* NOTREACHED */
1001:	br.cond.sptk.few 1b
101END(start)
102
103
104#ifdef MULTIPROCESSOR
105/*
106 * AP wake-up entry point. The handoff state is similar as for the BSP,
107 * as described on page 3-9 of the IPF SAL Specification. The difference
108 * lies in the contents of register b0. For APs this register holds the
109 * return address into the SAL rendezvous routine.
110 *
111 * Note that we're responsible for clearing the IRR bit by reading cr.ivr
112 * and issuing the EOI to the local SAPIC.
113 */
114	.align	32
115ENTRY_NOPROFILE(os_boot_rendez,0)
116	mov	r16=cr.ivr	// clear IRR bit
117	;;
118	srlz.d
119	mov	cr.eoi=r0	// ACK the wake-up
120	;;
121	srlz.d
122	rsm	IA64_PSR_IC|IA64_PSR_I
123	;;
124	mov	r16 = (5<<8)|(PAGE_SHIFT<<2)|1
125	movl	r17 = 5<<61
126	;;
127	mov	rr[r17] = r16
128	;;
129	srlz.d
130	mov	r16 = (6<<8)|(IA64_ID_PAGE_SHIFT<<2)
131	movl	r17 = 6<<61
132	;;
133	mov	rr[r17] = r16
134	;;
135	srlz.d
136	mov	r16 = (7<<8)|(IA64_ID_PAGE_SHIFT<<2)
137	movl	r17 = 7<<61
138	;;
139	mov	rr[r17] = r16
140	;;
141	srlz.d
142	mov	r16 = PTE_PRESENT+PTE_MA_WB+PTE_ACCESSED+PTE_DIRTY+ \
143			PTE_PL_KERN+PTE_AR_RWX
144	mov	r18 = 28<<2
145	;;
146
147	mov	cr.ifa = r17
148	mov	cr.itir = r18
149	ptr.d	r17, r18
150	ptr.i	r17, r18
151	;;
152	srlz.i
153	;;
154	itr.d	dtr[r0] = r16
155	;;
156	itr.i	itr[r0] = r16
157	;;
158	srlz.i
159	;;
1601:	mov	r16 = ip
161	add	r17 = 2f-1b, r17
162	movl	r18 = (IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_DFH|IA64_PSR_DT|IA64_PSR_IC|IA64_PSR_IT|IA64_PSR_RT)
163	;;
164	add	r17 = r17, r16
165	mov	cr.ipsr = r18
166	mov	cr.ifs = r0
167	;;
168	mov	cr.iip = r17
169	;;
170	rfi
171
172	.align	32
1732:
174{	.mlx
175	mov	ar.rsc = 0
176	movl	r16 = ia64_vector_table			// set up IVT early
177	;;
178}
179{	.mlx
180	mov	cr.iva = r16
181	movl	r16 = ap_stack
182	;;
183}
184{	.mmi
185	srlz.i
186	;;
187	ld8	r16 = [r16]
188	mov	r18 = KSTACK_PAGES*PAGE_SIZE-SIZEOF_PCB-SIZEOF_TRAPFRAME-16
189	;;
190}
191{	.mlx
192	mov	ar.bspstore = r16
193	movl	gp = __gp
194	;;
195}
196{	.mmi
197	loadrs
198	;;
199	alloc	r17 = ar.pfs, 0, 0, 0, 0
200	add	sp = r18, r16
201	;;
202}
203{	.mfb
204	mov	ar.rsc = 3
205	nop	0
206	br.call.sptk.few rp = ia64_ap_startup
207	;;
208}
209	/* NOT REACHED */
2109:
211{	.mfb
212	nop	0
213	nop	0
214	br.sptk	9b
215	;;
216}
217END(os_boot_rendez)
218
219#endif /* MULTIPROCESSOR */
220
221/*
222 * Create a default interrupt name table. The first entry (vector 0) is
223 * hardwaired to the clock interrupt.
224 */
225	.data
226	.align 8
227EXPORT(intrnames)
228	.ascii "clock"
229	.fill INTRNAME_LEN - 5 - 1, 1, ' '
230	.byte 0
231intr_n = 0
232.rept INTRCNT_COUNT - 1
233	.ascii "#"
234	.byte intr_n / 100 + '0'
235	.byte (intr_n % 100) / 10 + '0'
236	.byte intr_n % 10 + '0'
237	.fill INTRNAME_LEN - 1 - 3 - 1, 1, ' '
238	.byte 0
239	intr_n = intr_n + 1
240.endr
241EXPORT(eintrnames)
242	.align 8
243EXPORT(intrcnt)
244	.fill INTRCNT_COUNT, 8, 0
245EXPORT(eintrcnt)
246
247	.text
248	// in0:	image base
249/*STATIC_ENTRY(_reloc, 1)
250	alloc	loc0=ar.pfs,1,2,0,0
251	mov	loc1=rp
252	;;
253	movl	r15=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
254	movl	r2=@gprel(fptr_storage)
255	movl	r3=@gprel(fptr_storage_end)
256	;;
257	add	r15=r15,gp		// relocate _DYNAMIC etc.
258	add	r2=r2,gp
259	add	r3=r3,gp
260	;;
2611:	ld8	r16=[r15],8		// read r15->d_tag
262	;;
263	ld8	r17=[r15],8		// and r15->d_val
264	;;
265	cmp.eq	p6,p0=DT_NULL,r16	// done?
266(p6)	br.cond.dpnt.few 2f
267	;;
268	cmp.eq	p6,p0=DT_RELA,r16
269	;;
270(p6)	add	r18=r17,in0		// found rela section
271	;;
272	cmp.eq	p6,p0=DT_RELASZ,r16
273	;;
274(p6)	mov	r19=r17			// found rela size
275	;;
276	cmp.eq	p6,p0=DT_SYMTAB,r16
277	;;
278(p6)	add	r20=r17,in0		// found symbol table
279	;;
280(p6)	setf.sig f8=r20
281	;;
282	cmp.eq	p6,p0=DT_SYMENT,r16
283	;;
284(p6)	setf.sig f9=r17			// found symbol entry size
285	;;
286	cmp.eq	p6,p0=DT_RELAENT,r16
287	;;
288(p6)	mov	r22=r17			// found rela entry size
289	;;
290	br.sptk.few 1b
291
2922:
293	ld8	r15=[r18],8		// read r_offset
294	;;
295	ld8	r16=[r18],8		// read r_info
296	add	r15=r15,in0		// relocate r_offset
297	;;
298	ld8	r17=[r18],8		// read r_addend
299	sub	r19=r19,r22		// update relasz
300
301	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
302	;;
303	cmp.eq	p6,p0=R_IA64_NONE,r23
304(p6)	br.cond.dpnt.few 3f
305	;;
306	cmp.eq	p6,p0=R_IA64_REL64LSB,r23
307(p6)	br.cond.dptk.few 4f
308	;;
309
310	extr.u	r16=r16,32,32		// ELF64_R_SYM(r16)
311	;;
312	setf.sig f10=r16		// so we can multiply
313	;;
314	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
315	;;
316	getf.sig r16=f10
317	;;
318	add	r16=8,r16		// address of st_value
319	;;
320	ld8	r16=[r16]		// read symbol value
321	;;
322	add	r16=r16,in0		// relocate symbol value
323	;;
324
325	cmp.eq	p6,p0=R_IA64_DIR64LSB,r23
326(p6)	br.cond.dptk.few 5f
327	;;
328	cmp.eq	p6,p0=R_IA64_FPTR64LSB,r23
329(p6)	br.cond.dptk.few 6f
330	;;
331
3323:
333	cmp.ltu	p6,p0=0,r19		// more?
334(p6)	br.cond.dptk.few 2b		// loop
335	mov	r8=0			// success return value
336	br.cond.sptk.few 9f		// done
337
3384:
339	add	r16=in0,r17		// BD + A
340	;;
341	st8	[r15]=r16		// word64 (LSB)
342	br.cond.sptk.few 3b
343
3445:
345	add	r16=r16,r17		// S + A
346	;;
347	st8	[r15]=r16		// word64 (LSB)
348	br.cond.sptk.few 3b
349
3506:
351	movl	r17=@gprel(fptr_storage)
352	;;
353	add	r17=r17,gp		// start of fptrs
354	;;
3557:	cmp.geu	p6,p0=r17,r2		// end of fptrs?
356(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
357	ld8	r20=[r17]		// read function from fptr
358	;;
359	cmp.eq	p6,p0=r16,r20		// same function?
360	;;
361(p6)	st8	[r15]=r17		// reuse fptr
362(p6)	br.cond.sptk.few 3b		// done
363	add	r17=16,r17		// next fptr
364	br.cond.sptk.few 7b
365
3668:					// allocate new fptr
367	mov	r8=1			// failure return value
368	cmp.geu	p6,p0=r2,r3		// space left?
369(p6)	br.cond.dpnt.few 9f		// bail out
370
371	st8	[r15]=r2		// install fptr
372	st8	[r2]=r16,8		// write fptr address
373	;;
374	st8	[r2]=gp,8		// write fptr gp
375	br.cond.sptk.few 3b
376
3779:
378	mov	ar.pfs=loc0
379	mov	rp=loc1
380	;;
381	br.ret.sptk.few rp
382
383END(_reloc)*/
384
385	.data
386	.align	16
387	.global fptr_storage
388fptr_storage:
389	.space	4096*16			// XXX
390fptr_storage_end:
391