1/* 2 * Copyright (C) Paul Mackerras 1997. 3 * 4 * Adapted for 64 bit LE PowerPC by Andrew Tauferner 5 * 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. 10 * 11 */ 12 13#include "ppc_asm.h" 14 15RELA = 7 16RELACOUNT = 0x6ffffff9 17 18 .data 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 21 * linked at 0x500000. 22 */ 23 .globl _zimage_start_opd 24_zimage_start_opd: 25 .long 0x500000, 0, 0, 0 26 .text 27 b _zimage_start 28 29#ifdef __powerpc64__ 30.balign 8 31p_start: .8byte _start 32p_etext: .8byte _etext 33p_bss_start: .8byte __bss_start 34p_end: .8byte _end 35 36p_toc: .8byte __toc_start + 0x8000 - p_base 37p_dyn: .8byte __dynamic_start - p_base 38p_rela: .8byte __rela_dyn_start - p_base 39p_prom: .8byte 0 40 .weak _platform_stack_top 41p_pstack: .8byte _platform_stack_top 42#else 43p_start: .long _start 44p_etext: .long _etext 45p_bss_start: .long __bss_start 46p_end: .long _end 47 48 .weak _platform_stack_top 49p_pstack: .long _platform_stack_top 50#endif 51 52 .globl _zimage_start 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 */ 55 .weak _zimage_start 56_zimage_start: 57 .globl _zimage_start_lib 58_zimage_start_lib: 59 /* Work out the offset between the address we were linked at 60 and the address where we're running. */ 61 bl .+4 62p_base: mflr r10 /* r10 now points to runtime addr of p_base */ 63#ifndef __powerpc64__ 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) 67 cmpwi r11,0 68 beq 3f /* if not linked -pie */ 69 /* get the runtime address of the dynamic section in r12 */ 70 .weak __dynamic_start 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 */ 74 75 /* The dynamic section contains a series of tagged entries. 76 * We need the RELA and RELACOUNT entries. */ 77 li r9,0 78 li r0,0 799: lwz r8,0(r12) /* get tag */ 80 cmpwi r8,0 81 beq 10f /* end of list */ 82 cmpwi r8,RELA 83 bne 11f 84 lwz r9,4(r12) /* get RELA pointer in r9 */ 85 b 12f 8611: addis r8,r8,(-RELACOUNT)@ha 87 cmpwi r8,RELACOUNT@l 88 bne 12f 89 lwz r0,4(r12) /* get RELACOUNT value in r0 */ 9012: addi r12,r12,8 91 b 9b 92 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 97 * of them. */ 9810: /* skip relocation if we don't have both */ 99 cmpwi r0,0 100 beq 3f 101 cmpwi r9,0 102 beq 3f 103 104 add r9,r9,r11 /* Relocate RELA pointer */ 105 mtctr r0 1062: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ 107 cmpwi r0,22 /* R_PPC_RELATIVE */ 108 bne 3f 109 lwz r12,0(r9) /* reloc->r_offset */ 110 lwz r0,8(r9) /* reloc->r_addend */ 111 add r0,r0,r11 112 stwx r0,r11,r12 113 addi r9,r9,12 114 bdnz 2b 115 116 /* Do a cache flush for our text, in case the loader didn't */ 1173: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ 118 lwz r8,p_etext-p_base(r10) 1194: dcbf r0,r9 120 icbi r0,r9 121 addi r9,r9,0x20 122 cmplw cr0,r9,r8 123 blt 4b 124 sync 125 isync 126 127 /* Clear the BSS */ 128 lwz r9,p_bss_start-p_base(r10) 129 lwz r8,p_end-p_base(r10) 130 li r0,0 1315: stw r0,0(r9) 132 addi r9,r9,4 133 cmplw cr0,r9,r8 134 blt 5b 135 136 /* Possibly set up a custom stack */ 137 lwz r8,p_pstack-p_base(r10) 138 cmpwi r8,0 139 beq 6f 140 lwz r1,0(r8) 141 li r0,0 142 stwu r0,-16(r1) /* establish a stack frame */ 1436: 144#else /* __powerpc64__ */ 145 /* Save the prom pointer at p_prom. */ 146 std r5,(p_prom-p_base)(r10) 147 148 /* Set r2 to the TOC. */ 149 ld r2,(p_toc-p_base)(r10) 150 add r2,r2,r10 151 152 /* Grab the link address of the dynamic section in r11. */ 153 ld r11,-32768(r2) 154 cmpwi r11,0 155 beq 3f /* if not linked -pie then no dynamic section */ 156 157 ld r11,(p_dyn-p_base)(r10) 158 add r11,r11,r10 159 ld r9,(p_rela-p_base)(r10) 160 add r9,r9,r10 161 162 li r13,0 163 li r8,0 1649: ld r12,0(r11) /* get tag */ 165 cmpdi r12,0 166 beq 12f /* end of list */ 167 cmpdi r12,RELA 168 bne 10f 169 ld r13,8(r11) /* get RELA pointer in r13 */ 170 b 11f 17110: addis r12,r12,(-RELACOUNT)@ha 172 cmpdi r12,RELACOUNT@l 173 bne 11f 174 ld r8,8(r11) /* get RELACOUNT value in r8 */ 17511: addi r11,r11,16 176 b 9b 17712: 178 cmpdi r13,0 /* check we have both RELA and RELACOUNT */ 179 cmpdi cr1,r8,0 180 beq 3f 181 beq cr1,3f 182 183 /* Calcuate the runtime offset. */ 184 subf r13,r13,r9 185 186 /* Run through the list of relocations and process the 187 * R_PPC64_RELATIVE ones. */ 188 mtctr r8 18913: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ 190 cmpdi r0,22 /* R_PPC64_RELATIVE */ 191 bne 3f 192 ld r12,0(r9) /* reloc->r_offset */ 193 ld r0,16(r9) /* reloc->r_addend */ 194 add r0,r0,r13 195 stdx r0,r13,r12 196 addi r9,r9,24 197 bdnz 13b 198 199 /* Do a cache flush for our text, in case the loader didn't */ 2003: ld r9,p_start-p_base(r10) /* note: these are relocated now */ 201 ld r8,p_etext-p_base(r10) 2024: dcbf r0,r9 203 icbi r0,r9 204 addi r9,r9,0x20 205 cmpld cr0,r9,r8 206 blt 4b 207 sync 208 isync 209 210 /* Clear the BSS */ 211 ld r9,p_bss_start-p_base(r10) 212 ld r8,p_end-p_base(r10) 213 li r0,0 2145: std r0,0(r9) 215 addi r9,r9,8 216 cmpld cr0,r9,r8 217 blt 5b 218 219 /* Possibly set up a custom stack */ 220 ld r8,p_pstack-p_base(r10) 221 cmpdi r8,0 222 beq 6f 223 ld r1,0(r8) 224 li r0,0 225 stdu r0,-112(r1) /* establish a stack frame */ 2266: 227#endif /* __powerpc64__ */ 228 /* Call platform_init() */ 229 bl platform_init 230 231 /* Call start */ 232 b start 233 234#ifdef __powerpc64__ 235 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) 247 248/* prom handles the jump into and return from firmware. The prom args pointer 249 is loaded in r3. */ 250.globl prom 251prom: 252 mflr r0 253 std r0,16(r1) 254 stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ 255 256 SAVE_GPR(2, r1) 257 SAVE_GPR(13, r1) 258 SAVE_8GPRS(14, r1) 259 SAVE_10GPRS(22, r1) 260 mfcr r10 261 std r10,8*32(r1) 262 mfmsr r10 263 std r10,8*33(r1) 264 265 /* remove MSR_LE from msr but keep MSR_SF */ 266 mfmsr r10 267 rldicr r10,r10,0,62 268 mtsrr1 r10 269 270 /* Load FW address, set LR to label 1, and jump to FW */ 271 bl 0f 2720: mflr r10 273 addi r11,r10,(1f-0b) 274 mtlr r11 275 276 ld r10,(p_prom-0b)(r10) 277 mtsrr0 r10 278 279 rfid 280 2811: /* Return from OF */ 282 FIXUP_ENDIAN 283 284 /* Restore registers and return. */ 285 rldicl r1,r1,0,32 286 287 /* Restore the MSR (back to 64 bits) */ 288 ld r10,8*(33)(r1) 289 mtmsr r10 290 isync 291 292 /* Restore other registers */ 293 REST_GPR(2, r1) 294 REST_GPR(13, r1) 295 REST_8GPRS(14, r1) 296 REST_10GPRS(22, r1) 297 ld r10,8*32(r1) 298 mtcr r10 299 300 addi r1,r1,PROM_FRAME_SIZE 301 ld r0,16(r1) 302 mtlr r0 303 blr 304#endif 305