1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * Copyright (C) Paul Mackerras 1997.
5 * Adapted for 64 bit LE PowerPC by Andrew Tauferner
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
19 .globl _zimage_start_opd
21 .long 0x500000, 0, 0, 0
27 p_start: .8byte _start
28 p_etext: .8byte _etext
29 p_bss_start: .8byte __bss_start
32 p_toc: .8byte .TOC. - p_base
33 p_dyn: .8byte __dynamic_start - p_base
34 p_rela: .8byte __rela_dyn_start - p_base
36 .weak _platform_stack_top
37 p_pstack: .8byte _platform_stack_top
41 p_bss_start: .long __bss_start
44 .weak _platform_stack_top
45 p_pstack: .long _platform_stack_top
50 .globl _zimage_start_lib
52 /* Work out the offset between the address we were linked at
53 and the address where we're running. */
55 p_base: mflr r10 /* r10 now points to runtime addr of p_base */
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)
61 beq 3f /* if not linked -pie */
62 /* get the runtime address of the dynamic section in r12 */
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 */
68 /* The dynamic section contains a series of tagged entries.
69 * We need the RELA and RELACOUNT entries. */
72 9: lwz r8,0(r12) /* get tag */
74 beq 10f /* end of list */
77 lwz r9,4(r12) /* get RELA pointer in r9 */
80 bne .Lcheck_for_relaent
81 lwz r0,4(r12) /* get RELASZ value in r0 */
86 lwz r14,4(r12) /* get RELAENT value in r14 */
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 */
101 add r9,r9,r11 /* Relocate RELA pointer */
102 divwu r0,r0,r14 /* RELASZ / RELAENT */
104 2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */
105 cmpwi r0,22 /* R_PPC_RELATIVE */
107 lwz r12,0(r9) /* reloc->r_offset */
108 lwz r0,8(r9) /* reloc->r_addend */
111 .Lnext: add r9,r9,r14
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)
126 lwz r9,p_bss_start-p_base(r10)
127 lwz r8,p_end-p_base(r10)
134 /* Possibly set up a custom stack */
135 lwz r8,p_pstack-p_base(r10)
140 stwu r0,-16(r1) /* establish a stack frame */
142 #else /* __powerpc64__ */
143 /* Save the prom pointer at p_prom. */
144 std r5,(p_prom-p_base)(r10)
146 /* Set r2 to the TOC. */
147 ld r2,(p_toc-p_base)(r10)
150 /* Grab the link address of the dynamic section in r11. */
153 beq 3f /* if not linked -pie then no dynamic section */
155 ld r11,(p_dyn-p_base)(r10)
157 ld r9,(p_rela-p_base)(r10)
162 9: ld r12,0(r11) /* get tag */
164 beq 12f /* end of list */
167 ld r13,8(r11) /* get RELA pointer in r13 */
170 bne .Lcheck_for_relaent
171 lwz r8,8(r11) /* get RELASZ pointer in r8 */
176 lwz r14,8(r11) /* get RELAENT pointer in r14 */
180 cmpdi r13,0 /* check we have both RELA, RELASZ, RELAENT*/
187 /* Calcuate the runtime offset. */
190 /* Run through the list of relocations and process the
191 * R_PPC64_RELATIVE ones. */
192 divdu r8,r8,r14 /* RELASZ / RELAENT */
194 13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */
195 cmpdi r0,22 /* R_PPC64_RELATIVE */
197 ld r12,0(r9) /* reloc->r_offset */
198 ld r0,16(r9) /* reloc->r_addend */
201 .Lnext: add r9,r9,r14
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)
216 ld r9,p_bss_start-p_base(r10)
217 ld r8,p_end-p_base(r10)
224 /* Possibly set up a custom stack */
225 ld r8,p_pstack-p_base(r10)
230 stdu r0,-112(r1) /* establish a stack frame */
232 #endif /* __powerpc64__ */
233 /* Call platform_init() */
241 #define PROM_FRAME_SIZE 512
243 .macro OP_REGS op, width, start, end, base, offset
245 .rept (\end - \start + 1)
246 \op .Lreg,\offset+\width*.Lreg(\base)
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)
256 /* prom handles the jump into and return from firmware. The prom args pointer
262 stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
265 SAVE_GPRS(13, 31, r1)
271 /* remove MSR_LE from msr but keep MSR_SF */
276 /* Load FW address, set LR to label 1, and jump to FW */
282 ld r10,(p_prom-0b)(r10)
287 1: /* Return from OF */
290 /* Restore registers and return. */
293 /* Restore the MSR (back to 64 bits) */
298 /* Restore other registers */
300 REST_GPRS(13, 31, r1)
304 addi r1,r1,PROM_FRAME_SIZE