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. - 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 .weak _zimage_start 48_zimage_start: 49 .globl _zimage_start_lib 50_zimage_start_lib: 51 /* Work out the offset between the address we were linked at 52 and the address where we're running. */ 53 bl .+4 54p_base: mflr r10 /* r10 now points to runtime addr of p_base */ 55#ifndef __powerpc64__ 56 /* grab the link address of the dynamic section in r11 */ 57 addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha 58 lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) 59 cmpwi r11,0 60 beq 3f /* if not linked -pie */ 61 /* get the runtime address of the dynamic section in r12 */ 62 .weak __dynamic_start 63 addis r12,r10,(__dynamic_start-p_base)@ha 64 addi r12,r12,(__dynamic_start-p_base)@l 65 subf r11,r11,r12 /* runtime - linktime offset */ 66 67 /* The dynamic section contains a series of tagged entries. 68 * We need the RELA and RELACOUNT entries. */ 69 li r9,0 70 li r0,0 719: lwz r8,0(r12) /* get tag */ 72 cmpwi r8,0 73 beq 10f /* end of list */ 74 cmpwi r8,RELA 75 bne 11f 76 lwz r9,4(r12) /* get RELA pointer in r9 */ 77 b 12f 7811: addis r8,r8,(-RELACOUNT)@ha 79 cmpwi r8,RELACOUNT@l 80 bne 12f 81 lwz r0,4(r12) /* get RELACOUNT value in r0 */ 8212: addi r12,r12,8 83 b 9b 84 85 /* The relocation section contains a list of relocations. 86 * We now do the R_PPC_RELATIVE ones, which point to words 87 * which need to be initialized with addend + offset. 88 * The R_PPC_RELATIVE ones come first and there are RELACOUNT 89 * of them. */ 9010: /* skip relocation if we don't have both */ 91 cmpwi r0,0 92 beq 3f 93 cmpwi r9,0 94 beq 3f 95 96 add r9,r9,r11 /* Relocate RELA pointer */ 97 mtctr r0 982: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ 99 cmpwi r0,22 /* R_PPC_RELATIVE */ 100 bne 3f 101 lwz r12,0(r9) /* reloc->r_offset */ 102 lwz r0,8(r9) /* reloc->r_addend */ 103 add r0,r0,r11 104 stwx r0,r11,r12 105 addi r9,r9,12 106 bdnz 2b 107 108 /* Do a cache flush for our text, in case the loader didn't */ 1093: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ 110 lwz r8,p_etext-p_base(r10) 1114: dcbf r0,r9 112 icbi r0,r9 113 addi r9,r9,0x20 114 cmplw cr0,r9,r8 115 blt 4b 116 sync 117 isync 118 119 /* Clear the BSS */ 120 lwz r9,p_bss_start-p_base(r10) 121 lwz r8,p_end-p_base(r10) 122 li r0,0 1235: stw r0,0(r9) 124 addi r9,r9,4 125 cmplw cr0,r9,r8 126 blt 5b 127 128 /* Possibly set up a custom stack */ 129 lwz r8,p_pstack-p_base(r10) 130 cmpwi r8,0 131 beq 6f 132 lwz r1,0(r8) 133 li r0,0 134 stwu r0,-16(r1) /* establish a stack frame */ 1356: 136#else /* __powerpc64__ */ 137 /* Save the prom pointer at p_prom. */ 138 std r5,(p_prom-p_base)(r10) 139 140 /* Set r2 to the TOC. */ 141 ld r2,(p_toc-p_base)(r10) 142 add r2,r2,r10 143 144 /* Grab the link address of the dynamic section in r11. */ 145 ld r11,-32768(r2) 146 cmpwi r11,0 147 beq 3f /* if not linked -pie then no dynamic section */ 148 149 ld r11,(p_dyn-p_base)(r10) 150 add r11,r11,r10 151 ld r9,(p_rela-p_base)(r10) 152 add r9,r9,r10 153 154 li r13,0 155 li r8,0 1569: ld r12,0(r11) /* get tag */ 157 cmpdi r12,0 158 beq 12f /* end of list */ 159 cmpdi r12,RELA 160 bne 10f 161 ld r13,8(r11) /* get RELA pointer in r13 */ 162 b 11f 16310: addis r12,r12,(-RELACOUNT)@ha 164 cmpdi r12,RELACOUNT@l 165 bne 11f 166 ld r8,8(r11) /* get RELACOUNT value in r8 */ 16711: addi r11,r11,16 168 b 9b 16912: 170 cmpdi r13,0 /* check we have both RELA and RELACOUNT */ 171 cmpdi cr1,r8,0 172 beq 3f 173 beq cr1,3f 174 175 /* Calcuate the runtime offset. */ 176 subf r13,r13,r9 177 178 /* Run through the list of relocations and process the 179 * R_PPC64_RELATIVE ones. */ 180 mtctr r8 18113: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ 182 cmpdi r0,22 /* R_PPC64_RELATIVE */ 183 bne 3f 184 ld r12,0(r9) /* reloc->r_offset */ 185 ld r0,16(r9) /* reloc->r_addend */ 186 add r0,r0,r13 187 stdx r0,r13,r12 188 addi r9,r9,24 189 bdnz 13b 190 191 /* Do a cache flush for our text, in case the loader didn't */ 1923: ld r9,p_start-p_base(r10) /* note: these are relocated now */ 193 ld r8,p_etext-p_base(r10) 1944: dcbf r0,r9 195 icbi r0,r9 196 addi r9,r9,0x20 197 cmpld cr0,r9,r8 198 blt 4b 199 sync 200 isync 201 202 /* Clear the BSS */ 203 ld r9,p_bss_start-p_base(r10) 204 ld r8,p_end-p_base(r10) 205 li r0,0 2065: std r0,0(r9) 207 addi r9,r9,8 208 cmpld cr0,r9,r8 209 blt 5b 210 211 /* Possibly set up a custom stack */ 212 ld r8,p_pstack-p_base(r10) 213 cmpdi r8,0 214 beq 6f 215 ld r1,0(r8) 216 li r0,0 217 stdu r0,-112(r1) /* establish a stack frame */ 2186: 219#endif /* __powerpc64__ */ 220 /* Call platform_init() */ 221 bl platform_init 222 223 /* Call start */ 224 b start 225 226#ifdef __powerpc64__ 227 228#define PROM_FRAME_SIZE 512 229 230.macro OP_REGS op, width, start, end, base, offset 231 .Lreg=\start 232 .rept (\end - \start + 1) 233 \op .Lreg,\offset+\width*.Lreg(\base) 234 .Lreg=.Lreg+1 235 .endr 236.endm 237 238#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0 239#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0 240#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base) 241#define REST_GPR(n, base) REST_GPRS(n, n, 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_GPRS(13, 31, r1) 253 mfcr r10 254 std r10,8*32(r1) 255 mfmsr r10 256 std r10,8*33(r1) 257 258 /* remove MSR_LE from msr but keep MSR_SF */ 259 mfmsr r10 260 rldicr r10,r10,0,62 261 mtsrr1 r10 262 263 /* Load FW address, set LR to label 1, and jump to FW */ 264 bl 0f 2650: mflr r10 266 addi r11,r10,(1f-0b) 267 mtlr r11 268 269 ld r10,(p_prom-0b)(r10) 270 mtsrr0 r10 271 272 rfid 273 2741: /* Return from OF */ 275 FIXUP_ENDIAN 276 277 /* Restore registers and return. */ 278 rldicl r1,r1,0,32 279 280 /* Restore the MSR (back to 64 bits) */ 281 ld r10,8*(33)(r1) 282 mtmsr r10 283 isync 284 285 /* Restore other registers */ 286 REST_GPR(2, r1) 287 REST_GPRS(13, 31, r1) 288 ld r10,8*32(r1) 289 mtcr r10 290 291 addi r1,r1,PROM_FRAME_SIZE 292 ld r0,16(r1) 293 mtlr r0 294 blr 295#endif 296