Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) Paul Mackerras 1997. * * Adapted for 64 bit LE PowerPC by Andrew Tauferner */ #include "ppc_asm.h" RELA = 7 RELASZ = 8 RELAENT = 9 .data /* A procedure descriptor used when booting this as a COFF file. * When making COFF, this comes first in the link and we're * linked at 0x500000. */ .globl _zimage_start_opd _zimage_start_opd: .long 0x500000, 0, 0, 0 .text b _zimage_start #ifdef __powerpc64__ .balign 8 p_start: .8byte _start p_etext: .8byte _etext p_bss_start: .8byte __bss_start p_end: .8byte _end p_toc: .8byte .TOC. - p_base p_dyn: .8byte __dynamic_start - p_base p_rela: .8byte __rela_dyn_start - p_base p_prom: .8byte 0 .weak _platform_stack_top p_pstack: .8byte _platform_stack_top #else p_start: .long _start p_etext: .long _etext p_bss_start: .long __bss_start p_end: .long _end .weak _platform_stack_top p_pstack: .long _platform_stack_top #endif .weak _zimage_start _zimage_start: .globl _zimage_start_lib _zimage_start_lib: /* Work out the offset between the address we were linked at and the address where we're running. */ bl .+4 p_base: mflr r10 /* r10 now points to runtime addr of p_base */ #ifndef __powerpc64__ /* grab the link address of the dynamic section in r11 */ addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) cmpwi r11,0 beq 3f /* if not linked -pie */ /* get the runtime address of the dynamic section in r12 */ .weak __dynamic_start addis r12,r10,(__dynamic_start-p_base)@ha addi r12,r12,(__dynamic_start-p_base)@l subf r11,r11,r12 /* runtime - linktime offset */ /* The dynamic section contains a series of tagged entries. * We need the RELA and RELACOUNT entries. */ li r9,0 li r0,0 9: lwz r8,0(r12) /* get tag */ cmpwi r8,0 beq 10f /* end of list */ cmpwi r8,RELA bne 11f lwz r9,4(r12) /* get RELA pointer in r9 */ b 12f 11: cmpwi r8,RELASZ bne .Lcheck_for_relaent lwz r0,4(r12) /* get RELASZ value in r0 */ b 12f .Lcheck_for_relaent: cmpwi r8,RELAENT bne 12f lwz r14,4(r12) /* get RELAENT value in r14 */ 12: addi r12,r12,8 b 9b /* The relocation section contains a list of relocations. * We now do the R_PPC_RELATIVE ones, which point to words * which need to be initialized with addend + offset */ 10: /* skip relocation if we don't have both */ cmpwi r0,0 beq 3f cmpwi r9,0 beq 3f cmpwi r14,0 beq 3f add r9,r9,r11 /* Relocate RELA pointer */ divwu r0,r0,r14 /* RELASZ / RELAENT */ mtctr r0 2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ cmpwi r0,22 /* R_PPC_RELATIVE */ bne .Lnext lwz r12,0(r9) /* reloc->r_offset */ lwz r0,8(r9) /* reloc->r_addend */ add r0,r0,r11 stwx r0,r11,r12 .Lnext: add r9,r9,r14 bdnz 2b /* Do a cache flush for our text, in case the loader didn't */ 3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ lwz r8,p_etext-p_base(r10) 4: dcbf r0,r9 icbi r0,r9 addi r9,r9,0x20 cmplw cr0,r9,r8 blt 4b sync isync /* Clear the BSS */ lwz r9,p_bss_start-p_base(r10) lwz r8,p_end-p_base(r10) li r0,0 5: stw r0,0(r9) addi r9,r9,4 cmplw cr0,r9,r8 blt 5b /* Possibly set up a custom stack */ lwz r8,p_pstack-p_base(r10) cmpwi r8,0 beq 6f lwz r1,0(r8) li r0,0 stwu r0,-16(r1) /* establish a stack frame */ 6: #else /* __powerpc64__ */ /* Save the prom pointer at p_prom. */ std r5,(p_prom-p_base)(r10) /* Set r2 to the TOC. */ ld r2,(p_toc-p_base)(r10) add r2,r2,r10 /* Grab the link address of the dynamic section in r11. */ ld r11,-32768(r2) cmpwi r11,0 beq 3f /* if not linked -pie then no dynamic section */ ld r11,(p_dyn-p_base)(r10) add r11,r11,r10 ld r9,(p_rela-p_base)(r10) add r9,r9,r10 li r13,0 li r8,0 9: ld r12,0(r11) /* get tag */ cmpdi r12,0 beq 12f /* end of list */ cmpdi r12,RELA bne 10f ld r13,8(r11) /* get RELA pointer in r13 */ b 11f 10: cmpwi r12,RELASZ bne .Lcheck_for_relaent lwz r8,8(r11) /* get RELASZ pointer in r8 */ b 11f .Lcheck_for_relaent: cmpwi r12,RELAENT bne 11f lwz r14,8(r11) /* get RELAENT pointer in r14 */ 11: addi r11,r11,16 b 9b 12: cmpdi r13,0 /* check we have both RELA, RELASZ, RELAENT*/ cmpdi cr1,r8,0 beq 3f beq cr1,3f cmpdi r14,0 beq 3f /* Calcuate the runtime offset. */ subf r13,r13,r9 /* Run through the list of relocations and process the * R_PPC64_RELATIVE ones. */ divdu r8,r8,r14 /* RELASZ / RELAENT */ mtctr r8 13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ cmpdi r0,22 /* R_PPC64_RELATIVE */ bne .Lnext ld r12,0(r9) /* reloc->r_offset */ ld r0,16(r9) /* reloc->r_addend */ add r0,r0,r13 stdx r0,r13,r12 .Lnext: add r9,r9,r14 bdnz 13b /* Do a cache flush for our text, in case the loader didn't */ 3: ld r9,p_start-p_base(r10) /* note: these are relocated now */ ld r8,p_etext-p_base(r10) 4: dcbf r0,r9 icbi r0,r9 addi r9,r9,0x20 cmpld cr0,r9,r8 blt 4b sync isync /* Clear the BSS */ ld r9,p_bss_start-p_base(r10) ld r8,p_end-p_base(r10) li r0,0 5: std r0,0(r9) addi r9,r9,8 cmpld cr0,r9,r8 blt 5b /* Possibly set up a custom stack */ ld r8,p_pstack-p_base(r10) cmpdi r8,0 beq 6f ld r1,0(r8) li r0,0 stdu r0,-112(r1) /* establish a stack frame */ 6: #endif /* __powerpc64__ */ /* Call platform_init() */ bl platform_init /* Call start */ b start #ifdef __powerpc64__ #define PROM_FRAME_SIZE 512 .macro OP_REGS op, width, start, end, base, offset .Lreg=\start .rept (\end - \start + 1) \op .Lreg,\offset+\width*.Lreg(\base) .Lreg=.Lreg+1 .endr .endm #define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0 #define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0 #define SAVE_GPR(n, base) SAVE_GPRS(n, n, base) #define REST_GPR(n, base) REST_GPRS(n, n, base) /* prom handles the jump into and return from firmware. The prom args pointer is loaded in r3. */ .globl prom prom: mflr r0 std r0,16(r1) stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ SAVE_GPR(2, r1) SAVE_GPRS(13, 31, r1) mfcr r10 std r10,8*32(r1) mfmsr r10 std r10,8*33(r1) /* remove MSR_LE from msr but keep MSR_SF */ mfmsr r10 rldicr r10,r10,0,62 mtsrr1 r10 /* Load FW address, set LR to label 1, and jump to FW */ bl 0f 0: mflr r10 addi r11,r10,(1f-0b) mtlr r11 ld r10,(p_prom-0b)(r10) mtsrr0 r10 rfid 1: /* Return from OF */ FIXUP_ENDIAN /* Restore registers and return. */ rldicl r1,r1,0,32 /* Restore the MSR (back to 64 bits) */ ld r10,8*(33)(r1) mtmsr r10 isync /* Restore other registers */ REST_GPR(2, r1) REST_GPRS(13, 31, r1) ld r10,8*32(r1) mtcr r10 addi r1,r1,PROM_FRAME_SIZE ld r0,16(r1) mtlr r0 blr #endif |