start.S revision 95190
1/*-
2 * Copyright (c) 2001 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/boot/ia64/efi/start.S 95190 2002-04-21 08:49:47Z marcel $
27 */
28
29	.text
30
31#include <machine/asm.h>
32
33#define EFI_SUCCESS		0
34#define EFI_LOAD_ERROR		1
35#define EFI_BUFFER_TOO_SMALL	5
36
37#define DT_NULL		0	/* Terminating entry. */
38#define DT_NEEDED	1	/* String table offset of a needed shared
39				   library. */
40#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
41#define DT_PLTGOT	3	/* Processor-dependent address. */
42#define DT_HASH		4	/* Address of symbol hash table. */
43#define DT_STRTAB	5	/* Address of string table. */
44#define DT_SYMTAB	6	/* Address of symbol table. */
45#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
46#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
47#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
48#define DT_STRSZ	10	/* Size of string table. */
49#define DT_SYMENT	11	/* Size of each symbol table entry. */
50#define DT_INIT		12	/* Address of initialization function. */
51#define DT_FINI		13	/* Address of finalization function. */
52#define DT_SONAME	14	/* String table offset of shared object
53				   name. */
54#define DT_RPATH	15	/* String table offset of library path. */
55#define DT_SYMBOLIC	16	/* Indicates "symbolic" linking. */
56#define DT_REL		17	/* Address of ElfNN_Rel relocations. */
57#define DT_RELSZ	18	/* Total size of ElfNN_Rel relocations. */
58#define DT_RELENT	19	/* Size of each ElfNN_Rel relocation. */
59#define DT_PLTREL	20	/* Type of relocation used for PLT. */
60#define DT_DEBUG	21	/* Reserved (not used). */
61#define DT_TEXTREL	22	/* Indicates there may be relocations in
62				   non-writable segments. */
63#define DT_JMPREL	23	/* Address of PLT relocations. */
64
65#define DT_COUNT	24	/* Number of defined d_tag values. */
66
67#define R_IA64_NONE		0	/* None */
68#define R_IA64_DIR64MSB		0x26	/* word64 MSB	S + A */
69#define R_IA64_DIR64LSB		0x27	/* word64 LSB	S + A */
70#define R_IA64_FPTR64MSB	0x46	/* word64 MSB	@fptr(S + A) */
71#define R_IA64_FPTR64LSB	0x47	/* word64 LSB	@fptr(S + A) */
72#define R_IA64_REL64MSB		0x6e	/* word64 MSB	BD + A */
73#define R_IA64_REL64LSB		0x6f	/* word64 LSB	BD + A */
74#define	R_IA64_IPLTLSB		0x81	/* function descriptor LSB speciaal */
75
76ENTRY(_start, 2)
77	alloc	loc0=ar.pfs,2,3,3,0
78	mov	loc1=rp
79	movl	loc2=@gprel(ImageBase)
80	;;
81	add	loc2=gp,loc2
82	;;
83	mov	out0=loc2
84	mov	out1=in1
85	;;
86	br.call.sptk.few rp=_reloc	// relocate image
87
88	cmp.ne	p6,p0=EFI_SUCCESS,r8	// did it work?
89(p6)	br.cond.dpnt.few 9f
90
91	mov	out0=in0		// image_handle
92	mov	out1=in1		// system_table
93	br.call.sptk.few rp=efi_main
949:
95	mov	ar.pfs=loc0
96	mov	rp=loc1
97	;;
98	br.ret.sptk.few rp
99END(_start)
100
101	// PLABEL for PE32+
102	.global _start_plabel
103	.section .plabel, "a"
104	.align	16
105_start_plabel:
106	.quad	_start
107	.quad	__gp
108	.previous
109
110	// A PE32+ relocation entry for the plabel
111
112	.section .reloc, "a"
113	.long	_start_plabel
114	.long	12
115	.short	(10 << 12) + 0
116	.short	(10 << 12) + 8
117	.previous
118
119// in0:	image base
120// in1:	system table
121//
122// XXX Assumes PLT relocations are of type Elf_Rela
123//
124// r2 = address of fptr_storage
125// r3 = address of fptr_storage_end
126// r4 = address of first free fptr
127//
128// r15 = r_offset
129// r16 = r_info		-OR-	d_tag
130// r17 = r_addend	-OR-	d_val (=d_ptr)
131// r18 = address of .rela dynamic section
132// r19 = size of .rela section
133// r20 = size of .rela element (Elf_Rela)
134// r21 = address of first PLT relocation
135// r22 = size of PLT relocations
136// r23 = relocation type
137// r24 = address of symbol
138// r28 = R_IA64_IPLTLSB
139// f8 = address of symbol table
140// f9 = size of symtab element
141
142STATIC_ENTRY(_reloc, 2)
143	alloc	loc0=ar.pfs,2,2,0,0
144	;;
145	mov	loc1=rp
146	movl	r29=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
147	;;
148	add	r15=r29,gp
149	movl	r29=@gprel(fptr_storage)
150	;;
151	add	r2=r29,gp
152	movl	r29=@gprel(fptr_storage_end)
153	;;
154	add	r3=r29,gp
155	mov	r4=r2
156	mov	r19=0
157	mov	r22=0
158	mov	r20=24
159	mov	r28=R_IA64_IPLTLSB
160	;;
1611:
162	ld8	r16=[r15],8		// read r15->d_tag
163	;;
164	ld8	r17=[r15],8		// and r15->d_val
165	;;
166	cmp.eq	p6,p0=DT_NULL,r16	// done?
167(p6)	br.cond.dpnt.few 2f
168	;;
169	cmp.eq	p6,p0=DT_RELA,r16	// rela section?
170	;;
171(p6)	add	r18=r17,in0
172	cmp.eq	p6,p0=DT_RELASZ,r16	// rela section size?
173	;;
174(p6)	mov	r19=r17
175	cmp.eq	p6,p0=DT_RELAENT,r16	// rela entry size?
176	;;
177(p6)	mov	r20=r17
178	cmp.eq	p6,p0=DT_JMPREL,r16	// PLT relocs?
179	;;
180(p6)	add	r21=r17,in0
181	cmp.eq	p6,p0=DT_PLTRELSZ,r16	// PLT relocs size?
182	;;
183(p6)	mov	r22=r17
184	cmp.eq	p6,p0=DT_SYMTAB,r16	// symbol table?
185	;;
186(p6)	add	r29=r17,in0
187	;;
188(p6)	setf.sig f8=r29
189	cmp.eq	p6,p0=DT_SYMENT,r16	// symbol entry size?
190	;;
191(p6)	setf.sig f9=r17
192	br.dptk	1b
193
1942:
195	cmp.lt	p6,p0=0,r19
196(p6)	br.cond.dptk	3f
197	;;
198	mov	r19=r22
199	mov	r18=r21
200	mov	r21=0
201	mov	r22=0
202	;;
203	cmp.lt	p6,p0=0,r19
204(p6)	br.cond.dptk	3f
205	;;
206	mov	r8=EFI_SUCCESS
207	br.dptk	9f
2083:
209	ld8	r29=[r18],8		// read r_offset
210	;;
211	ld8	r16=[r18],8		// read r_info
212	add	r15=r29,in0		// relocate r_offset
213	;;
214	ld8	r17=[r18],8		// read r_addend
215	sub	r19=r19,r20		// update relasz
216	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
217	;;
218	cmp.eq	p6,p0=R_IA64_NONE,r23
219(p6)	br.cond.dpnt.few 2b
220	;;
221	cmp.eq	p6,p0=R_IA64_REL64LSB,r23
222(p6)	br.cond.dptk.few 4f
223	;;
224	extr.u	r29=r16,32,32		// ELF64_R_SYM(r16)
225	;;
226	setf.sig f10=r29		// so we can multiply
227	;;
228	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
229	;;
230	getf.sig r29=f10
231	;;
232	add	r29=8,r29		// address of st_value
233	;;
234	ld8	r29=[r29]		// read symbol value
235	;;
236	add	r24=r29,in0		// relocate symbol value
237	;;
238	cmp.eq	p6,p0=R_IA64_DIR64LSB,r23
239(p6)	br.cond.dptk.few 5f
240	;;
241	cmp.eq	p6,p0=R_IA64_FPTR64LSB,r23
242(p6)	br.cond.dptk.few 6f
243	;;
244	cmp.ne	p6,p0=r28,r23		// IPLTLSB
245(p6)	br.cond.dptk.few 2b
246
247	// IPLTLSB
248	add	r29=r24,r17		// S + A
249	;;
250	st8	[r15]=r29,8		// fdesc:FP
251	;;
252	st8	[r15]=gp		// fdesc:GP
253	br.cond.sptk.few 2b
254
255	// REL64LSB
2564:
257	add	r29=in0,r17		// BD + A
258	;;
259	st8	[r15]=r29		// word64
260	br.cond.sptk.few 2b
261
262	// DIR64LSB
2635:
264	add	r29=r24,r17		// S + A
265	;;
266	st8	[r15]=r29		// word64
267	br.cond.sptk.few 2b
268
2696:
270	mov	r29=r2			// FPTR64LSB
271	;;
2727:
273	cmp.geu	p6,p0=r29,r4		// end of fptrs?
274(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
275	ld8	r17=[r29]		// read function from fptr
276	;;
277	cmp.eq	p6,p0=r24,r17		// same function?
278	;;
279(p6)	st8	[r15]=r29		// reuse fptr
280(p6)	br.cond.sptk.few 2b		// done
281	add	r29=16,r29		// next fptr
282	br.sptk.few 7b
2838:
284	mov	r8=EFI_BUFFER_TOO_SMALL	// failure return value
285	cmp.geu	p6,p0=r4,r3		// space left?
286(p6)	br.cond.dpnt.few 9f		// bail out
287	st8	[r15]=r4		// install fptr
288	;;
289	st8	[r4]=r24,8		// write fptr address
290	;;
291	st8	[r4]=gp,8		// write fptr gp
292	br.cond.sptk.few 2b
293
2949:
295	mov	ar.pfs=loc0
296	mov	rp=loc1
297	;;
298	br.ret.sptk.few rp
299END(_reloc)
300
301	// in0:	system table
302	// in1:	character
303ENTRY(_putchar, 2)
304	alloc	loc0=ar.pfs,2,3,2,0
305	mov	loc1=rp
306	mov	loc2=gp
307	add	sp=-32,sp
308	;;
309	add	r14=64,in0		// r14 = &in1->ConOut
310	;;
311	ld8	r14=[r14]		// r14 = in1->ConOut
312	;;
313	add	r15=8,r14		// r15 = &r14->OutputString
314	mov	out0=r14
315	mov	out1=sp
316	mov	r16=sp
317	;;
318	ld8	r15=[r15]		// r15 = r14->OutputString
319	st2	[r16]=in1,2		// write character
320	;;
321	st2	[r16]=r0		// terminate
322	ld8	r17=[r15],8		// function address
323	;;
324	ld8	gp=[r15]		// function gp
325	mov	b6=r17			// transfer to branch register
326	;;
327	br.call.sptk.few rp=b6		// call function
328	;;
329	mov	gp=loc2			// restore gp
330	mov	ar.pfs=loc0
331	mov	rp=loc1
332	add	sp=32,sp
333	;;
334	br.ret.sptk.few rp
335
336END(_putchar)
337
338	// in0:	system table
339	// in1:	string
340ENTRY(_puts, 2)
341	alloc	loc0=ar.pfs,3,2,2,0
342	mov	loc1=rp
343	;;
344	mov	out0=in0
345	;;
3461:	ld1	out1=[in1],1
347	;;
348	cmp.eq	p6,p0=r0,out1
349(p6)	br.cond.dpnt.few 9f
350	;;
351	br.call.sptk.few rp=_putchar
352	;;
353	br.cond.sptk.few 1b
3549:
355	mov	ar.pfs=loc0
356	mov	rp=loc1
357	;;
358	br.ret.sptk.few rp
359END(_puts)
360
361	// in0:	system table
362	// in1:	number
363ENTRY(_puthex, 2)
364	alloc	loc0=ar.pfs,2,3,2,0
365	mov	loc1=rp
366	mov	loc2=ar.lc
367	;;
368	mov	out0=in0
369	mov	ar.lc=15
370	;;
3711:	extr.u	out1=in1,60,4
372	;;
373	cmp.leu	p6,p7=10,out1
374	;;
375(p6)	add	out1='a'-10,out1
376(p7)	add	out1='0',out1
377	dep.z	in1=in1,4,60
378	;;
379	br.call.sptk.few rp=_putchar
380	;;
381	br.cloop.sptk.few 1b
382	;;
383	mov	out1='\r'
384	;;
385	br.call.sptk.few rp=_putchar
386	;;
387	mov	out1='\n'
388	;;
389	br.call.sptk.few rp=_putchar
390	;;
3919:
392	mov	ar.pfs=loc0
393	mov	rp=loc1
394	mov	ar.lc=loc2
395	;;
396	br.ret.sptk.few rp
397END(_puthex)
398
399	.data
400	.align	16
401
402fptr_storage:
403	.space	1024*16			// XXX
404fptr_storage_end:
405