initial commit
[freebsd-arm:freebsd-arm.git] / boot / ia64 / efi / start.S
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
53 ENTRY(_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
71 9:
72         mov     ar.pfs=loc0
73         mov     rp=loc1
74         ;;
75         br.ret.sptk.few rp
76 END(_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
117 STATIC_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         ;;
136 1:
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
169 2:
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
183 3:
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
234 3:
235         add     r29=in0,r17
236         ;;
237         st4     [r15]=r29
238         br.cond.sptk.few 2b
239
240         // REL64LSB
241 4:
242         add     r29=in0,r17             // BD + A
243         ;;
244         st8     [r15]=r29               // word64
245         br.cond.sptk.few 2b
246
247         // DIR64LSB
248 5:
249         add     r29=r24,r17             // S + A
250         ;;
251         st8     [r15]=r29               // word64
252         br.cond.sptk.few 2b
253
254 6:
255         mov     r29=r2                  // FPTR64LSB
256         ;;
257 7:
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
268 8:
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
279 9:
280         mov     ar.pfs=loc0
281         mov     rp=loc1
282         ;;
283         br.ret.sptk.few rp
284 END(_reloc)
285
286         .data
287         .align  16
288 fptr_storage:
289         .space  1024*16                 // XXX
290 fptr_storage_end: