blob: 12866ccb5694d3bce05fa7ab8030a57585eb2914 [file] [log] [blame]
Kyle Swenson8d8f6542021-03-15 11:02:55 -06001/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * Adapted for 64 bit LE PowerPC by Andrew Tauferner
5 *
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 *
11 */
12
13#include "ppc_asm.h"
14
15RELA = 7
16RELACOUNT = 0x6ffffff9
17
18 .text
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 */
23 .globl _zimage_start_opd
24_zimage_start_opd:
25 .long 0x500000, 0, 0, 0
26
27#ifdef __powerpc64__
28.balign 8
29p_start: .llong _start
30p_etext: .llong _etext
31p_bss_start: .llong __bss_start
32p_end: .llong _end
33
34p_toc: .llong __toc_start + 0x8000 - p_base
35p_dyn: .llong __dynamic_start - p_base
36p_rela: .llong __rela_dyn_start - p_base
37p_prom: .llong 0
38 .weak _platform_stack_top
39p_pstack: .llong _platform_stack_top
40#else
41p_start: .long _start
42p_etext: .long _etext
43p_bss_start: .long __bss_start
44p_end: .long _end
45
46 .weak _platform_stack_top
47p_pstack: .long _platform_stack_top
48#endif
49
50 .weak _zimage_start
51 .globl _zimage_start
52_zimage_start:
53 .globl _zimage_start_lib
54_zimage_start_lib:
55 /* Work out the offset between the address we were linked at
56 and the address where we're running. */
57 bl .+4
58p_base: mflr r10 /* r10 now points to runtime addr of p_base */
59#ifndef __powerpc64__
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. */
73 li r9,0
74 li r0,0
759: 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
8211: addis r8,r8,(-RELACOUNT)@ha
83 cmpwi r8,RELACOUNT@l
84 bne 12f
85 lwz r0,4(r12) /* get RELACOUNT value in r0 */
8612: addi r12,r12,8
87 b 9b
88
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. */
9410: /* skip relocation if we don't have both */
95 cmpwi r0,0
96 beq 3f
97 cmpwi r9,0
98 beq 3f
99
100 add r9,r9,r11 /* Relocate RELA pointer */
101 mtctr r0
1022: 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
110 bdnz 2b
111
112 /* Do a cache flush for our text, in case the loader didn't */
1133: lwz r9,p_start-p_base(r10) /* note: these are relocated now */
114 lwz r8,p_etext-p_base(r10)
1154: dcbf r0,r9
116 icbi r0,r9
117 addi r9,r9,0x20
118 cmplw cr0,r9,r8
119 blt 4b
120 sync
121 isync
122
123 /* Clear the BSS */
124 lwz r9,p_bss_start-p_base(r10)
125 lwz r8,p_end-p_base(r10)
126 li r0,0
1275: stw r0,0(r9)
128 addi r9,r9,4
129 cmplw cr0,r9,r8
130 blt 5b
131
132 /* Possibly set up a custom stack */
133 lwz r8,p_pstack-p_base(r10)
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 */
1396:
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
158 li r13,0
159 li r8,0
1609: ld r12,0(r11) /* get tag */
161 cmpdi r12,0
162 beq 12f /* end of list */
163 cmpdi r12,RELA
164 bne 10f
165 ld r13,8(r11) /* get RELA pointer in r13 */
166 b 11f
16710: addis r12,r12,(-RELACOUNT)@ha
168 cmpdi r12,RELACOUNT@l
169 bne 11f
170 ld r8,8(r11) /* get RELACOUNT value in r8 */
17111: addi r11,r11,16
172 b 9b
17312:
174 cmpdi r13,0 /* check we have both RELA and RELACOUNT */
175 cmpdi cr1,r8,0
176 beq 3f
177 beq cr1,3f
178
179 /* Calcuate the runtime offset. */
180 subf r13,r13,r9
181
182 /* Run through the list of relocations and process the
183 * R_PPC64_RELATIVE ones. */
184 mtctr r8
18513: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */
186 cmpdi r0,22 /* R_PPC64_RELATIVE */
187 bne 3f
188 ld r12,0(r9) /* reloc->r_offset */
189 ld r0,16(r9) /* reloc->r_addend */
190 add r0,r0,r13
191 stdx r0,r13,r12
192 addi r9,r9,24
193 bdnz 13b
194
195 /* Do a cache flush for our text, in case the loader didn't */
1963: ld r9,p_start-p_base(r10) /* note: these are relocated now */
197 ld r8,p_etext-p_base(r10)
1984: 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
2105: 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
221 stdu r0,-112(r1) /* establish a stack frame */
2226:
223#endif /* __powerpc64__ */
224 /* Call platform_init() */
225 bl platform_init
226
227 /* Call start */
228 b start
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
247prom:
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
2680: 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
2771: /* Return from OF */
278 FIXUP_ENDIAN
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