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