Linux-libre 5.4.49-gnu
[librecmc/linux-libre.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         .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
57 p_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
74 9:      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
81 11:     addis   r8,r8,(-RELACOUNT)@ha
82         cmpwi   r8,RELACOUNT@l
83         bne     12f
84         lwz     r0,4(r12)       /* get RELACOUNT value in r0 */
85 12:     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. */
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
99         add     r9,r9,r11       /* Relocate RELA pointer */
100         mtctr   r0
101 2:      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 */
112 3:      lwz     r9,p_start-p_base(r10)  /* note: these are relocated now */
113         lwz     r8,p_etext-p_base(r10)
114 4:      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
126 5:      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 */
138 6:
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
159 9:      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
166 10:     addis   r12,r12,(-RELACOUNT)@ha
167         cmpdi   r12,RELACOUNT@l
168         bne     11f
169         ld      r8,8(r11)       /* get RELACOUNT value in r8 */
170 11:     addi    r11,r11,16
171         b       9b
172 12:
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
184 13:     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 */
195 3:      ld      r9,p_start-p_base(r10)  /* note: these are relocated now */
196         ld      r8,p_etext-p_base(r10)
197 4:      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
209 5:      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 */
221 6:
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
246 prom:
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
267 0:      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
276 1:      /* 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