/* 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. */ bcl 20,31,.+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 */ bcl 20,31,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