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$
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_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
39#define DT_SYMTAB	6	/* Address of symbol table. */
40#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
41#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
42#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
43#define DT_SYMENT	11	/* Size of each symbol table entry. */
44#define DT_JMPREL	23	/* Address of PLT relocations. */
45
46#define R_IA_64_NONE		0	/* None */
47#define R_IA_64_DIR64LSB	0x27	/* word64 LSB	S + A */
48#define R_IA_64_FPTR64LSB	0x47	/* word64 LSB	@fptr(S + A) */
49#define R_IA_64_REL32LSB	0x6d	/* word32 LSB	BD + A */
50#define R_IA_64_REL64LSB	0x6f	/* word64 LSB	BD + A */
51#define	R_IA_64_IPLTLSB		0x81	/* function descriptor LSB speciaal */
52
53ENTRY(_start, 2)
54	alloc	loc0=ar.pfs,2,3,3,0
55	mov	loc1=rp
56	movl	loc2=@gprel(ImageBase)
57	;;
58	add	loc2=gp,loc2
59	;;
60	mov	out0=loc2
61	mov	out1=in1
62	;;
63	br.call.sptk.few rp=_reloc	// relocate image
64
65	cmp.ne	p6,p0=EFI_SUCCESS,r8	// did it work?
66(p6)	br.cond.dpnt.few 9f
67
68	mov	out0=in0		// image_handle
69	mov	out1=in1		// system_table
70	br.call.sptk.few rp=efi_main
719:
72	mov	ar.pfs=loc0
73	mov	rp=loc1
74	;;
75	br.ret.sptk.few rp
76END(_start)
77
78	// PLABEL for PE32+
79	.section .plabel, "a"
80	.align	16
81	.global _start_plabel
82_start_plabel:
83	data16	@iplt(_start)
84	.previous
85
86	// A PE32+ relocation entry for the plabel
87	.section .reloc, "a"
88	data4	_start_plabel
89	data4	12
90	data2	(10 << 12) + 0
91	data2	(10 << 12) + 8
92	.previous
93
94// in0:	image base
95// in1:	system table
96//
97// XXX Assumes PLT relocations are of type Elf_Rela
98//
99// r2 = address of fptr_storage
100// r3 = address of fptr_storage_end
101// r4 = address of first free fptr
102//
103// r15 = r_offset
104// r16 = r_info		-OR-	d_tag
105// r17 = r_addend	-OR-	d_val (=d_ptr)
106// r18 = address of .rela dynamic section
107// r19 = size of .rela section
108// r20 = size of .rela element (Elf_Rela)
109// r21 = address of first PLT relocation
110// r22 = size of PLT relocations
111// r23 = relocation type
112// r24 = address of symbol
113// r28 = R_IA_64_IPLTLSB
114// f8 = address of symbol table
115// f9 = size of symtab element
116
117STATIC_ENTRY(_reloc, 2)
118	alloc	loc0=ar.pfs,2,2,0,0
119	;;
120	mov	loc1=rp
121	movl	r29=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
122	;;
123	add	r15=r29,gp
124	movl	r29=@gprel(fptr_storage)
125	;;
126	add	r2=r29,gp
127	movl	r29=@gprel(fptr_storage_end)
128	;;
129	add	r3=r29,gp
130	mov	r4=r2
131	mov	r19=0
132	mov	r22=0
133	mov	r20=24
134	mov	r28=R_IA_64_IPLTLSB
135	;;
1361:
137	ld8	r16=[r15],8		// read r15->d_tag
138	;;
139	ld8	r17=[r15],8		// and r15->d_val
140	;;
141	cmp.eq	p6,p0=DT_NULL,r16	// done?
142(p6)	br.cond.dpnt.few 2f
143	;;
144	cmp.eq	p6,p0=DT_RELA,r16	// rela section?
145	;;
146(p6)	add	r18=r17,in0
147	cmp.eq	p6,p0=DT_RELASZ,r16	// rela section size?
148	;;
149(p6)	mov	r19=r17
150	cmp.eq	p6,p0=DT_RELAENT,r16	// rela entry size?
151	;;
152(p6)	mov	r20=r17
153	cmp.eq	p6,p0=DT_JMPREL,r16	// PLT relocs?
154	;;
155(p6)	add	r21=r17,in0
156	cmp.eq	p6,p0=DT_PLTRELSZ,r16	// PLT relocs size?
157	;;
158(p6)	mov	r22=r17
159	cmp.eq	p6,p0=DT_SYMTAB,r16	// symbol table?
160	;;
161(p6)	add	r29=r17,in0
162	;;
163(p6)	setf.sig f8=r29
164	cmp.eq	p6,p0=DT_SYMENT,r16	// symbol entry size?
165	;;
166(p6)	setf.sig f9=r17
167	br.dptk	1b
168
1692:
170	cmp.lt	p6,p0=0,r19
171(p6)	br.cond.dptk	3f
172	;;
173	mov	r19=r22
174	mov	r18=r21
175	mov	r21=0
176	mov	r22=0
177	;;
178	cmp.lt	p6,p0=0,r19
179(p6)	br.cond.dptk	3f
180	;;
181	mov	r8=EFI_SUCCESS
182	br.dptk	9f
1833:
184	ld8	r29=[r18],8		// read r_offset
185	;;
186	ld8	r16=[r18],8		// read r_info
187	add	r15=r29,in0		// relocate r_offset
188	;;
189	ld8	r17=[r18],8		// read r_addend
190	sub	r19=r19,r20		// update relasz
191	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
192	;;
193	cmp.eq	p6,p0=R_IA_64_NONE,r23
194(p6)	br.cond.dpnt.few 2b
195	;;
196	cmp.eq	p6,p0=R_IA_64_REL32LSB,r23
197(p6)	br.cond.dptk.few 3f
198	;;
199	cmp.eq	p6,p0=R_IA_64_REL64LSB,r23
200(p6)	br.cond.dptk.few 4f
201	;;
202	extr.u	r29=r16,32,32		// ELF64_R_SYM(r16)
203	;;
204	setf.sig f10=r29		// so we can multiply
205	;;
206	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
207	;;
208	getf.sig r29=f10
209	;;
210	add	r29=8,r29		// address of st_value
211	;;
212	ld8	r29=[r29]		// read symbol value
213	;;
214	add	r24=r29,in0		// relocate symbol value
215	;;
216	cmp.eq	p6,p0=R_IA_64_DIR64LSB,r23
217(p6)	br.cond.dptk.few 5f
218	;;
219	cmp.eq	p6,p0=R_IA_64_FPTR64LSB,r23
220(p6)	br.cond.dptk.few 6f
221	;;
222	cmp.ne	p6,p0=r28,r23		// IPLTLSB
223(p6)	br.cond.dptk.few 2b
224
225	// IPLTLSB
226	add	r29=r24,r17		// S + A
227	;;
228	st8	[r15]=r29,8		// fdesc:FP
229	;;
230	st8	[r15]=gp		// fdesc:GP
231	br.cond.sptk.few 2b
232
233	// REL32LSB
2343:
235	add	r29=in0,r17
236	;;
237	st4	[r15]=r29
238	br.cond.sptk.few 2b
239
240	// REL64LSB
2414:
242	add	r29=in0,r17		// BD + A
243	;;
244	st8	[r15]=r29		// word64
245	br.cond.sptk.few 2b
246
247	// DIR64LSB
2485:
249	add	r29=r24,r17		// S + A
250	;;
251	st8	[r15]=r29		// word64
252	br.cond.sptk.few 2b
253
2546:
255	mov	r29=r2			// FPTR64LSB
256	;;
2577:
258	cmp.geu	p6,p0=r29,r4		// end of fptrs?
259(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
260	ld8	r17=[r29]		// read function from fptr
261	;;
262	cmp.eq	p6,p0=r24,r17		// same function?
263	;;
264(p6)	st8	[r15]=r29		// reuse fptr
265(p6)	br.cond.sptk.few 2b		// done
266	add	r29=16,r29		// next fptr
267	br.sptk.few 7b
2688:
269	mov	r8=EFI_BUFFER_TOO_SMALL	// failure return value
270	cmp.geu	p6,p0=r4,r3		// space left?
271(p6)	br.cond.dpnt.few 9f		// bail out
272	st8	[r15]=r4		// install fptr
273	;;
274	st8	[r4]=r24,8		// write fptr address
275	;;
276	st8	[r4]=gp,8		// write fptr gp
277	br.cond.sptk.few 2b
278
2799:
280	mov	ar.pfs=loc0
281	mov	rp=loc1
282	;;
283	br.ret.sptk.few rp
284END(_reloc)
285
286	.data
287	.align	16
288fptr_storage:
289	.space	1024*16			// XXX
290fptr_storage_end:
291