start.S revision 95190
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: head/sys/boot/ia64/efi/start.S 95190 2002-04-21 08:49:47Z marcel $
2777943Sdfr */
2877943Sdfr
2977943Sdfr	.text
3077943Sdfr
3177943Sdfr#include <machine/asm.h>
3277943Sdfr
3377943Sdfr#define EFI_SUCCESS		0
3477943Sdfr#define EFI_LOAD_ERROR		1
3577943Sdfr#define EFI_BUFFER_TOO_SMALL	5
3677943Sdfr
3777943Sdfr#define DT_NULL		0	/* Terminating entry. */
3877943Sdfr#define DT_NEEDED	1	/* String table offset of a needed shared
3977943Sdfr				   library. */
4077943Sdfr#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
4177943Sdfr#define DT_PLTGOT	3	/* Processor-dependent address. */
4277943Sdfr#define DT_HASH		4	/* Address of symbol hash table. */
4377943Sdfr#define DT_STRTAB	5	/* Address of string table. */
4477943Sdfr#define DT_SYMTAB	6	/* Address of symbol table. */
4577943Sdfr#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
4677943Sdfr#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
4777943Sdfr#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
4877943Sdfr#define DT_STRSZ	10	/* Size of string table. */
4977943Sdfr#define DT_SYMENT	11	/* Size of each symbol table entry. */
5077943Sdfr#define DT_INIT		12	/* Address of initialization function. */
5177943Sdfr#define DT_FINI		13	/* Address of finalization function. */
5277943Sdfr#define DT_SONAME	14	/* String table offset of shared object
5377943Sdfr				   name. */
5477943Sdfr#define DT_RPATH	15	/* String table offset of library path. */
5577943Sdfr#define DT_SYMBOLIC	16	/* Indicates "symbolic" linking. */
5677943Sdfr#define DT_REL		17	/* Address of ElfNN_Rel relocations. */
5777943Sdfr#define DT_RELSZ	18	/* Total size of ElfNN_Rel relocations. */
5877943Sdfr#define DT_RELENT	19	/* Size of each ElfNN_Rel relocation. */
5977943Sdfr#define DT_PLTREL	20	/* Type of relocation used for PLT. */
6077943Sdfr#define DT_DEBUG	21	/* Reserved (not used). */
6177943Sdfr#define DT_TEXTREL	22	/* Indicates there may be relocations in
6277943Sdfr				   non-writable segments. */
6377943Sdfr#define DT_JMPREL	23	/* Address of PLT relocations. */
6477943Sdfr
6577943Sdfr#define DT_COUNT	24	/* Number of defined d_tag values. */
6677943Sdfr
6777943Sdfr#define R_IA64_NONE		0	/* None */
6877943Sdfr#define R_IA64_DIR64MSB		0x26	/* word64 MSB	S + A */
6977943Sdfr#define R_IA64_DIR64LSB		0x27	/* word64 LSB	S + A */
7077943Sdfr#define R_IA64_FPTR64MSB	0x46	/* word64 MSB	@fptr(S + A) */
7177943Sdfr#define R_IA64_FPTR64LSB	0x47	/* word64 LSB	@fptr(S + A) */
7277943Sdfr#define R_IA64_REL64MSB		0x6e	/* word64 MSB	BD + A */
7377943Sdfr#define R_IA64_REL64LSB		0x6f	/* word64 LSB	BD + A */
7485436Sdfr#define	R_IA64_IPLTLSB		0x81	/* function descriptor LSB speciaal */
7577943Sdfr
7677943SdfrENTRY(_start, 2)
7777943Sdfr	alloc	loc0=ar.pfs,2,3,3,0
7877943Sdfr	mov	loc1=rp
7977943Sdfr	movl	loc2=@gprel(ImageBase)
8077943Sdfr	;;
8177943Sdfr	add	loc2=gp,loc2
8277943Sdfr	;;
8377943Sdfr	mov	out0=loc2
8477943Sdfr	mov	out1=in1
8595190Smarcel	;;
8677943Sdfr	br.call.sptk.few rp=_reloc	// relocate image
8777943Sdfr
8877943Sdfr	cmp.ne	p6,p0=EFI_SUCCESS,r8	// did it work?
8977943Sdfr(p6)	br.cond.dpnt.few 9f
9077943Sdfr
9177943Sdfr	mov	out0=in0		// image_handle
9277943Sdfr	mov	out1=in1		// system_table
9377943Sdfr	br.call.sptk.few rp=efi_main
9477943Sdfr9:
9577943Sdfr	mov	ar.pfs=loc0
9677943Sdfr	mov	rp=loc1
9777943Sdfr	;;
9877943Sdfr	br.ret.sptk.few rp
9977943SdfrEND(_start)
10077943Sdfr
10177943Sdfr	// PLABEL for PE32+
10277943Sdfr	.global _start_plabel
10377943Sdfr	.section .plabel, "a"
10477943Sdfr	.align	16
10577943Sdfr_start_plabel:
10677943Sdfr	.quad	_start
10777943Sdfr	.quad	__gp
10877943Sdfr	.previous
10977943Sdfr
11077943Sdfr	// A PE32+ relocation entry for the plabel
11177943Sdfr
11277943Sdfr	.section .reloc, "a"
11377943Sdfr	.long	_start_plabel
11477943Sdfr	.long	12
11577943Sdfr	.short	(10 << 12) + 0
11677943Sdfr	.short	(10 << 12) + 8
11777943Sdfr	.previous
11877943Sdfr
11995190Smarcel// in0:	image base
12095190Smarcel// in1:	system table
12195190Smarcel//
12295190Smarcel// XXX Assumes PLT relocations are of type Elf_Rela
12395190Smarcel//
12495190Smarcel// r2 = address of fptr_storage
12595190Smarcel// r3 = address of fptr_storage_end
12695190Smarcel// r4 = address of first free fptr
12795190Smarcel//
12895190Smarcel// r15 = r_offset
12995190Smarcel// r16 = r_info		-OR-	d_tag
13095190Smarcel// r17 = r_addend	-OR-	d_val (=d_ptr)
13195190Smarcel// r18 = address of .rela dynamic section
13295190Smarcel// r19 = size of .rela section
13395190Smarcel// r20 = size of .rela element (Elf_Rela)
13495190Smarcel// r21 = address of first PLT relocation
13595190Smarcel// r22 = size of PLT relocations
13695190Smarcel// r23 = relocation type
13795190Smarcel// r24 = address of symbol
13895190Smarcel// r28 = R_IA64_IPLTLSB
13995190Smarcel// f8 = address of symbol table
14095190Smarcel// f9 = size of symtab element
14195190Smarcel
14277943SdfrSTATIC_ENTRY(_reloc, 2)
14395190Smarcel	alloc	loc0=ar.pfs,2,2,0,0
14495190Smarcel	;;
14577943Sdfr	mov	loc1=rp
14695190Smarcel	movl	r29=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
14777943Sdfr	;;
14895190Smarcel	add	r15=r29,gp
14995190Smarcel	movl	r29=@gprel(fptr_storage)
15095190Smarcel	;;
15195190Smarcel	add	r2=r29,gp
15295190Smarcel	movl	r29=@gprel(fptr_storage_end)
15395190Smarcel	;;
15495190Smarcel	add	r3=r29,gp
15595190Smarcel	mov	r4=r2
15685436Sdfr	mov	r19=0
15795190Smarcel	mov	r22=0
15895190Smarcel	mov	r20=24
15995190Smarcel	mov	r28=R_IA64_IPLTLSB
16077943Sdfr	;;
16195190Smarcel1:
16295190Smarcel	ld8	r16=[r15],8		// read r15->d_tag
16377943Sdfr	;;
16477943Sdfr	ld8	r17=[r15],8		// and r15->d_val
16577943Sdfr	;;
16677943Sdfr	cmp.eq	p6,p0=DT_NULL,r16	// done?
16777943Sdfr(p6)	br.cond.dpnt.few 2f
16877943Sdfr	;;
16995190Smarcel	cmp.eq	p6,p0=DT_RELA,r16	// rela section?
17095190Smarcel	;;
17195190Smarcel(p6)	add	r18=r17,in0
17295190Smarcel	cmp.eq	p6,p0=DT_RELASZ,r16	// rela section size?
17395190Smarcel	;;
17495190Smarcel(p6)	mov	r19=r17
17595190Smarcel	cmp.eq	p6,p0=DT_RELAENT,r16	// rela entry size?
17695190Smarcel	;;
17795190Smarcel(p6)	mov	r20=r17
17895190Smarcel	cmp.eq	p6,p0=DT_JMPREL,r16	// PLT relocs?
17995190Smarcel	;;
18095190Smarcel(p6)	add	r21=r17,in0
18195190Smarcel	cmp.eq	p6,p0=DT_PLTRELSZ,r16	// PLT relocs size?
18295190Smarcel	;;
18395190Smarcel(p6)	mov	r22=r17
18495190Smarcel	cmp.eq	p6,p0=DT_SYMTAB,r16	// symbol table?
18595190Smarcel	;;
18695190Smarcel(p6)	add	r29=r17,in0
18795190Smarcel	;;
18895190Smarcel(p6)	setf.sig f8=r29
18995190Smarcel	cmp.eq	p6,p0=DT_SYMENT,r16	// symbol entry size?
19095190Smarcel	;;
19195190Smarcel(p6)	setf.sig f9=r17
19295190Smarcel	br.dptk	1b
19395190Smarcel
19495190Smarcel2:
19595190Smarcel	cmp.lt	p6,p0=0,r19
19695190Smarcel(p6)	br.cond.dptk	3f
19795190Smarcel	;;
19895190Smarcel	mov	r19=r22
19995190Smarcel	mov	r18=r21
20095190Smarcel	mov	r21=0
20195190Smarcel	mov	r22=0
20295190Smarcel	;;
20395190Smarcel	cmp.lt	p6,p0=0,r19
20495190Smarcel(p6)	br.cond.dptk	3f
20595190Smarcel	;;
20695190Smarcel	mov	r8=EFI_SUCCESS
20795190Smarcel	br.dptk	9f
20895190Smarcel3:
20995190Smarcel	ld8	r29=[r18],8		// read r_offset
21095190Smarcel	;;
21177943Sdfr	ld8	r16=[r18],8		// read r_info
21295190Smarcel	add	r15=r29,in0		// relocate r_offset
21377943Sdfr	;;
21477943Sdfr	ld8	r17=[r18],8		// read r_addend
21595190Smarcel	sub	r19=r19,r20		// update relasz
21677943Sdfr	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
21777943Sdfr	;;
21877943Sdfr	cmp.eq	p6,p0=R_IA64_NONE,r23
21995190Smarcel(p6)	br.cond.dpnt.few 2b
22077943Sdfr	;;
22195190Smarcel	cmp.eq	p6,p0=R_IA64_REL64LSB,r23
22277943Sdfr(p6)	br.cond.dptk.few 4f
22377943Sdfr	;;
22495190Smarcel	extr.u	r29=r16,32,32		// ELF64_R_SYM(r16)
22577943Sdfr	;;
22695190Smarcel	setf.sig f10=r29		// so we can multiply
22777943Sdfr	;;
22895190Smarcel	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
22977943Sdfr	;;
23095190Smarcel	getf.sig r29=f10
23177943Sdfr	;;
23295190Smarcel	add	r29=8,r29		// address of st_value
23385436Sdfr	;;
23495190Smarcel	ld8	r29=[r29]		// read symbol value
23595190Smarcel	;;
23695190Smarcel	add	r24=r29,in0		// relocate symbol value
23795190Smarcel	;;
23895190Smarcel	cmp.eq	p6,p0=R_IA64_DIR64LSB,r23
23985436Sdfr(p6)	br.cond.dptk.few 5f
24085436Sdfr	;;
24195190Smarcel	cmp.eq	p6,p0=R_IA64_FPTR64LSB,r23
24295190Smarcel(p6)	br.cond.dptk.few 6f
24377943Sdfr	;;
24495190Smarcel	cmp.ne	p6,p0=r28,r23		// IPLTLSB
24595190Smarcel(p6)	br.cond.dptk.few 2b
24677943Sdfr
24795190Smarcel	// IPLTLSB
24895190Smarcel	add	r29=r24,r17		// S + A
24977943Sdfr	;;
25095190Smarcel	st8	[r15]=r29,8		// fdesc:FP
25177943Sdfr	;;
25295190Smarcel	st8	[r15]=gp		// fdesc:GP
25395190Smarcel	br.cond.sptk.few 2b
25477943Sdfr
25595190Smarcel	// REL64LSB
25695190Smarcel4:
25795190Smarcel	add	r29=in0,r17		// BD + A
25877943Sdfr	;;
25995190Smarcel	st8	[r15]=r29		// word64
26095190Smarcel	br.cond.sptk.few 2b
26195190Smarcel
26295190Smarcel	// DIR64LSB
26395190Smarcel5:
26495190Smarcel	add	r29=r24,r17		// S + A
26577943Sdfr	;;
26695190Smarcel	st8	[r15]=r29		// word64
26795190Smarcel	br.cond.sptk.few 2b
26895190Smarcel
26995190Smarcel6:
27095190Smarcel	mov	r29=r2			// FPTR64LSB
27185436Sdfr	;;
27295190Smarcel7:
27395190Smarcel	cmp.geu	p6,p0=r29,r4		// end of fptrs?
27495190Smarcel(p6)	br.cond.dpnt.few 8f		// can't find existing fptr
27595190Smarcel	ld8	r17=[r29]		// read function from fptr
27685436Sdfr	;;
27795190Smarcel	cmp.eq	p6,p0=r24,r17		// same function?
27885436Sdfr	;;
27995190Smarcel(p6)	st8	[r15]=r29		// reuse fptr
28095190Smarcel(p6)	br.cond.sptk.few 2b		// done
28195190Smarcel	add	r29=16,r29		// next fptr
28295190Smarcel	br.sptk.few 7b
28395190Smarcel8:
28477943Sdfr	mov	r8=EFI_BUFFER_TOO_SMALL	// failure return value
28595190Smarcel	cmp.geu	p6,p0=r4,r3		// space left?
28677943Sdfr(p6)	br.cond.dpnt.few 9f		// bail out
28795190Smarcel	st8	[r15]=r4		// install fptr
28877943Sdfr	;;
28995190Smarcel	st8	[r4]=r24,8		// write fptr address
29077943Sdfr	;;
29195190Smarcel	st8	[r4]=gp,8		// write fptr gp
29295190Smarcel	br.cond.sptk.few 2b
29377943Sdfr
29477943Sdfr9:
29577943Sdfr	mov	ar.pfs=loc0
29677943Sdfr	mov	rp=loc1
29777943Sdfr	;;
29877943Sdfr	br.ret.sptk.few rp
29977943SdfrEND(_reloc)
30077943Sdfr
30177943Sdfr	// in0:	system table
30277943Sdfr	// in1:	character
30377943SdfrENTRY(_putchar, 2)
30477943Sdfr	alloc	loc0=ar.pfs,2,3,2,0
30577943Sdfr	mov	loc1=rp
30677943Sdfr	mov	loc2=gp
30777943Sdfr	add	sp=-32,sp
30877943Sdfr	;;
30977943Sdfr	add	r14=64,in0		// r14 = &in1->ConOut
31077943Sdfr	;;
31177943Sdfr	ld8	r14=[r14]		// r14 = in1->ConOut
31277943Sdfr	;;
31377943Sdfr	add	r15=8,r14		// r15 = &r14->OutputString
31477943Sdfr	mov	out0=r14
31577943Sdfr	mov	out1=sp
31677943Sdfr	mov	r16=sp
31777943Sdfr	;;
31877943Sdfr	ld8	r15=[r15]		// r15 = r14->OutputString
31977943Sdfr	st2	[r16]=in1,2		// write character
32077943Sdfr	;;
32177943Sdfr	st2	[r16]=r0		// terminate
32277943Sdfr	ld8	r17=[r15],8		// function address
32377943Sdfr	;;
32477943Sdfr	ld8	gp=[r15]		// function gp
32577943Sdfr	mov	b6=r17			// transfer to branch register
32677943Sdfr	;;
32777943Sdfr	br.call.sptk.few rp=b6		// call function
32877943Sdfr	;;
32977943Sdfr	mov	gp=loc2			// restore gp
33077943Sdfr	mov	ar.pfs=loc0
33177943Sdfr	mov	rp=loc1
33277943Sdfr	add	sp=32,sp
33377943Sdfr	;;
33477943Sdfr	br.ret.sptk.few rp
33577943Sdfr
33677943SdfrEND(_putchar)
33777943Sdfr
33877943Sdfr	// in0:	system table
33977943Sdfr	// in1:	string
34077943SdfrENTRY(_puts, 2)
34177943Sdfr	alloc	loc0=ar.pfs,3,2,2,0
34277943Sdfr	mov	loc1=rp
34377943Sdfr	;;
34477943Sdfr	mov	out0=in0
34577943Sdfr	;;
34677943Sdfr1:	ld1	out1=[in1],1
34795190Smarcel	;;
34877943Sdfr	cmp.eq	p6,p0=r0,out1
34977943Sdfr(p6)	br.cond.dpnt.few 9f
35077943Sdfr	;;
35177943Sdfr	br.call.sptk.few rp=_putchar
35277943Sdfr	;;
35377943Sdfr	br.cond.sptk.few 1b
35477943Sdfr9:
35577943Sdfr	mov	ar.pfs=loc0
35677943Sdfr	mov	rp=loc1
35777943Sdfr	;;
35877943Sdfr	br.ret.sptk.few rp
35977943SdfrEND(_puts)
36077943Sdfr
36177943Sdfr	// in0:	system table
36277943Sdfr	// in1:	number
36377943SdfrENTRY(_puthex, 2)
36477943Sdfr	alloc	loc0=ar.pfs,2,3,2,0
36577943Sdfr	mov	loc1=rp
36677943Sdfr	mov	loc2=ar.lc
36777943Sdfr	;;
36877943Sdfr	mov	out0=in0
36977943Sdfr	mov	ar.lc=15
37077943Sdfr	;;
37177943Sdfr1:	extr.u	out1=in1,60,4
37277943Sdfr	;;
37377943Sdfr	cmp.leu	p6,p7=10,out1
37477943Sdfr	;;
37577943Sdfr(p6)	add	out1='a'-10,out1
37677943Sdfr(p7)	add	out1='0',out1
37777943Sdfr	dep.z	in1=in1,4,60
37877943Sdfr	;;
37977943Sdfr	br.call.sptk.few rp=_putchar
38077943Sdfr	;;
38177943Sdfr	br.cloop.sptk.few 1b
38277943Sdfr	;;
38377943Sdfr	mov	out1='\r'
38477943Sdfr	;;
38577943Sdfr	br.call.sptk.few rp=_putchar
38677943Sdfr	;;
38777943Sdfr	mov	out1='\n'
38877943Sdfr	;;
38977943Sdfr	br.call.sptk.few rp=_putchar
39077943Sdfr	;;
39177943Sdfr9:
39277943Sdfr	mov	ar.pfs=loc0
39377943Sdfr	mov	rp=loc1
39477943Sdfr	mov	ar.lc=loc2
39577943Sdfr	;;
39677943Sdfr	br.ret.sptk.few rp
39777943SdfrEND(_puthex)
39877943Sdfr
39977943Sdfr	.data
40077943Sdfr	.align	16
40177943Sdfr
40277943Sdfrfptr_storage:
40377943Sdfr	.space	1024*16			// XXX
40477943Sdfrfptr_storage_end:
405