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