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