start.S revision 85436
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 85436 2001-10-24 20:14:49Z dfr $
2777943Sdfr */
2877943Sdfr
2977943Sdfr	.text
3077943Sdfr
3177943Sdfr#include <sys/cdefs.h>
3277943Sdfr#include <machine/asm.h>
3377943Sdfr
3477943Sdfr#define EFI_SUCCESS		0
3577943Sdfr#define EFI_LOAD_ERROR		1
3677943Sdfr#define EFI_BUFFER_TOO_SMALL	5
3777943Sdfr
3877943Sdfr#define DT_NULL		0	/* Terminating entry. */
3977943Sdfr#define DT_NEEDED	1	/* String table offset of a needed shared
4077943Sdfr				   library. */
4177943Sdfr#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
4277943Sdfr#define DT_PLTGOT	3	/* Processor-dependent address. */
4377943Sdfr#define DT_HASH		4	/* Address of symbol hash table. */
4477943Sdfr#define DT_STRTAB	5	/* Address of string table. */
4577943Sdfr#define DT_SYMTAB	6	/* Address of symbol table. */
4677943Sdfr#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
4777943Sdfr#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
4877943Sdfr#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
4977943Sdfr#define DT_STRSZ	10	/* Size of string table. */
5077943Sdfr#define DT_SYMENT	11	/* Size of each symbol table entry. */
5177943Sdfr#define DT_INIT		12	/* Address of initialization function. */
5277943Sdfr#define DT_FINI		13	/* Address of finalization function. */
5377943Sdfr#define DT_SONAME	14	/* String table offset of shared object
5477943Sdfr				   name. */
5577943Sdfr#define DT_RPATH	15	/* String table offset of library path. */
5677943Sdfr#define DT_SYMBOLIC	16	/* Indicates "symbolic" linking. */
5777943Sdfr#define DT_REL		17	/* Address of ElfNN_Rel relocations. */
5877943Sdfr#define DT_RELSZ	18	/* Total size of ElfNN_Rel relocations. */
5977943Sdfr#define DT_RELENT	19	/* Size of each ElfNN_Rel relocation. */
6077943Sdfr#define DT_PLTREL	20	/* Type of relocation used for PLT. */
6177943Sdfr#define DT_DEBUG	21	/* Reserved (not used). */
6277943Sdfr#define DT_TEXTREL	22	/* Indicates there may be relocations in
6377943Sdfr				   non-writable segments. */
6477943Sdfr#define DT_JMPREL	23	/* Address of PLT relocations. */
6577943Sdfr
6677943Sdfr#define DT_COUNT	24	/* Number of defined d_tag values. */
6777943Sdfr
6877943Sdfr#define R_IA64_NONE		0	/* None */
6977943Sdfr#define R_IA64_DIR64MSB		0x26	/* word64 MSB	S + A */
7077943Sdfr#define R_IA64_DIR64LSB		0x27	/* word64 LSB	S + A */
7177943Sdfr#define R_IA64_FPTR64MSB	0x46	/* word64 MSB	@fptr(S + A) */
7277943Sdfr#define R_IA64_FPTR64LSB	0x47	/* word64 LSB	@fptr(S + A) */
7377943Sdfr#define R_IA64_REL64MSB		0x6e	/* word64 MSB	BD + A */
7477943Sdfr#define R_IA64_REL64LSB		0x6f	/* word64 LSB	BD + A */
7585436Sdfr#define	R_IA64_IPLTLSB		0x81	/* function descriptor LSB speciaal */
7677943Sdfr
7777943SdfrENTRY(_start, 2)
7877943Sdfr	alloc	loc0=ar.pfs,2,3,3,0
7977943Sdfr	mov	loc1=rp
8077943Sdfr	movl	loc2=@gprel(ImageBase)
8177943Sdfr	;;
8277943Sdfr	add	loc2=gp,loc2
8377943Sdfr	;;
8477943Sdfr	mov	out0=loc2
8577943Sdfr	mov	out1=in1
8677943Sdfr	;;
8777943Sdfr	br.call.sptk.few rp=_reloc	// relocate image
8877943Sdfr
8977943Sdfr	cmp.ne	p6,p0=EFI_SUCCESS,r8	// did it work?
9077943Sdfr(p6)	br.cond.dpnt.few 9f
9177943Sdfr
9277943Sdfr	mov	out0=in0		// image_handle
9377943Sdfr	mov	out1=in1		// system_table
9477943Sdfr	br.call.sptk.few rp=efi_main
9577943Sdfr9:
9677943Sdfr	mov	ar.pfs=loc0
9777943Sdfr	mov	rp=loc1
9877943Sdfr	;;
9977943Sdfr	br.ret.sptk.few rp
10077943SdfrEND(_start)
10177943Sdfr
10277943Sdfr	// PLABEL for PE32+
10377943Sdfr	.global _start_plabel
10477943Sdfr	.section .plabel, "a"
10577943Sdfr	.align	16
10677943Sdfr_start_plabel:
10777943Sdfr	.quad	_start
10877943Sdfr	.quad	__gp
10977943Sdfr	.previous
11077943Sdfr
11177943Sdfr	// A PE32+ relocation entry for the plabel
11277943Sdfr
11377943Sdfr	.section .reloc, "a"
11477943Sdfr	.long	_start_plabel
11577943Sdfr	.long	12
11677943Sdfr	.short	(10 << 12) + 0
11777943Sdfr	.short	(10 << 12) + 8
11877943Sdfr	.previous
11977943Sdfr
12077943Sdfr	// in0:	image base
12177943Sdfr	// in1:	system table
12285436Sdfr	//
12385436Sdfr	// This assumes that the pltrel section immediately follows
12485436Sdfr	// the rela section.
12577943SdfrSTATIC_ENTRY(_reloc, 2)
12677943Sdfr	alloc	loc0=ar.pfs,2,2,2,0
12777943Sdfr	mov	loc1=rp
12877943Sdfr	;;
12977943Sdfr	movl	r15=@gprel(_DYNAMIC)	// find _DYNAMIC etc.
13077943Sdfr	movl	r2=@gprel(fptr_storage)
13177943Sdfr	movl	r3=@gprel(fptr_storage_end)
13277943Sdfr	;;
13377943Sdfr	add	r15=r15,gp		// relocate _DYNAMIC etc.
13477943Sdfr	add	r2=r2,gp
13577943Sdfr	add	r3=r3,gp
13685436Sdfr	mov	r19=0
13777943Sdfr	;;
13877943Sdfr1:	ld8	r16=[r15],8		// read r15->d_tag
13977943Sdfr	;;
14077943Sdfr	ld8	r17=[r15],8		// and r15->d_val
14177943Sdfr	;;
14277943Sdfr	cmp.eq	p6,p0=DT_NULL,r16	// done?
14377943Sdfr(p6)	br.cond.dpnt.few 2f
14477943Sdfr	;;
14577943Sdfr	cmp.eq	p6,p0=DT_RELA,r16
14677943Sdfr	;;
14777943Sdfr(p6)	add	r18=r17,in0		// found rela section
14877943Sdfr	;;
14977943Sdfr	cmp.eq	p6,p0=DT_RELASZ,r16
15077943Sdfr	;;
15185436Sdfr(p6)	add	r19=r17,r19		// found rela size
15277943Sdfr	;;
15385436Sdfr	cmp.eq	p6,p0=DT_PLTRELSZ,r16
15485436Sdfr	;;
15585436Sdfr(p6)	add	r19=r17,r19		// found pltrel size
15685436Sdfr	;;
15777943Sdfr	cmp.eq	p6,p0=DT_SYMTAB,r16
15877943Sdfr	;;
15977943Sdfr(p6)	add	r20=r17,in0		// found symbol table
16077943Sdfr	;;
16177943Sdfr(p6)	setf.sig f8=r20
16277943Sdfr	;;
16377943Sdfr	cmp.eq	p6,p0=DT_SYMENT,r16
16477943Sdfr	;;
16577943Sdfr(p6)	setf.sig f9=r17			// found symbol entry size
16677943Sdfr	;;
16777943Sdfr	cmp.eq	p6,p0=DT_RELAENT,r16
16877943Sdfr	;;
16977943Sdfr(p6)	mov	r22=r17			// found rela entry size
17077943Sdfr	;;
17177943Sdfr	br.sptk.few 1b
17277943Sdfr
17377943Sdfr2:
17477943Sdfr	ld8	r15=[r18],8		// read r_offset
17577943Sdfr	;;
17677943Sdfr	ld8	r16=[r18],8		// read r_info
17777943Sdfr	add	r15=r15,in0		// relocate r_offset
17877943Sdfr	;;
17977943Sdfr	ld8	r17=[r18],8		// read r_addend
18077943Sdfr	sub	r19=r19,r22		// update relasz
18177943Sdfr
18277943Sdfr	extr.u	r23=r16,0,32		// ELF64_R_TYPE(r16)
18377943Sdfr	;;
18477943Sdfr	cmp.eq	p6,p0=R_IA64_NONE,r23
18577943Sdfr(p6)	br.cond.dpnt.few 3f
18677943Sdfr	;;
18777943Sdfr	cmp.eq	p6,p0=R_IA64_DIR64LSB,r23
18877943Sdfr	;;
18977943Sdfr(p6)	br.cond.dptk.few 4f
19077943Sdfr	;;
19177943Sdfr	cmp.eq	p6,p0=R_IA64_FPTR64LSB,r23
19277943Sdfr	;;
19377943Sdfr(p6)	br.cond.dptk.few 5f
19477943Sdfr	;;
19577943Sdfr	cmp.eq	p6,p0=R_IA64_REL64LSB,r23
19677943Sdfr	;;
19777943Sdfr(p6)	br.cond.dptk.few 4f
19877943Sdfr	;;
19985436Sdfr	mov	r24=R_IA64_IPLTLSB
20085436Sdfr	;;
20185436Sdfr	cmp.eq	p6,p0=r24,r23
20285436Sdfr	;;
20385436Sdfr(p6)	br.cond.dptk.few 5f
20485436Sdfr	;;
20577943Sdfr
20677943Sdfr3:	cmp.ltu	p6,p0=0,r19		// more?
20777943Sdfr(p6)	br.cond.dptk.few 2b		// loop
20877943Sdfr
20977943Sdfr	mov	r8=EFI_SUCCESS		// success return value
21077943Sdfr	;;
21177943Sdfr	br.cond.sptk.few 9f		// done
21277943Sdfr
21385436Sdfr4:					// DIR64LSB or REL64LSB
21477943Sdfr	ld8	r16=[r15]		// read value
21577943Sdfr	;;
21677943Sdfr	add	r16=r16,in0		// relocate it
21777943Sdfr	;;
21877943Sdfr	st8	[r15]=r16		// and store it back
21977943Sdfr	br.cond.sptk.few 3b
22077943Sdfr
22185436Sdfr5:					// FPTR64LSB or IPLTLSB
22285436Sdfr	extr.u	r24=r16,32,32		// ELF64_R_SYM(r16)
22377943Sdfr	;;
22485436Sdfr	setf.sig f10=r24		// so we can multiply
22577943Sdfr	;;
22677943Sdfr	xma.lu	f10=f10,f9,f8		// f10=symtab + r_sym*syment
22777943Sdfr	;;
22877943Sdfr	getf.sig r16=f10
22985436Sdfr	;;
23085436Sdfr	mov	r24=R_IA64_IPLTLSB
23185436Sdfr	;;
23285436Sdfr	cmp.ne	p6,p0=r24,r23		// IPLTLSB doesn't need an @fptr
23385436Sdfr(p6)	br.cond.sptk.few 6f
23485436Sdfr	;;
23585436Sdfr	add	r16=8,r16		// address of st_value
23685436Sdfr	;;
23785436Sdfr	ld8	r16=[r16]		// read symbol value
23885436Sdfr	;;
23985436Sdfr	add	r16=r16,in0		// relocate symbol value
24085436Sdfr	;;
24185436Sdfr	st8	[r15]=r16,8		// update plt target
24285436Sdfr	;;
24385436Sdfr	st8	[r15]=gp		// and gp
24485436Sdfr	br.cond.sptk.few 3b
24585436Sdfr	;;
24685436Sdfr6:
24777943Sdfr	mov	r8=EFI_BUFFER_TOO_SMALL	// failure return value
24877943Sdfr	;;
24977943Sdfr	cmp.geu	p6,p0=r2,r3		// space left?
25077943Sdfr(p6)	br.cond.dpnt.few 9f		// bail out
25177943Sdfr
25277943Sdfr	st8	[r15]=r2		// install fptr
25377943Sdfr	add	r16=8,r16		// address of st_value
25477943Sdfr	;;
25577943Sdfr	ld8	r16=[r16]		// read symbol value
25677943Sdfr	;;
25777943Sdfr	add	r16=r16,in0		// relocate symbol value
25877943Sdfr	;;
25977943Sdfr	st8	[r2]=r16,8		// write fptr address
26077943Sdfr	;;
26177943Sdfr	st8	[r2]=gp,8		// write fptr gp
26277943Sdfr	br.cond.sptk.few 3b
26377943Sdfr
26477943Sdfr9:
26577943Sdfr	mov	ar.pfs=loc0
26677943Sdfr	mov	rp=loc1
26777943Sdfr	;;
26877943Sdfr	br.ret.sptk.few rp
26977943Sdfr
27077943SdfrEND(_reloc)
27177943Sdfr
27277943Sdfr	// in0:	system table
27377943Sdfr	// in1:	character
27477943SdfrENTRY(_putchar, 2)
27577943Sdfr	alloc	loc0=ar.pfs,2,3,2,0
27677943Sdfr	mov	loc1=rp
27777943Sdfr	mov	loc2=gp
27877943Sdfr	add	sp=-32,sp
27977943Sdfr	;;
28077943Sdfr	add	r14=64,in0		// r14 = &in1->ConOut
28177943Sdfr	;;
28277943Sdfr	ld8	r14=[r14]		// r14 = in1->ConOut
28377943Sdfr	;;
28477943Sdfr	add	r15=8,r14		// r15 = &r14->OutputString
28577943Sdfr	mov	out0=r14
28677943Sdfr	mov	out1=sp
28777943Sdfr	mov	r16=sp
28877943Sdfr	;;
28977943Sdfr	ld8	r15=[r15]		// r15 = r14->OutputString
29077943Sdfr	st2	[r16]=in1,2		// write character
29177943Sdfr	;;
29277943Sdfr	st2	[r16]=r0		// terminate
29377943Sdfr	ld8	r17=[r15],8		// function address
29477943Sdfr	;;
29577943Sdfr	ld8	gp=[r15]		// function gp
29677943Sdfr	mov	b6=r17			// transfer to branch register
29777943Sdfr	;;
29877943Sdfr	br.call.sptk.few rp=b6		// call function
29977943Sdfr	;;
30077943Sdfr	mov	gp=loc2			// restore gp
30177943Sdfr	mov	ar.pfs=loc0
30277943Sdfr	mov	rp=loc1
30377943Sdfr	add	sp=32,sp
30477943Sdfr	;;
30577943Sdfr	br.ret.sptk.few rp
30677943Sdfr
30777943SdfrEND(_putchar)
30877943Sdfr
30977943Sdfr	// in0:	system table
31077943Sdfr	// in1:	string
31177943SdfrENTRY(_puts, 2)
31277943Sdfr	alloc	loc0=ar.pfs,3,2,2,0
31377943Sdfr	mov	loc1=rp
31477943Sdfr	;;
31577943Sdfr	mov	out0=in0
31677943Sdfr	;;
31777943Sdfr1:	ld1	out1=[in1],1
31877943Sdfr	;;
31977943Sdfr	cmp.eq	p6,p0=r0,out1
32077943Sdfr(p6)	br.cond.dpnt.few 9f
32177943Sdfr	;;
32277943Sdfr	br.call.sptk.few rp=_putchar
32377943Sdfr	;;
32477943Sdfr	br.cond.sptk.few 1b
32577943Sdfr9:
32677943Sdfr	mov	ar.pfs=loc0
32777943Sdfr	mov	rp=loc1
32877943Sdfr	;;
32977943Sdfr	br.ret.sptk.few rp
33077943SdfrEND(_puts)
33177943Sdfr
33277943Sdfr	// in0:	system table
33377943Sdfr	// in1:	number
33477943SdfrENTRY(_puthex, 2)
33577943Sdfr	alloc	loc0=ar.pfs,2,3,2,0
33677943Sdfr	mov	loc1=rp
33777943Sdfr	mov	loc2=ar.lc
33877943Sdfr	;;
33977943Sdfr	mov	out0=in0
34077943Sdfr	mov	ar.lc=15
34177943Sdfr	;;
34277943Sdfr1:	extr.u	out1=in1,60,4
34377943Sdfr	;;
34477943Sdfr	cmp.leu	p6,p7=10,out1
34577943Sdfr	;;
34677943Sdfr(p6)	add	out1='a'-10,out1
34777943Sdfr(p7)	add	out1='0',out1
34877943Sdfr	dep.z	in1=in1,4,60
34977943Sdfr	;;
35077943Sdfr	br.call.sptk.few rp=_putchar
35177943Sdfr	;;
35277943Sdfr	br.cloop.sptk.few 1b
35377943Sdfr	;;
35477943Sdfr	mov	out1='\r'
35577943Sdfr	;;
35677943Sdfr	br.call.sptk.few rp=_putchar
35777943Sdfr	;;
35877943Sdfr	mov	out1='\n'
35977943Sdfr	;;
36077943Sdfr	br.call.sptk.few rp=_putchar
36177943Sdfr	;;
36277943Sdfr9:
36377943Sdfr	mov	ar.pfs=loc0
36477943Sdfr	mov	rp=loc1
36577943Sdfr	mov	ar.lc=loc2
36677943Sdfr	;;
36777943Sdfr	br.ret.sptk.few rp
36877943SdfrEND(_puthex)
36977943Sdfr
37077943Sdfr	.data
37177943Sdfr	.align	16
37277943Sdfr
37377943Sdfrfptr_storage:
37477943Sdfr	.space	1024*16			// XXX
37577943Sdfrfptr_storage_end:
376