Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/boot/crt0.S
26424 views
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
10
RELA = 7
11
RELASZ = 8
12
RELAENT = 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
27
p_start: .8byte _start
28
p_etext: .8byte _etext
29
p_bss_start: .8byte __bss_start
30
p_end: .8byte _end
31
32
p_toc: .8byte .TOC. - p_base
33
p_dyn: .8byte __dynamic_start - p_base
34
p_rela: .8byte __rela_dyn_start - p_base
35
p_prom: .8byte 0
36
.weak _platform_stack_top
37
p_pstack: .8byte _platform_stack_top
38
#else
39
p_start: .long _start
40
p_etext: .long _etext
41
p_bss_start: .long __bss_start
42
p_end: .long _end
43
44
.weak _platform_stack_top
45
p_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
bcl 20,31,.+4
55
p_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
72
9: 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
79
11: 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 */
87
12: 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 */
93
10: /* 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
104
2: 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 */
115
3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */
116
lwz r8,p_etext-p_base(r10)
117
4: 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
129
5: 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 */
141
6:
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
162
9: 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
169
10: 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 */
177
11: addi r11,r11,16
178
b 9b
179
12:
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
194
13: 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 */
205
3: ld r9,p_start-p_base(r10) /* note: these are relocated now */
206
ld r8,p_etext-p_base(r10)
207
4: 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
219
5: 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 */
231
6:
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
259
prom:
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
bcl 20,31,0f
278
0: 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
287
1: /* 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
309
310