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