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