/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* Copyright (C) Paul Mackerras 1997.3*4* Adapted for 64 bit LE PowerPC by Andrew Tauferner5*/67#include "ppc_asm.h"89RELA = 710RELASZ = 811RELAENT = 91213.data14/* A procedure descriptor used when booting this as a COFF file.15* When making COFF, this comes first in the link and we're16* linked at 0x500000.17*/18.globl _zimage_start_opd19_zimage_start_opd:20.long 0x500000, 0, 0, 021.text22b _zimage_start2324#ifdef __powerpc64__25.balign 826p_start: .8byte _start27p_etext: .8byte _etext28p_bss_start: .8byte __bss_start29p_end: .8byte _end3031p_toc: .8byte .TOC. - p_base32p_dyn: .8byte __dynamic_start - p_base33p_rela: .8byte __rela_dyn_start - p_base34p_prom: .8byte 035.weak _platform_stack_top36p_pstack: .8byte _platform_stack_top37#else38p_start: .long _start39p_etext: .long _etext40p_bss_start: .long __bss_start41p_end: .long _end4243.weak _platform_stack_top44p_pstack: .long _platform_stack_top45#endif4647.weak _zimage_start48_zimage_start:49.globl _zimage_start_lib50_zimage_start_lib:51/* Work out the offset between the address we were linked at52and the address where we're running. */53bcl 20,31,.+454p_base: mflr r10 /* r10 now points to runtime addr of p_base */55#ifndef __powerpc64__56/* grab the link address of the dynamic section in r11 */57addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha58lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)59cmpwi r11,060beq 3f /* if not linked -pie */61/* get the runtime address of the dynamic section in r12 */62.weak __dynamic_start63addis r12,r10,(__dynamic_start-p_base)@ha64addi r12,r12,(__dynamic_start-p_base)@l65subf r11,r11,r12 /* runtime - linktime offset */6667/* The dynamic section contains a series of tagged entries.68* We need the RELA and RELACOUNT entries. */69li r9,070li r0,0719: lwz r8,0(r12) /* get tag */72cmpwi r8,073beq 10f /* end of list */74cmpwi r8,RELA75bne 11f76lwz r9,4(r12) /* get RELA pointer in r9 */77b 12f7811: cmpwi r8,RELASZ79bne .Lcheck_for_relaent80lwz r0,4(r12) /* get RELASZ value in r0 */81b 12f82.Lcheck_for_relaent:83cmpwi r8,RELAENT84bne 12f85lwz r14,4(r12) /* get RELAENT value in r14 */8612: addi r12,r12,887b 9b8889/* The relocation section contains a list of relocations.90* We now do the R_PPC_RELATIVE ones, which point to words91* which need to be initialized with addend + offset */9210: /* skip relocation if we don't have both */93cmpwi r0,094beq 3f95cmpwi r9,096beq 3f97cmpwi r14,098beq 3f99100add r9,r9,r11 /* Relocate RELA pointer */101divwu r0,r0,r14 /* RELASZ / RELAENT */102mtctr r01032: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */104cmpwi r0,22 /* R_PPC_RELATIVE */105bne .Lnext106lwz r12,0(r9) /* reloc->r_offset */107lwz r0,8(r9) /* reloc->r_addend */108add r0,r0,r11109stwx r0,r11,r12110.Lnext: add r9,r9,r14111bdnz 2b112113/* 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 */115lwz r8,p_etext-p_base(r10)1164: dcbf r0,r9117icbi r0,r9118addi r9,r9,0x20119cmplw cr0,r9,r8120blt 4b121sync122isync123124/* Clear the BSS */125lwz r9,p_bss_start-p_base(r10)126lwz r8,p_end-p_base(r10)127li r0,01285: stw r0,0(r9)129addi r9,r9,4130cmplw cr0,r9,r8131blt 5b132133/* Possibly set up a custom stack */134lwz r8,p_pstack-p_base(r10)135cmpwi r8,0136beq 6f137lwz r1,0(r8)138li r0,0139stwu r0,-16(r1) /* establish a stack frame */1406:141#else /* __powerpc64__ */142/* Save the prom pointer at p_prom. */143std r5,(p_prom-p_base)(r10)144145/* Set r2 to the TOC. */146ld r2,(p_toc-p_base)(r10)147add r2,r2,r10148149/* Grab the link address of the dynamic section in r11. */150ld r11,-32768(r2)151cmpwi r11,0152beq 3f /* if not linked -pie then no dynamic section */153154ld r11,(p_dyn-p_base)(r10)155add r11,r11,r10156ld r9,(p_rela-p_base)(r10)157add r9,r9,r10158159li r13,0160li r8,01619: ld r12,0(r11) /* get tag */162cmpdi r12,0163beq 12f /* end of list */164cmpdi r12,RELA165bne 10f166ld r13,8(r11) /* get RELA pointer in r13 */167b 11f16810: cmpwi r12,RELASZ169bne .Lcheck_for_relaent170lwz r8,8(r11) /* get RELASZ pointer in r8 */171b 11f172.Lcheck_for_relaent:173cmpwi r12,RELAENT174bne 11f175lwz r14,8(r11) /* get RELAENT pointer in r14 */17611: addi r11,r11,16177b 9b17812:179cmpdi r13,0 /* check we have both RELA, RELASZ, RELAENT*/180cmpdi cr1,r8,0181beq 3f182beq cr1,3f183cmpdi r14,0184beq 3f185186/* Calcuate the runtime offset. */187subf r13,r13,r9188189/* Run through the list of relocations and process the190* R_PPC64_RELATIVE ones. */191divdu r8,r8,r14 /* RELASZ / RELAENT */192mtctr r819313: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */194cmpdi r0,22 /* R_PPC64_RELATIVE */195bne .Lnext196ld r12,0(r9) /* reloc->r_offset */197ld r0,16(r9) /* reloc->r_addend */198add r0,r0,r13199stdx r0,r13,r12200.Lnext: add r9,r9,r14201bdnz 13b202203/* Do a cache flush for our text, in case the loader didn't */2043: ld r9,p_start-p_base(r10) /* note: these are relocated now */205ld r8,p_etext-p_base(r10)2064: dcbf r0,r9207icbi r0,r9208addi r9,r9,0x20209cmpld cr0,r9,r8210blt 4b211sync212isync213214/* Clear the BSS */215ld r9,p_bss_start-p_base(r10)216ld r8,p_end-p_base(r10)217li r0,02185: std r0,0(r9)219addi r9,r9,8220cmpld cr0,r9,r8221blt 5b222223/* Possibly set up a custom stack */224ld r8,p_pstack-p_base(r10)225cmpdi r8,0226beq 6f227ld r1,0(r8)228li r0,0229stdu r0,-112(r1) /* establish a stack frame */2306:231#endif /* __powerpc64__ */232/* Call platform_init() */233bl platform_init234235/* Call start */236b start237238#ifdef __powerpc64__239240#define PROM_FRAME_SIZE 512241242.macro OP_REGS op, width, start, end, base, offset243.Lreg=\start244.rept (\end - \start + 1)245\op .Lreg,\offset+\width*.Lreg(\base)246.Lreg=.Lreg+1247.endr248.endm249250#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0251#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0252#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base)253#define REST_GPR(n, base) REST_GPRS(n, n, base)254255/* prom handles the jump into and return from firmware. The prom args pointer256is loaded in r3. */257.globl prom258prom:259mflr r0260std r0,16(r1)261stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */262263SAVE_GPR(2, r1)264SAVE_GPRS(13, 31, r1)265mfcr r10266std r10,8*32(r1)267mfmsr r10268std r10,8*33(r1)269270/* remove MSR_LE from msr but keep MSR_SF */271mfmsr r10272rldicr r10,r10,0,62273mtsrr1 r10274275/* Load FW address, set LR to label 1, and jump to FW */276bcl 20,31,0f2770: mflr r10278addi r11,r10,(1f-0b)279mtlr r11280281ld r10,(p_prom-0b)(r10)282mtsrr0 r10283284rfid2852861: /* Return from OF */287FIXUP_ENDIAN288289/* Restore registers and return. */290rldicl r1,r1,0,32291292/* Restore the MSR (back to 64 bits) */293ld r10,8*(33)(r1)294mtmsr r10295isync296297/* Restore other registers */298REST_GPR(2, r1)299REST_GPRS(13, 31, r1)300ld r10,8*32(r1)301mtcr r10302303addi r1,r1,PROM_FRAME_SIZE304ld r0,16(r1)305mtlr r0306blr307#endif308309310