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