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