2 * Copyright (C) Paul Mackerras 1997.
4 * Adapted for 64 bit LE PowerPC by Andrew Tauferner
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.
16 RELACOUNT = 0x6ffffff9
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
23 .globl _zimage_start_opd
25 .long 0x500000, 0, 0, 0
31 p_start: .llong _start
32 p_etext: .llong _etext
33 p_bss_start: .llong __bss_start
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
40 .weak _platform_stack_top
41 p_pstack: .llong _platform_stack_top
45 p_bss_start: .long __bss_start
48 .weak _platform_stack_top
49 p_pstack: .long _platform_stack_top
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 */
57 .globl _zimage_start_lib
59 /* Work out the offset between the address we were linked at
60 and the address where we're running. */
62 p_base: mflr r10 /* r10 now points to runtime addr of p_base */
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)
68 beq 3f /* if not linked -pie */
69 /* get the runtime address of the dynamic section in r12 */
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 */
75 /* The dynamic section contains a series of tagged entries.
76 * We need the RELA and RELACOUNT entries. */
79 9: lwz r8,0(r12) /* get tag */
81 beq 10f /* end of list */
84 lwz r9,4(r12) /* get RELA pointer in r9 */
86 11: addis r8,r8,(-RELACOUNT)@ha
89 lwz r0,4(r12) /* get RELACOUNT value in r0 */
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
98 10: /* skip relocation if we don't have both */
104 add r9,r9,r11 /* Relocate RELA pointer */
106 2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */
107 cmpwi r0,22 /* R_PPC_RELATIVE */
109 lwz r12,0(r9) /* reloc->r_offset */
110 lwz r0,8(r9) /* reloc->r_addend */
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)
128 lwz r9,p_bss_start-p_base(r10)
129 lwz r8,p_end-p_base(r10)
136 /* Possibly set up a custom stack */
137 lwz r8,p_pstack-p_base(r10)
142 stwu r0,-16(r1) /* establish a stack frame */
144 #else /* __powerpc64__ */
145 /* Save the prom pointer at p_prom. */
146 std r5,(p_prom-p_base)(r10)
148 /* Set r2 to the TOC. */
149 ld r2,(p_toc-p_base)(r10)
152 /* Grab the link address of the dynamic section in r11. */
155 beq 3f /* if not linked -pie then no dynamic section */
157 ld r11,(p_dyn-p_base)(r10)
159 ld r9,(p_rela-p_base)(r10)
164 9: ld r12,0(r11) /* get tag */
166 beq 12f /* end of list */
169 ld r13,8(r11) /* get RELA pointer in r13 */
171 10: addis r12,r12,(-RELACOUNT)@ha
172 cmpdi r12,RELACOUNT@l
174 ld r8,8(r11) /* get RELACOUNT value in r8 */
178 cmpdi r13,0 /* check we have both RELA and RELACOUNT */
183 /* Calcuate the runtime offset. */
186 /* Run through the list of relocations and process the
187 * R_PPC64_RELATIVE ones. */
189 13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */
190 cmpdi r0,22 /* R_PPC64_RELATIVE */
192 ld r12,0(r9) /* reloc->r_offset */
193 ld r0,16(r9) /* reloc->r_addend */
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)
211 ld r9,p_bss_start-p_base(r10)
212 ld r8,p_end-p_base(r10)
219 /* Possibly set up a custom stack */
220 ld r8,p_pstack-p_base(r10)
225 stdu r0,-112(r1) /* establish a stack frame */
227 #endif /* __powerpc64__ */
228 /* Call platform_init() */
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)
248 /* prom handles the jump into and return from firmware. The prom args pointer
254 stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
265 /* remove MSR_LE from msr but keep MSR_SF */
270 /* Load FW address, set LR to label 1, and jump to FW */
276 ld r10,(p_prom-0b)(r10)
281 1: /* Return from OF */
284 /* Restore registers and return. */
287 /* Restore the MSR (back to 64 bits) */
292 /* Restore other registers */
300 addi r1,r1,PROM_FRAME_SIZE