1/*-
2 * Copyright (c) 2001-2011 Marcel Moolenaar
3 * Copyright (c) 1998 Doug Rabson
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD$
28 */
29
30#include <machine/asm.h>
31#include <machine/ia64_cpu.h>
32#include <machine/intrcnt.h>
33#include <machine/pte.h>
34#include <assym.s>
35
36/*
37 * The Altix 350 needs more than the architected 16KB (8KB for stack and
38 * 8KB for RSE backing store) when calling EFI to setup virtual mode.
39 */
40#define	FW_STACK_SIZE	3*PAGE_SIZE
41
42	.section .ivt.data, "aw"
43	.align	PAGE_SIZE
44	.global	kstack
45kstack:	.space	FW_STACK_SIZE
46	.global	kstack_top
47kstack_top:
48
49	.text
50
51/*
52 * Not really a leaf but we can't return.
53 * The EFI loader passes the physical address of the bootinfo block in
54 * register r8.
55 */
56ENTRY_NOPROFILE(__start, 1)
57	.prologue
58	.save	rp,r0
59	.body
60{	.mlx
61	mov	ar.rsc=0
62	movl	r16=ia64_vector_table	// set up IVT early
63	;;
64}
65{	.mlx
66	mov	cr.iva=r16
67	movl	r16=kstack
68	;;
69}
70{	.mmi
71	srlz.i
72	;;
73	ssm	IA64_PSR_DFH
74	mov	r17=FW_STACK_SIZE-16
75	;;
76}
77{	.mlx
78	add	sp=r16,r17		// proc0's stack
79	movl	gp=__gp			// find kernel globals
80	;;
81}
82{	.mlx
83	mov	ar.bspstore=r16		// switch backing store
84	movl	r16=bootinfo
85	;;
86}
87{	.mmi
88	st8	[r16]=r8		// save the PA of the bootinfo block
89	loadrs				// invalidate regs
90	mov	r17=IA64_DCR_DEFAULT
91	;;
92}
93{	.mmi
94	mov	cr.dcr=r17
95	mov	ar.rsc=3		// turn rse back on
96	nop	0
97	;;
98}
99{	.mmi
100	srlz.d
101	alloc	r16=ar.pfs,0,0,1,0
102	mov	out0=r0			// we are linked at the right address
103	;;				// we just need to process fptrs
104}
105{	.mib
106	nop	0
107	nop	0
108	br.call.sptk.many rp=_reloc
109	;;
110}
111{	.mib
112	nop	0
113	nop	0
114	br.call.sptk.many rp=ia64_init
115	;;
116}
117	// We have the new bspstore in r8 and the new sp in r9.
118	// Switch onto the new stack and call mi_startup().
119{	.mmi
120	mov	ar.rsc = 0
121	;;
122	mov	ar.bspstore = r8
123	mov	sp = r9
124	;;
125}
126{	.mmi
127	loadrs
128	;;
129	mov	ar.rsc = 3
130	nop	0
131	;;
132}
133{	.mib
134	nop	0
135	nop	0
136	br.call.sptk.many rp=mi_startup
137	;;
138}
139	/* NOTREACHED */
1401:	br.cond.sptk.few 1b
141END(__start)
142
143/*
144 * fork_trampoline()
145 *
146 * Arrange for a function to be invoked neatly, after a cpu_switch().
147 *
148 * Invokes fork_exit() passing in three arguments: a callout function, an
149 * argument to the callout, and a trapframe pointer.  For child processes
150 * returning from fork(2), the argument is a pointer to the child process.
151 *
152 * The callout function and its argument is in the trapframe in scratch
153 * registers r2 and r3.
154 */
155ENTRY(fork_trampoline, 0)
156	.prologue
157	.save	rp,r0
158	.body
159{	.mmi
160	alloc		r14=ar.pfs,0,0,3,0
161	add		r15=32+SIZEOF_SPECIAL+8,sp
162	add		r16=32+SIZEOF_SPECIAL+16,sp
163	;;
164}
165{	.mmi
166	ld8		out0=[r15]
167	ld8		out1=[r16]
168	nop		0
169}
170{	.mib
171	add		out2=16,sp
172	nop		0
173	br.call.sptk	rp=fork_exit
174	;;
175}
176	// If we get back here, it means we're a user space process that's
177	// the immediate result of fork(2).
178	.global		enter_userland
179	.type		enter_userland, @function
180enter_userland:
181{	.mib
182	nop		0
183	nop		0
184	br.sptk		epc_syscall_return
185	;;
186}
187END(fork_trampoline)
188
189/*
190 * Create a default interrupt name table. The first entry (vector 0) is
191 * hardwaired to the clock interrupt.
192 */
193	.data
194	.align 8
195EXPORT(intrnames)
196	.ascii "clock"
197	.fill INTRNAME_LEN - 5 - 1, 1, ' '
198	.byte 0
199intr_n = 1
200.rept INTRCNT_COUNT - 1
201	.ascii "#"
202	.byte intr_n / 100 + '0'
203	.byte (intr_n % 100) / 10 + '0'
204	.byte intr_n % 10 + '0'
205	.fill INTRNAME_LEN - 1 - 3 - 1, 1, ' '
206	.byte 0
207	intr_n = intr_n + 1
208.endr
209EXPORT(sintrnames)
210	data8 INTRCNT_COUNT * INTRNAME_LEN
211
212	.align 8
213EXPORT(intrcnt)
214	.fill INTRCNT_COUNT, 8, 0
215EXPORT(sintrcnt)
216	data8 INTRCNT_COUNT * 8
217
218	.text
219	// in0:	image base
220STATIC_ENTRY(_reloc, 1)
221	alloc	loc0=ar.pfs,1,2,0,0
222	mov	loc1=rp
223	;;
224	movl	r15=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
225	movl	r2=@gprel(fptr_storage)
226	movl	r3=@gprel(fptr_storage_end)
227	;;
228	add	r15=r15,gp		// relocate _DYNAMIC etc.
229	add	r2=r2,gp
230	add	r3=r3,gp
231	;;
2321:	ld8	r16=[r15],8		// read r15->d_tag
233	;;
234	ld8	r17=[r15],8		// and r15->d_val
235	;;
236	cmp.eq	p6,p0=DT_NULL,r16	// done?
237(p6)	br.cond.dpnt.few 2f
238	;;
239	cmp.eq	p6,p0=DT_RELA,r16
240	;;
241(p6)	add	r18=r17,in0		// found rela section
242	;;
243	cmp.eq	p6,p0=DT_RELASZ,r16
244	;;
245(p6)	mov	r19=r17			// found rela size
246	;;
247	cmp.eq	p6,p0=DT_SYMTAB,r16
248	;;
249(p6)	add	r20=r17,in0		// found symbol table
250	;;
251(p6)	setf.sig f8=r20
252	;;
253	cmp.eq	p6,p0=DT_SYMENT,r16
254	;;
255(p6)	setf.sig f9=r17			// found symbol entry size
256	;;
257	cmp.eq	p6,p0=DT_RELAENT,r16
258	;;
259(p6)	mov	r22=r17			// found rela entry size
260	;;
261	br.sptk.few 1b
262
2632:
264	ld8	r15=[r18],8		// read r_offset
265	;;
266	ld8	r16=[r18],8		// read r_info
267	add	r15=r15,in0		// relocate r_offset
268	;;
269	ld8	r17=[r18],8		// read r_addend
270	sub	r19=r19,r22		// update relasz
271
272	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
273	;;
274	cmp.eq	p6,p0=R_IA_64_NONE,r23
275(p6)	br.cond.dpnt.few 3f
276	;;
277	cmp.eq	p6,p0=R_IA_64_REL64LSB,r23
278(p6)	br.cond.dptk.few 4f
279	;;
280
281	extr.u	r16=r16,32,32		// ELF64_R_SYM(r16)
282	;;
283	setf.sig f10=r16		// so we can multiply
284	;;
285	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
286	;;
287	getf.sig r16=f10
288	;;
289	add	r16=8,r16		// address of st_value
290	;;
291	ld8	r16=[r16]		// read symbol value
292	;;
293	add	r16=r16,in0		// relocate symbol value
294	;;
295
296	cmp.eq	p6,p0=R_IA_64_DIR64LSB,r23
297(p6)	br.cond.dptk.few 5f
298	;;
299	cmp.eq	p6,p0=R_IA_64_FPTR64LSB,r23
300(p6)	br.cond.dptk.few 6f
301	;;
302
3033:
304	cmp.ltu	p6,p0=0,r19		// more?
305(p6)	br.cond.dptk.few 2b		// loop
306	mov	r8=0			// success return value
307	br.cond.sptk.few 9f		// done
308
3094:
310	add	r16=in0,r17		// BD + A
311	;;
312	st8	[r15]=r16		// word64 (LSB)
313	br.cond.sptk.few 3b
314
3155:
316	add	r16=r16,r17		// S + A
317	;;
318	st8	[r15]=r16		// word64 (LSB)
319	br.cond.sptk.few 3b
320
3216:
322	movl	r17=@gprel(fptr_storage)
323	;;
324	add	r17=r17,gp		// start of fptrs
325	;;
3267:	cmp.geu	p6,p0=r17,r2		// end of fptrs?
327(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
328	ld8	r20=[r17]		// read function from fptr
329	;;
330	cmp.eq	p6,p0=r16,r20		// same function?
331	;;
332(p6)	st8	[r15]=r17		// reuse fptr
333(p6)	br.cond.sptk.few 3b		// done
334	add	r17=16,r17		// next fptr
335	br.cond.sptk.few 7b
336
3378:					// allocate new fptr
338	mov	r8=1			// failure return value
339	cmp.geu	p6,p0=r2,r3		// space left?
340(p6)	br.cond.dpnt.few 9f		// bail out
341
342	st8	[r15]=r2		// install fptr
343	st8	[r2]=r16,8		// write fptr address
344	;;
345	st8	[r2]=gp,8		// write fptr gp
346	br.cond.sptk.few 3b
347
3489:
349	mov	ar.pfs=loc0
350	mov	rp=loc1
351	;;
352	br.ret.sptk.few rp
353
354END(_reloc)
355
356	.data
357	.align	16
358	.global fptr_storage
359fptr_storage:
360	.space	4096*16			// XXX
361fptr_storage_end:
362