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