Merge tag 'mailbox-v4.20' of git://git.linaro.org/landing-teams/working/fujitsu/integ...
[sfrench/cifs-2.6.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         .text
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
27 #ifdef __powerpc64__
28 .balign 8
29 p_start:        .8byte  _start
30 p_etext:        .8byte  _etext
31 p_bss_start:    .8byte  __bss_start
32 p_end:          .8byte  _end
33
34 p_toc:          .8byte  __toc_start + 0x8000 - p_base
35 p_dyn:          .8byte  __dynamic_start - p_base
36 p_rela:         .8byte  __rela_dyn_start - p_base
37 p_prom:         .8byte  0
38         .weak   _platform_stack_top
39 p_pstack:       .8byte  _platform_stack_top
40 #else
41 p_start:        .long   _start
42 p_etext:        .long   _etext
43 p_bss_start:    .long   __bss_start
44 p_end:          .long   _end
45
46         .weak   _platform_stack_top
47 p_pstack:       .long   _platform_stack_top
48 #endif
49
50         .globl  _zimage_start
51         /* Clang appears to require the .weak directive to be after the symbol
52          * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921  */
53         .weak   _zimage_start
54 _zimage_start:
55         .globl  _zimage_start_lib
56 _zimage_start_lib:
57         /* Work out the offset between the address we were linked at
58            and the address where we're running. */
59         bl      .+4
60 p_base: mflr    r10             /* r10 now points to runtime addr of p_base */
61 #ifndef __powerpc64__
62         /* grab the link address of the dynamic section in r11 */
63         addis   r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
64         lwz     r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
65         cmpwi   r11,0
66         beq     3f              /* if not linked -pie */
67         /* get the runtime address of the dynamic section in r12 */
68         .weak   __dynamic_start
69         addis   r12,r10,(__dynamic_start-p_base)@ha
70         addi    r12,r12,(__dynamic_start-p_base)@l
71         subf    r11,r11,r12     /* runtime - linktime offset */
72
73         /* The dynamic section contains a series of tagged entries.
74          * We need the RELA and RELACOUNT entries. */
75         li      r9,0
76         li      r0,0
77 9:      lwz     r8,0(r12)       /* get tag */
78         cmpwi   r8,0
79         beq     10f             /* end of list */
80         cmpwi   r8,RELA
81         bne     11f
82         lwz     r9,4(r12)       /* get RELA pointer in r9 */
83         b       12f
84 11:     addis   r8,r8,(-RELACOUNT)@ha
85         cmpwi   r8,RELACOUNT@l
86         bne     12f
87         lwz     r0,4(r12)       /* get RELACOUNT value in r0 */
88 12:     addi    r12,r12,8
89         b       9b
90
91         /* The relocation section contains a list of relocations.
92          * We now do the R_PPC_RELATIVE ones, which point to words
93          * which need to be initialized with addend + offset.
94          * The R_PPC_RELATIVE ones come first and there are RELACOUNT
95          * of them. */
96 10:     /* skip relocation if we don't have both */
97         cmpwi   r0,0
98         beq     3f
99         cmpwi   r9,0
100         beq     3f
101
102         add     r9,r9,r11       /* Relocate RELA pointer */
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     3f
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         addi    r9,r9,12
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:     addis   r12,r12,(-RELACOUNT)@ha
170         cmpdi   r12,RELACOUNT@l
171         bne     11f
172         ld      r8,8(r11)       /* get RELACOUNT value in r8 */
173 11:     addi    r11,r11,16
174         b       9b
175 12:
176         cmpdi   r13,0            /* check we have both RELA and RELACOUNT */
177         cmpdi   cr1,r8,0
178         beq     3f
179         beq     cr1,3f
180
181         /* Calcuate the runtime offset. */
182         subf    r13,r13,r9
183
184         /* Run through the list of relocations and process the
185          * R_PPC64_RELATIVE ones. */
186         mtctr   r8
187 13:     ld      r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
188         cmpdi   r0,22           /* R_PPC64_RELATIVE */
189         bne     3f
190         ld      r12,0(r9)        /* reloc->r_offset */
191         ld      r0,16(r9)       /* reloc->r_addend */
192         add     r0,r0,r13
193         stdx    r0,r13,r12
194         addi    r9,r9,24
195         bdnz    13b
196
197         /* Do a cache flush for our text, in case the loader didn't */
198 3:      ld      r9,p_start-p_base(r10)  /* note: these are relocated now */
199         ld      r8,p_etext-p_base(r10)
200 4:      dcbf    r0,r9
201         icbi    r0,r9
202         addi    r9,r9,0x20
203         cmpld   cr0,r9,r8
204         blt     4b
205         sync
206         isync
207
208         /* Clear the BSS */
209         ld      r9,p_bss_start-p_base(r10)
210         ld      r8,p_end-p_base(r10)
211         li      r0,0
212 5:      std     r0,0(r9)
213         addi    r9,r9,8
214         cmpld   cr0,r9,r8
215         blt     5b
216
217         /* Possibly set up a custom stack */
218         ld      r8,p_pstack-p_base(r10)
219         cmpdi   r8,0
220         beq     6f
221         ld      r1,0(r8)
222         li      r0,0
223         stdu    r0,-112(r1)     /* establish a stack frame */
224 6:
225 #endif  /* __powerpc64__ */
226         /* Call platform_init() */
227         bl      platform_init
228
229         /* Call start */
230         b       start
231
232 #ifdef __powerpc64__
233
234 #define PROM_FRAME_SIZE 512
235 #define SAVE_GPR(n, base)       std     n,8*(n)(base)
236 #define REST_GPR(n, base)       ld      n,8*(n)(base)
237 #define SAVE_2GPRS(n, base)     SAVE_GPR(n, base); SAVE_GPR(n+1, base)
238 #define SAVE_4GPRS(n, base)     SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
239 #define SAVE_8GPRS(n, base)     SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
240 #define SAVE_10GPRS(n, base)    SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
241 #define REST_2GPRS(n, base)     REST_GPR(n, base); REST_GPR(n+1, base)
242 #define REST_4GPRS(n, base)     REST_2GPRS(n, base); REST_2GPRS(n+2, base)
243 #define REST_8GPRS(n, base)     REST_4GPRS(n, base); REST_4GPRS(n+4, base)
244 #define REST_10GPRS(n, base)    REST_8GPRS(n, base); REST_2GPRS(n+8, base)
245
246 /* prom handles the jump into and return from firmware.  The prom args pointer
247    is loaded in r3. */
248 .globl prom
249 prom:
250         mflr    r0
251         std     r0,16(r1)
252         stdu    r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
253
254         SAVE_GPR(2, r1)
255         SAVE_GPR(13, r1)
256         SAVE_8GPRS(14, r1)
257         SAVE_10GPRS(22, r1)
258         mfcr    r10
259         std     r10,8*32(r1)
260         mfmsr   r10
261         std     r10,8*33(r1)
262
263         /* remove MSR_LE from msr but keep MSR_SF */
264         mfmsr   r10
265         rldicr  r10,r10,0,62
266         mtsrr1  r10
267
268         /* Load FW address, set LR to label 1, and jump to FW */
269         bl      0f
270 0:      mflr    r10
271         addi    r11,r10,(1f-0b)
272         mtlr    r11
273
274         ld      r10,(p_prom-0b)(r10)
275         mtsrr0  r10
276
277         rfid
278
279 1:      /* Return from OF */
280         FIXUP_ENDIAN
281
282         /* Restore registers and return. */
283         rldicl  r1,r1,0,32
284
285         /* Restore the MSR (back to 64 bits) */
286         ld      r10,8*(33)(r1)
287         mtmsr   r10
288         isync
289
290         /* Restore other registers */
291         REST_GPR(2, r1)
292         REST_GPR(13, r1)
293         REST_8GPRS(14, r1)
294         REST_10GPRS(22, r1)
295         ld      r10,8*32(r1)
296         mtcr    r10
297
298         addi    r1,r1,PROM_FRAME_SIZE
299         ld      r0,16(r1)
300         mtlr    r0
301         blr
302 #endif