177943Sdfr/*-
277943Sdfr * Copyright (c) 2001 Doug Rabson
377943Sdfr * All rights reserved.
477943Sdfr *
577943Sdfr * Redistribution and use in source and binary forms, with or without
677943Sdfr * modification, are permitted provided that the following conditions
777943Sdfr * are met:
877943Sdfr * 1. Redistributions of source code must retain the above copyright
977943Sdfr *    notice, this list of conditions and the following disclaimer.
1077943Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1177943Sdfr *    notice, this list of conditions and the following disclaimer in the
1277943Sdfr *    documentation and/or other materials provided with the distribution.
1377943Sdfr *
1477943Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1577943Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1677943Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1777943Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1877943Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1977943Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2077943Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2177943Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2277943Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2377943Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2477943Sdfr * SUCH DAMAGE.
2577943Sdfr *
2677943Sdfr *	$FreeBSD$
2777943Sdfr */
2877943Sdfr
2977943Sdfr	.text
3077943Sdfr
3177943Sdfr#include <machine/asm.h>
32154527Smarcel
3377943Sdfr#define EFI_SUCCESS		0
3477943Sdfr#define EFI_LOAD_ERROR		1
3577943Sdfr#define EFI_BUFFER_TOO_SMALL	5
36154527Smarcel
3777943Sdfr#define DT_NULL		0	/* Terminating entry. */
3877943Sdfr#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
3977943Sdfr#define DT_SYMTAB	6	/* Address of symbol table. */
4077943Sdfr#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
4177943Sdfr#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
4277943Sdfr#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
4377943Sdfr#define DT_SYMENT	11	/* Size of each symbol table entry. */
4477943Sdfr#define DT_JMPREL	23	/* Address of PLT relocations. */
4577943Sdfr
46154491Smarcel#define R_IA_64_NONE		0	/* None */
47154491Smarcel#define R_IA_64_DIR64LSB	0x27	/* word64 LSB	S + A */
48154491Smarcel#define R_IA_64_FPTR64LSB	0x47	/* word64 LSB	@fptr(S + A) */
49154491Smarcel#define R_IA_64_REL32LSB	0x6d	/* word32 LSB	BD + A */
50154491Smarcel#define R_IA_64_REL64LSB	0x6f	/* word64 LSB	BD + A */
51154491Smarcel#define	R_IA_64_IPLTLSB		0x81	/* function descriptor LSB speciaal */
5277943Sdfr
5377943SdfrENTRY(_start, 2)
5477943Sdfr	alloc	loc0=ar.pfs,2,3,3,0
5577943Sdfr	mov	loc1=rp
5677943Sdfr	movl	loc2=@gprel(ImageBase)
5777943Sdfr	;;
5877943Sdfr	add	loc2=gp,loc2
5977943Sdfr	;;
6077943Sdfr	mov	out0=loc2
6177943Sdfr	mov	out1=in1
6295190Smarcel	;;
6377943Sdfr	br.call.sptk.few rp=_reloc	// relocate image
6477943Sdfr
6577943Sdfr	cmp.ne	p6,p0=EFI_SUCCESS,r8	// did it work?
6677943Sdfr(p6)	br.cond.dpnt.few 9f
6777943Sdfr
6877943Sdfr	mov	out0=in0		// image_handle
6977943Sdfr	mov	out1=in1		// system_table
7077943Sdfr	br.call.sptk.few rp=efi_main
7177943Sdfr9:
7277943Sdfr	mov	ar.pfs=loc0
7377943Sdfr	mov	rp=loc1
7477943Sdfr	;;
7577943Sdfr	br.ret.sptk.few rp
7677943SdfrEND(_start)
7777943Sdfr
7877943Sdfr	// PLABEL for PE32+
7977943Sdfr	.section .plabel, "a"
8077943Sdfr	.align	16
81132437Smarcel	.global _start_plabel
82132437Smarcel_start_plabel:
83132437Smarcel	data16	@iplt(_start)
8477943Sdfr	.previous
8577943Sdfr
8677943Sdfr	// A PE32+ relocation entry for the plabel
8777943Sdfr	.section .reloc, "a"
88132437Smarcel	data4	_start_plabel
89132437Smarcel	data4	12
90132437Smarcel	data2	(10 << 12) + 0
91132437Smarcel	data2	(10 << 12) + 8
9277943Sdfr	.previous
9377943Sdfr
9495190Smarcel// in0:	image base
9595190Smarcel// in1:	system table
9695190Smarcel//
9795190Smarcel// XXX Assumes PLT relocations are of type Elf_Rela
9895190Smarcel//
9995190Smarcel// r2 = address of fptr_storage
10095190Smarcel// r3 = address of fptr_storage_end
10195190Smarcel// r4 = address of first free fptr
10295190Smarcel//
10395190Smarcel// r15 = r_offset
10495190Smarcel// r16 = r_info		-OR-	d_tag
10595190Smarcel// r17 = r_addend	-OR-	d_val (=d_ptr)
10695190Smarcel// r18 = address of .rela dynamic section
10795190Smarcel// r19 = size of .rela section
10895190Smarcel// r20 = size of .rela element (Elf_Rela)
10995190Smarcel// r21 = address of first PLT relocation
11095190Smarcel// r22 = size of PLT relocations
11195190Smarcel// r23 = relocation type
11295190Smarcel// r24 = address of symbol
113154491Smarcel// r28 = R_IA_64_IPLTLSB
11495190Smarcel// f8 = address of symbol table
11595190Smarcel// f9 = size of symtab element
11695190Smarcel
11777943SdfrSTATIC_ENTRY(_reloc, 2)
11895190Smarcel	alloc	loc0=ar.pfs,2,2,0,0
11995190Smarcel	;;
12077943Sdfr	mov	loc1=rp
12195190Smarcel	movl	r29=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
12277943Sdfr	;;
12395190Smarcel	add	r15=r29,gp
12495190Smarcel	movl	r29=@gprel(fptr_storage)
12595190Smarcel	;;
12695190Smarcel	add	r2=r29,gp
12795190Smarcel	movl	r29=@gprel(fptr_storage_end)
12895190Smarcel	;;
12995190Smarcel	add	r3=r29,gp
13095190Smarcel	mov	r4=r2
13185436Sdfr	mov	r19=0
13295190Smarcel	mov	r22=0
13395190Smarcel	mov	r20=24
134154491Smarcel	mov	r28=R_IA_64_IPLTLSB
13577943Sdfr	;;
13695190Smarcel1:
13795190Smarcel	ld8	r16=[r15],8		// read r15->d_tag
13877943Sdfr	;;
13977943Sdfr	ld8	r17=[r15],8		// and r15->d_val
14077943Sdfr	;;
14177943Sdfr	cmp.eq	p6,p0=DT_NULL,r16	// done?
14277943Sdfr(p6)	br.cond.dpnt.few 2f
14377943Sdfr	;;
14495190Smarcel	cmp.eq	p6,p0=DT_RELA,r16	// rela section?
14595190Smarcel	;;
14695190Smarcel(p6)	add	r18=r17,in0
14795190Smarcel	cmp.eq	p6,p0=DT_RELASZ,r16	// rela section size?
14895190Smarcel	;;
14995190Smarcel(p6)	mov	r19=r17
15095190Smarcel	cmp.eq	p6,p0=DT_RELAENT,r16	// rela entry size?
15195190Smarcel	;;
15295190Smarcel(p6)	mov	r20=r17
15395190Smarcel	cmp.eq	p6,p0=DT_JMPREL,r16	// PLT relocs?
15495190Smarcel	;;
15595190Smarcel(p6)	add	r21=r17,in0
15695190Smarcel	cmp.eq	p6,p0=DT_PLTRELSZ,r16	// PLT relocs size?
15795190Smarcel	;;
15895190Smarcel(p6)	mov	r22=r17
15995190Smarcel	cmp.eq	p6,p0=DT_SYMTAB,r16	// symbol table?
16095190Smarcel	;;
16195190Smarcel(p6)	add	r29=r17,in0
16295190Smarcel	;;
16395190Smarcel(p6)	setf.sig f8=r29
16495190Smarcel	cmp.eq	p6,p0=DT_SYMENT,r16	// symbol entry size?
16595190Smarcel	;;
16695190Smarcel(p6)	setf.sig f9=r17
16795190Smarcel	br.dptk	1b
16895190Smarcel
16995190Smarcel2:
17095190Smarcel	cmp.lt	p6,p0=0,r19
17195190Smarcel(p6)	br.cond.dptk	3f
17295190Smarcel	;;
17395190Smarcel	mov	r19=r22
17495190Smarcel	mov	r18=r21
17595190Smarcel	mov	r21=0
17695190Smarcel	mov	r22=0
17795190Smarcel	;;
17895190Smarcel	cmp.lt	p6,p0=0,r19
17995190Smarcel(p6)	br.cond.dptk	3f
18095190Smarcel	;;
18195190Smarcel	mov	r8=EFI_SUCCESS
18295190Smarcel	br.dptk	9f
18395190Smarcel3:
18495190Smarcel	ld8	r29=[r18],8		// read r_offset
18595190Smarcel	;;
18677943Sdfr	ld8	r16=[r18],8		// read r_info
18795190Smarcel	add	r15=r29,in0		// relocate r_offset
18877943Sdfr	;;
18977943Sdfr	ld8	r17=[r18],8		// read r_addend
19095190Smarcel	sub	r19=r19,r20		// update relasz
19177943Sdfr	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
19277943Sdfr	;;
193154491Smarcel	cmp.eq	p6,p0=R_IA_64_NONE,r23
19495190Smarcel(p6)	br.cond.dpnt.few 2b
19577943Sdfr	;;
196154491Smarcel	cmp.eq	p6,p0=R_IA_64_REL32LSB,r23
197132437Smarcel(p6)	br.cond.dptk.few 3f
198132437Smarcel	;;
199154491Smarcel	cmp.eq	p6,p0=R_IA_64_REL64LSB,r23
20077943Sdfr(p6)	br.cond.dptk.few 4f
20177943Sdfr	;;
20295190Smarcel	extr.u	r29=r16,32,32		// ELF64_R_SYM(r16)
20377943Sdfr	;;
20495190Smarcel	setf.sig f10=r29		// so we can multiply
20577943Sdfr	;;
20695190Smarcel	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
20777943Sdfr	;;
20895190Smarcel	getf.sig r29=f10
20977943Sdfr	;;
21095190Smarcel	add	r29=8,r29		// address of st_value
21185436Sdfr	;;
21295190Smarcel	ld8	r29=[r29]		// read symbol value
21395190Smarcel	;;
21495190Smarcel	add	r24=r29,in0		// relocate symbol value
21595190Smarcel	;;
216154491Smarcel	cmp.eq	p6,p0=R_IA_64_DIR64LSB,r23
21785436Sdfr(p6)	br.cond.dptk.few 5f
21885436Sdfr	;;
219154491Smarcel	cmp.eq	p6,p0=R_IA_64_FPTR64LSB,r23
22095190Smarcel(p6)	br.cond.dptk.few 6f
22177943Sdfr	;;
22295190Smarcel	cmp.ne	p6,p0=r28,r23		// IPLTLSB
22395190Smarcel(p6)	br.cond.dptk.few 2b
22477943Sdfr
22595190Smarcel	// IPLTLSB
22695190Smarcel	add	r29=r24,r17		// S + A
22777943Sdfr	;;
22895190Smarcel	st8	[r15]=r29,8		// fdesc:FP
22977943Sdfr	;;
23095190Smarcel	st8	[r15]=gp		// fdesc:GP
23195190Smarcel	br.cond.sptk.few 2b
23277943Sdfr
233132437Smarcel	// REL32LSB
234132437Smarcel3:
235132437Smarcel	add	r29=in0,r17
236132437Smarcel	;;
237132437Smarcel	st4	[r15]=r29
238132437Smarcel	br.cond.sptk.few 2b
239132437Smarcel
24095190Smarcel	// REL64LSB
24195190Smarcel4:
24295190Smarcel	add	r29=in0,r17		// BD + A
24377943Sdfr	;;
24495190Smarcel	st8	[r15]=r29		// word64
24595190Smarcel	br.cond.sptk.few 2b
24695190Smarcel
24795190Smarcel	// DIR64LSB
24895190Smarcel5:
24995190Smarcel	add	r29=r24,r17		// S + A
25077943Sdfr	;;
25195190Smarcel	st8	[r15]=r29		// word64
25295190Smarcel	br.cond.sptk.few 2b
25395190Smarcel
25495190Smarcel6:
25595190Smarcel	mov	r29=r2			// FPTR64LSB
25685436Sdfr	;;
25795190Smarcel7:
25895190Smarcel	cmp.geu	p6,p0=r29,r4		// end of fptrs?
25995190Smarcel(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
26095190Smarcel	ld8	r17=[r29]		// read function from fptr
26185436Sdfr	;;
26295190Smarcel	cmp.eq	p6,p0=r24,r17		// same function?
26385436Sdfr	;;
26495190Smarcel(p6)	st8	[r15]=r29		// reuse fptr
26595190Smarcel(p6)	br.cond.sptk.few 2b		// done
26695190Smarcel	add	r29=16,r29		// next fptr
26795190Smarcel	br.sptk.few 7b
26895190Smarcel8:
26977943Sdfr	mov	r8=EFI_BUFFER_TOO_SMALL	// failure return value
27095190Smarcel	cmp.geu	p6,p0=r4,r3		// space left?
27177943Sdfr(p6)	br.cond.dpnt.few 9f		// bail out
27295190Smarcel	st8	[r15]=r4		// install fptr
27377943Sdfr	;;
27495190Smarcel	st8	[r4]=r24,8		// write fptr address
27577943Sdfr	;;
27695190Smarcel	st8	[r4]=gp,8		// write fptr gp
27795190Smarcel	br.cond.sptk.few 2b
27877943Sdfr
27977943Sdfr9:
28077943Sdfr	mov	ar.pfs=loc0
28177943Sdfr	mov	rp=loc1
28277943Sdfr	;;
28377943Sdfr	br.ret.sptk.few rp
28477943SdfrEND(_reloc)
28577943Sdfr
28677943Sdfr	.data
28777943Sdfr	.align	16
288107720Smarcelfptr_storage:
28977943Sdfr	.space	1024*16			// XXX
290107720Smarcelfptr_storage_end:
291