Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) Paul Mackerras 1997. | |
3 | * | |
f16e9684 CLG |
4 | * Adapted for 64 bit LE PowerPC by Andrew Tauferner |
5 | * | |
1da177e4 LT |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | * | |
1da177e4 LT |
11 | */ |
12 | ||
decd300b | 13 | #include "ppc_asm.h" |
1da177e4 | 14 | |
f16e9684 CLG |
15 | RELA = 7 |
16 | RELACOUNT = 0x6ffffff9 | |
17 | ||
1da177e4 | 18 | .text |
6975a783 ME |
19 | /* A procedure descriptor used when booting this as a COFF file. |
20 | * When making COFF, this comes first in the link and we're | |
21 | * linked at 0x500000. | |
22 | */ | |
f40e524e | 23 | .globl _zimage_start_opd |
66a45dd3 | 24 | _zimage_start_opd: |
6975a783 ME |
25 | .long 0x500000, 0, 0, 0 |
26 | ||
f16e9684 CLG |
27 | #ifdef __powerpc64__ |
28 | .balign 8 | |
eb039161 TH |
29 | p_start: .8byte _start |
30 | p_etext: .8byte _etext | |
31 | p_bss_start: .8byte __bss_start | |
32 | p_end: .8byte _end | |
f16e9684 | 33 | |
eb039161 TH |
34 | p_toc: .8byte __toc_start + 0x8000 - p_base |
35 | p_dyn: .8byte __dynamic_start - p_base | |
36 | p_rela: .8byte __rela_dyn_start - p_base | |
37 | p_prom: .8byte 0 | |
f16e9684 | 38 | .weak _platform_stack_top |
eb039161 | 39 | p_pstack: .8byte _platform_stack_top |
f16e9684 | 40 | #else |
6975a783 ME |
41 | p_start: .long _start |
42 | p_etext: .long _etext | |
43 | p_bss_start: .long __bss_start | |
44 | p_end: .long _end | |
45 | ||
46 | .weak _platform_stack_top | |
47 | p_pstack: .long _platform_stack_top | |
f16e9684 | 48 | #endif |
66a45dd3 | 49 | |
cd197ffc | 50 | .weak _zimage_start |
67a1b682 OH |
51 | .globl _zimage_start |
52 | _zimage_start: | |
160cc3ec MM |
53 | .globl _zimage_start_lib |
54 | _zimage_start_lib: | |
66a45dd3 PM |
55 | /* Work out the offset between the address we were linked at |
56 | and the address where we're running. */ | |
6975a783 ME |
57 | bl .+4 |
58 | p_base: mflr r10 /* r10 now points to runtime addr of p_base */ | |
f16e9684 | 59 | #ifndef __powerpc64__ |
6975a783 ME |
60 | /* grab the link address of the dynamic section in r11 */ |
61 | addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha | |
62 | lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) | |
63 | cmpwi r11,0 | |
64 | beq 3f /* if not linked -pie */ | |
65 | /* get the runtime address of the dynamic section in r12 */ | |
66 | .weak __dynamic_start | |
67 | addis r12,r10,(__dynamic_start-p_base)@ha | |
68 | addi r12,r12,(__dynamic_start-p_base)@l | |
69 | subf r11,r11,r12 /* runtime - linktime offset */ | |
70 | ||
71 | /* The dynamic section contains a series of tagged entries. | |
72 | * We need the RELA and RELACOUNT entries. */ | |
6975a783 ME |
73 | li r9,0 |
74 | li r0,0 | |
75 | 9: lwz r8,0(r12) /* get tag */ | |
76 | cmpwi r8,0 | |
77 | beq 10f /* end of list */ | |
78 | cmpwi r8,RELA | |
79 | bne 11f | |
80 | lwz r9,4(r12) /* get RELA pointer in r9 */ | |
81 | b 12f | |
82 | 11: addis r8,r8,(-RELACOUNT)@ha | |
83 | cmpwi r8,RELACOUNT@l | |
84 | bne 12f | |
85 | lwz r0,4(r12) /* get RELACOUNT value in r0 */ | |
86 | 12: addi r12,r12,8 | |
87 | b 9b | |
a4497235 | 88 | |
6975a783 ME |
89 | /* The relocation section contains a list of relocations. |
90 | * We now do the R_PPC_RELATIVE ones, which point to words | |
91 | * which need to be initialized with addend + offset. | |
92 | * The R_PPC_RELATIVE ones come first and there are RELACOUNT | |
93 | * of them. */ | |
94 | 10: /* skip relocation if we don't have both */ | |
95 | cmpwi r0,0 | |
68643cfb | 96 | beq 3f |
6975a783 ME |
97 | cmpwi r9,0 |
98 | beq 3f | |
99 | ||
100 | add r9,r9,r11 /* Relocate RELA pointer */ | |
101 | mtctr r0 | |
102 | 2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ | |
103 | cmpwi r0,22 /* R_PPC_RELATIVE */ | |
104 | bne 3f | |
105 | lwz r12,0(r9) /* reloc->r_offset */ | |
106 | lwz r0,8(r9) /* reloc->r_addend */ | |
107 | add r0,r0,r11 | |
108 | stwx r0,r11,r12 | |
109 | addi r9,r9,12 | |
68643cfb | 110 | bdnz 2b |
a4497235 | 111 | |
cd197ffc | 112 | /* Do a cache flush for our text, in case the loader didn't */ |
6975a783 ME |
113 | 3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ |
114 | lwz r8,p_etext-p_base(r10) | |
68643cfb | 115 | 4: dcbf r0,r9 |
1da177e4 LT |
116 | icbi r0,r9 |
117 | addi r9,r9,0x20 | |
eacb1962 | 118 | cmplw cr0,r9,r8 |
68643cfb | 119 | blt 4b |
1da177e4 LT |
120 | sync |
121 | isync | |
122 | ||
cd197ffc | 123 | /* Clear the BSS */ |
6975a783 ME |
124 | lwz r9,p_bss_start-p_base(r10) |
125 | lwz r8,p_end-p_base(r10) | |
126 | li r0,0 | |
127 | 5: stw r0,0(r9) | |
cd197ffc DG |
128 | addi r9,r9,4 |
129 | cmplw cr0,r9,r8 | |
130 | blt 5b | |
1da177e4 | 131 | |
cd197ffc | 132 | /* Possibly set up a custom stack */ |
6975a783 | 133 | lwz r8,p_pstack-p_base(r10) |
cd197ffc DG |
134 | cmpwi r8,0 |
135 | beq 6f | |
136 | lwz r1,0(r8) | |
137 | li r0,0 | |
138 | stwu r0,-16(r1) /* establish a stack frame */ | |
139 | 6: | |
f16e9684 CLG |
140 | #else /* __powerpc64__ */ |
141 | /* Save the prom pointer at p_prom. */ | |
142 | std r5,(p_prom-p_base)(r10) | |
143 | ||
144 | /* Set r2 to the TOC. */ | |
145 | ld r2,(p_toc-p_base)(r10) | |
146 | add r2,r2,r10 | |
147 | ||
148 | /* Grab the link address of the dynamic section in r11. */ | |
149 | ld r11,-32768(r2) | |
150 | cmpwi r11,0 | |
151 | beq 3f /* if not linked -pie then no dynamic section */ | |
152 | ||
153 | ld r11,(p_dyn-p_base)(r10) | |
154 | add r11,r11,r10 | |
155 | ld r9,(p_rela-p_base)(r10) | |
156 | add r9,r9,r10 | |
157 | ||
7f664cf9 | 158 | li r13,0 |
f16e9684 | 159 | li r8,0 |
7f664cf9 JK |
160 | 9: ld r12,0(r11) /* get tag */ |
161 | cmpdi r12,0 | |
f16e9684 | 162 | beq 12f /* end of list */ |
7f664cf9 | 163 | cmpdi r12,RELA |
f16e9684 | 164 | bne 10f |
7f664cf9 | 165 | ld r13,8(r11) /* get RELA pointer in r13 */ |
f16e9684 | 166 | b 11f |
7f664cf9 JK |
167 | 10: addis r12,r12,(-RELACOUNT)@ha |
168 | cmpdi r12,RELACOUNT@l | |
f16e9684 CLG |
169 | bne 11f |
170 | ld r8,8(r11) /* get RELACOUNT value in r8 */ | |
171 | 11: addi r11,r11,16 | |
172 | b 9b | |
173 | 12: | |
7f664cf9 | 174 | cmpdi r13,0 /* check we have both RELA and RELACOUNT */ |
f16e9684 CLG |
175 | cmpdi cr1,r8,0 |
176 | beq 3f | |
177 | beq cr1,3f | |
178 | ||
179 | /* Calcuate the runtime offset. */ | |
7f664cf9 | 180 | subf r13,r13,r9 |
cd197ffc | 181 | |
f16e9684 CLG |
182 | /* Run through the list of relocations and process the |
183 | * R_PPC64_RELATIVE ones. */ | |
184 | mtctr r8 | |
185 | 13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ | |
186 | cmpdi r0,22 /* R_PPC64_RELATIVE */ | |
187 | bne 3f | |
7f664cf9 | 188 | ld r12,0(r9) /* reloc->r_offset */ |
f16e9684 | 189 | ld r0,16(r9) /* reloc->r_addend */ |
7f664cf9 JK |
190 | add r0,r0,r13 |
191 | stdx r0,r13,r12 | |
f16e9684 CLG |
192 | addi r9,r9,24 |
193 | bdnz 13b | |
194 | ||
195 | /* Do a cache flush for our text, in case the loader didn't */ | |
196 | 3: ld r9,p_start-p_base(r10) /* note: these are relocated now */ | |
197 | ld r8,p_etext-p_base(r10) | |
198 | 4: dcbf r0,r9 | |
199 | icbi r0,r9 | |
200 | addi r9,r9,0x20 | |
201 | cmpld cr0,r9,r8 | |
202 | blt 4b | |
203 | sync | |
204 | isync | |
205 | ||
206 | /* Clear the BSS */ | |
207 | ld r9,p_bss_start-p_base(r10) | |
208 | ld r8,p_end-p_base(r10) | |
209 | li r0,0 | |
210 | 5: std r0,0(r9) | |
211 | addi r9,r9,8 | |
212 | cmpld cr0,r9,r8 | |
213 | blt 5b | |
214 | ||
215 | /* Possibly set up a custom stack */ | |
216 | ld r8,p_pstack-p_base(r10) | |
217 | cmpdi r8,0 | |
218 | beq 6f | |
219 | ld r1,0(r8) | |
220 | li r0,0 | |
8c06f0d9 | 221 | stdu r0,-112(r1) /* establish a stack frame */ |
f16e9684 CLG |
222 | 6: |
223 | #endif /* __powerpc64__ */ | |
cd197ffc DG |
224 | /* Call platform_init() */ |
225 | bl platform_init | |
226 | ||
227 | /* Call start */ | |
cd197ffc | 228 | b start |
93d39210 CLG |
229 | |
230 | #ifdef __powerpc64__ | |
231 | ||
232 | #define PROM_FRAME_SIZE 512 | |
233 | #define SAVE_GPR(n, base) std n,8*(n)(base) | |
234 | #define REST_GPR(n, base) ld n,8*(n)(base) | |
235 | #define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) | |
236 | #define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) | |
237 | #define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) | |
238 | #define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) | |
239 | #define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) | |
240 | #define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) | |
241 | #define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) | |
242 | #define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) | |
243 | ||
244 | /* prom handles the jump into and return from firmware. The prom args pointer | |
245 | is loaded in r3. */ | |
246 | .globl prom | |
247 | prom: | |
248 | mflr r0 | |
249 | std r0,16(r1) | |
250 | stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ | |
251 | ||
252 | SAVE_GPR(2, r1) | |
253 | SAVE_GPR(13, r1) | |
254 | SAVE_8GPRS(14, r1) | |
255 | SAVE_10GPRS(22, r1) | |
256 | mfcr r10 | |
257 | std r10,8*32(r1) | |
258 | mfmsr r10 | |
259 | std r10,8*33(r1) | |
260 | ||
261 | /* remove MSR_LE from msr but keep MSR_SF */ | |
262 | mfmsr r10 | |
263 | rldicr r10,r10,0,62 | |
264 | mtsrr1 r10 | |
265 | ||
266 | /* Load FW address, set LR to label 1, and jump to FW */ | |
267 | bl 0f | |
268 | 0: mflr r10 | |
269 | addi r11,r10,(1f-0b) | |
270 | mtlr r11 | |
271 | ||
272 | ld r10,(p_prom-0b)(r10) | |
273 | mtsrr0 r10 | |
274 | ||
275 | rfid | |
276 | ||
277 | 1: /* Return from OF */ | |
147c0516 | 278 | FIXUP_ENDIAN |
93d39210 CLG |
279 | |
280 | /* Restore registers and return. */ | |
281 | rldicl r1,r1,0,32 | |
282 | ||
283 | /* Restore the MSR (back to 64 bits) */ | |
284 | ld r10,8*(33)(r1) | |
285 | mtmsr r10 | |
286 | isync | |
287 | ||
288 | /* Restore other registers */ | |
289 | REST_GPR(2, r1) | |
290 | REST_GPR(13, r1) | |
291 | REST_8GPRS(14, r1) | |
292 | REST_10GPRS(22, r1) | |
293 | ld r10,8*32(r1) | |
294 | mtcr r10 | |
295 | ||
296 | addi r1,r1,PROM_FRAME_SIZE | |
297 | ld r0,16(r1) | |
298 | mtlr r0 | |
299 | blr | |
300 | #endif |