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