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