12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */ 294b212c2SPaul Mackerras/* 394b212c2SPaul Mackerras * Copyright (C) Paul Mackerras 1997. 494b212c2SPaul Mackerras * 5f16e9684SCédric Le Goater * Adapted for 64 bit LE PowerPC by Andrew Tauferner 694b212c2SPaul Mackerras */ 794b212c2SPaul Mackerras 894b212c2SPaul Mackerras#include "ppc_asm.h" 994b212c2SPaul Mackerras 10f16e9684SCédric Le GoaterRELA = 7 11c14d31baSAlexey KardashevskiyRELASZ = 8 12c14d31baSAlexey KardashevskiyRELAENT = 9 13f16e9684SCédric Le Goater 145564597dSPaul Mackerras .data 156975a783SMichael Ellerman /* A procedure descriptor used when booting this as a COFF file. 166975a783SMichael Ellerman * When making COFF, this comes first in the link and we're 176975a783SMichael Ellerman * linked at 0x500000. 186975a783SMichael Ellerman */ 19f40e524eSPaul Mackerras .globl _zimage_start_opd 2066a45dd3SPaul Mackerras_zimage_start_opd: 216975a783SMichael Ellerman .long 0x500000, 0, 0, 0 225564597dSPaul Mackerras .text 235564597dSPaul Mackerras b _zimage_start 246975a783SMichael Ellerman 25f16e9684SCédric Le Goater#ifdef __powerpc64__ 26f16e9684SCédric Le Goater.balign 8 27eb039161STobin C. Hardingp_start: .8byte _start 28eb039161STobin C. Hardingp_etext: .8byte _etext 29eb039161STobin C. Hardingp_bss_start: .8byte __bss_start 30eb039161STobin C. Hardingp_end: .8byte _end 31f16e9684SCédric Le Goater 32a3ad84daSAlan Modrap_toc: .8byte .TOC. - p_base 33eb039161STobin C. Hardingp_dyn: .8byte __dynamic_start - p_base 34eb039161STobin C. Hardingp_rela: .8byte __rela_dyn_start - p_base 35eb039161STobin C. Hardingp_prom: .8byte 0 36f16e9684SCédric Le Goater .weak _platform_stack_top 37eb039161STobin C. Hardingp_pstack: .8byte _platform_stack_top 38f16e9684SCédric Le Goater#else 396975a783SMichael Ellermanp_start: .long _start 406975a783SMichael Ellermanp_etext: .long _etext 416975a783SMichael Ellermanp_bss_start: .long __bss_start 426975a783SMichael Ellermanp_end: .long _end 436975a783SMichael Ellerman 446975a783SMichael Ellerman .weak _platform_stack_top 456975a783SMichael Ellermanp_pstack: .long _platform_stack_top 46f16e9684SCédric Le Goater#endif 4766a45dd3SPaul Mackerras 48ee9d21b3SJoel Stanley .weak _zimage_start 4994b212c2SPaul Mackerras_zimage_start: 50160cc3ecSMilton Miller .globl _zimage_start_lib 51160cc3ecSMilton Miller_zimage_start_lib: 5266a45dd3SPaul Mackerras /* Work out the offset between the address we were linked at 5366a45dd3SPaul Mackerras and the address where we're running. */ 54*cd99dac6SNicholas Piggin bcl 20,31,.+4 556975a783SMichael Ellermanp_base: mflr r10 /* r10 now points to runtime addr of p_base */ 56f16e9684SCédric Le Goater#ifndef __powerpc64__ 576975a783SMichael Ellerman /* grab the link address of the dynamic section in r11 */ 586975a783SMichael Ellerman addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha 596975a783SMichael Ellerman lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) 606975a783SMichael Ellerman cmpwi r11,0 616975a783SMichael Ellerman beq 3f /* if not linked -pie */ 626975a783SMichael Ellerman /* get the runtime address of the dynamic section in r12 */ 636975a783SMichael Ellerman .weak __dynamic_start 646975a783SMichael Ellerman addis r12,r10,(__dynamic_start-p_base)@ha 656975a783SMichael Ellerman addi r12,r12,(__dynamic_start-p_base)@l 666975a783SMichael Ellerman subf r11,r11,r12 /* runtime - linktime offset */ 6794b212c2SPaul Mackerras 686975a783SMichael Ellerman /* The dynamic section contains a series of tagged entries. 696975a783SMichael Ellerman * We need the RELA and RELACOUNT entries. */ 706975a783SMichael Ellerman li r9,0 716975a783SMichael Ellerman li r0,0 726975a783SMichael Ellerman9: lwz r8,0(r12) /* get tag */ 736975a783SMichael Ellerman cmpwi r8,0 746975a783SMichael Ellerman beq 10f /* end of list */ 756975a783SMichael Ellerman cmpwi r8,RELA 766975a783SMichael Ellerman bne 11f 776975a783SMichael Ellerman lwz r9,4(r12) /* get RELA pointer in r9 */ 786975a783SMichael Ellerman b 12f 79c14d31baSAlexey Kardashevskiy11: cmpwi r8,RELASZ 80c14d31baSAlexey Kardashevskiy bne .Lcheck_for_relaent 81c14d31baSAlexey Kardashevskiy lwz r0,4(r12) /* get RELASZ value in r0 */ 82c14d31baSAlexey Kardashevskiy b 12f 83c14d31baSAlexey Kardashevskiy.Lcheck_for_relaent: 84c14d31baSAlexey Kardashevskiy cmpwi r8,RELAENT 856975a783SMichael Ellerman bne 12f 86c14d31baSAlexey Kardashevskiy lwz r14,4(r12) /* get RELAENT value in r14 */ 876975a783SMichael Ellerman12: addi r12,r12,8 886975a783SMichael Ellerman b 9b 896975a783SMichael Ellerman 906975a783SMichael Ellerman /* The relocation section contains a list of relocations. 916975a783SMichael Ellerman * We now do the R_PPC_RELATIVE ones, which point to words 92c14d31baSAlexey Kardashevskiy * which need to be initialized with addend + offset */ 936975a783SMichael Ellerman10: /* skip relocation if we don't have both */ 946975a783SMichael Ellerman cmpwi r0,0 9568643cfbSOlaf Hering beq 3f 966975a783SMichael Ellerman cmpwi r9,0 976975a783SMichael Ellerman beq 3f 98c14d31baSAlexey Kardashevskiy cmpwi r14,0 99c14d31baSAlexey Kardashevskiy beq 3f 1006975a783SMichael Ellerman 1016975a783SMichael Ellerman add r9,r9,r11 /* Relocate RELA pointer */ 102c14d31baSAlexey Kardashevskiy divwu r0,r0,r14 /* RELASZ / RELAENT */ 1036975a783SMichael Ellerman mtctr r0 1046975a783SMichael Ellerman2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ 1056975a783SMichael Ellerman cmpwi r0,22 /* R_PPC_RELATIVE */ 106c14d31baSAlexey Kardashevskiy bne .Lnext 1076975a783SMichael Ellerman lwz r12,0(r9) /* reloc->r_offset */ 1086975a783SMichael Ellerman lwz r0,8(r9) /* reloc->r_addend */ 1096975a783SMichael Ellerman add r0,r0,r11 1106975a783SMichael Ellerman stwx r0,r11,r12 111c14d31baSAlexey Kardashevskiy.Lnext: add r9,r9,r14 11268643cfbSOlaf Hering bdnz 2b 11394b212c2SPaul Mackerras 114cd197ffcSDavid Gibson /* Do a cache flush for our text, in case the loader didn't */ 1156975a783SMichael Ellerman3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ 1166975a783SMichael Ellerman lwz r8,p_etext-p_base(r10) 11768643cfbSOlaf Hering4: dcbf r0,r9 11894b212c2SPaul Mackerras icbi r0,r9 11994b212c2SPaul Mackerras addi r9,r9,0x20 120eacb1962SOlaf Hering cmplw cr0,r9,r8 12168643cfbSOlaf Hering blt 4b 12294b212c2SPaul Mackerras sync 12394b212c2SPaul Mackerras isync 12494b212c2SPaul Mackerras 125cd197ffcSDavid Gibson /* Clear the BSS */ 1266975a783SMichael Ellerman lwz r9,p_bss_start-p_base(r10) 1276975a783SMichael Ellerman lwz r8,p_end-p_base(r10) 1286975a783SMichael Ellerman li r0,0 1296975a783SMichael Ellerman5: stw r0,0(r9) 130cd197ffcSDavid Gibson addi r9,r9,4 131cd197ffcSDavid Gibson cmplw cr0,r9,r8 132cd197ffcSDavid Gibson blt 5b 13394b212c2SPaul Mackerras 134cd197ffcSDavid Gibson /* Possibly set up a custom stack */ 1356975a783SMichael Ellerman lwz r8,p_pstack-p_base(r10) 136cd197ffcSDavid Gibson cmpwi r8,0 137cd197ffcSDavid Gibson beq 6f 138cd197ffcSDavid Gibson lwz r1,0(r8) 139cd197ffcSDavid Gibson li r0,0 140cd197ffcSDavid Gibson stwu r0,-16(r1) /* establish a stack frame */ 141cd197ffcSDavid Gibson6: 142f16e9684SCédric Le Goater#else /* __powerpc64__ */ 143f16e9684SCédric Le Goater /* Save the prom pointer at p_prom. */ 144f16e9684SCédric Le Goater std r5,(p_prom-p_base)(r10) 145cd197ffcSDavid Gibson 146f16e9684SCédric Le Goater /* Set r2 to the TOC. */ 147f16e9684SCédric Le Goater ld r2,(p_toc-p_base)(r10) 148f16e9684SCédric Le Goater add r2,r2,r10 149f16e9684SCédric Le Goater 150f16e9684SCédric Le Goater /* Grab the link address of the dynamic section in r11. */ 151f16e9684SCédric Le Goater ld r11,-32768(r2) 152f16e9684SCédric Le Goater cmpwi r11,0 153f16e9684SCédric Le Goater beq 3f /* if not linked -pie then no dynamic section */ 154f16e9684SCédric Le Goater 155f16e9684SCédric Le Goater ld r11,(p_dyn-p_base)(r10) 156f16e9684SCédric Le Goater add r11,r11,r10 157f16e9684SCédric Le Goater ld r9,(p_rela-p_base)(r10) 158f16e9684SCédric Le Goater add r9,r9,r10 159f16e9684SCédric Le Goater 1607f664cf9SJeremy Kerr li r13,0 161f16e9684SCédric Le Goater li r8,0 1627f664cf9SJeremy Kerr9: ld r12,0(r11) /* get tag */ 1637f664cf9SJeremy Kerr cmpdi r12,0 164f16e9684SCédric Le Goater beq 12f /* end of list */ 1657f664cf9SJeremy Kerr cmpdi r12,RELA 166f16e9684SCédric Le Goater bne 10f 1677f664cf9SJeremy Kerr ld r13,8(r11) /* get RELA pointer in r13 */ 168f16e9684SCédric Le Goater b 11f 169c14d31baSAlexey Kardashevskiy10: cmpwi r12,RELASZ 170c14d31baSAlexey Kardashevskiy bne .Lcheck_for_relaent 171c14d31baSAlexey Kardashevskiy lwz r8,8(r11) /* get RELASZ pointer in r8 */ 172c14d31baSAlexey Kardashevskiy b 11f 173c14d31baSAlexey Kardashevskiy.Lcheck_for_relaent: 174c14d31baSAlexey Kardashevskiy cmpwi r12,RELAENT 175f16e9684SCédric Le Goater bne 11f 176c14d31baSAlexey Kardashevskiy lwz r14,8(r11) /* get RELAENT pointer in r14 */ 177f16e9684SCédric Le Goater11: addi r11,r11,16 178f16e9684SCédric Le Goater b 9b 179f16e9684SCédric Le Goater12: 180c14d31baSAlexey Kardashevskiy cmpdi r13,0 /* check we have both RELA, RELASZ, RELAENT*/ 181f16e9684SCédric Le Goater cmpdi cr1,r8,0 182f16e9684SCédric Le Goater beq 3f 183f16e9684SCédric Le Goater beq cr1,3f 184c14d31baSAlexey Kardashevskiy cmpdi r14,0 185c14d31baSAlexey Kardashevskiy beq 3f 186f16e9684SCédric Le Goater 187f16e9684SCédric Le Goater /* Calcuate the runtime offset. */ 1887f664cf9SJeremy Kerr subf r13,r13,r9 189f16e9684SCédric Le Goater 190f16e9684SCédric Le Goater /* Run through the list of relocations and process the 191f16e9684SCédric Le Goater * R_PPC64_RELATIVE ones. */ 192c14d31baSAlexey Kardashevskiy divdu r8,r8,r14 /* RELASZ / RELAENT */ 193f16e9684SCédric Le Goater mtctr r8 194f16e9684SCédric Le Goater13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ 195f16e9684SCédric Le Goater cmpdi r0,22 /* R_PPC64_RELATIVE */ 196c14d31baSAlexey Kardashevskiy bne .Lnext 1977f664cf9SJeremy Kerr ld r12,0(r9) /* reloc->r_offset */ 198f16e9684SCédric Le Goater ld r0,16(r9) /* reloc->r_addend */ 1997f664cf9SJeremy Kerr add r0,r0,r13 2007f664cf9SJeremy Kerr stdx r0,r13,r12 201c14d31baSAlexey Kardashevskiy.Lnext: add r9,r9,r14 202f16e9684SCédric Le Goater bdnz 13b 203f16e9684SCédric Le Goater 204f16e9684SCédric Le Goater /* Do a cache flush for our text, in case the loader didn't */ 205f16e9684SCédric Le Goater3: ld r9,p_start-p_base(r10) /* note: these are relocated now */ 206f16e9684SCédric Le Goater ld r8,p_etext-p_base(r10) 207f16e9684SCédric Le Goater4: dcbf r0,r9 208f16e9684SCédric Le Goater icbi r0,r9 209f16e9684SCédric Le Goater addi r9,r9,0x20 210f16e9684SCédric Le Goater cmpld cr0,r9,r8 211f16e9684SCédric Le Goater blt 4b 212f16e9684SCédric Le Goater sync 213f16e9684SCédric Le Goater isync 214f16e9684SCédric Le Goater 215f16e9684SCédric Le Goater /* Clear the BSS */ 216f16e9684SCédric Le Goater ld r9,p_bss_start-p_base(r10) 217f16e9684SCédric Le Goater ld r8,p_end-p_base(r10) 218f16e9684SCédric Le Goater li r0,0 219f16e9684SCédric Le Goater5: std r0,0(r9) 220f16e9684SCédric Le Goater addi r9,r9,8 221f16e9684SCédric Le Goater cmpld cr0,r9,r8 222f16e9684SCédric Le Goater blt 5b 223f16e9684SCédric Le Goater 224f16e9684SCédric Le Goater /* Possibly set up a custom stack */ 225f16e9684SCédric Le Goater ld r8,p_pstack-p_base(r10) 226f16e9684SCédric Le Goater cmpdi r8,0 227f16e9684SCédric Le Goater beq 6f 228f16e9684SCédric Le Goater ld r1,0(r8) 229f16e9684SCédric Le Goater li r0,0 2308c06f0d9SJeremy Kerr stdu r0,-112(r1) /* establish a stack frame */ 231f16e9684SCédric Le Goater6: 232f16e9684SCédric Le Goater#endif /* __powerpc64__ */ 233cd197ffcSDavid Gibson /* Call platform_init() */ 234cd197ffcSDavid Gibson bl platform_init 235cd197ffcSDavid Gibson 236cd197ffcSDavid Gibson /* Call start */ 237cd197ffcSDavid Gibson b start 23893d39210SCédric Le Goater 23993d39210SCédric Le Goater#ifdef __powerpc64__ 24093d39210SCédric Le Goater 24193d39210SCédric Le Goater#define PROM_FRAME_SIZE 512 242aebd1fb4SNicholas Piggin 243aebd1fb4SNicholas Piggin.macro OP_REGS op, width, start, end, base, offset 244aebd1fb4SNicholas Piggin .Lreg=\start 245aebd1fb4SNicholas Piggin .rept (\end - \start + 1) 246aebd1fb4SNicholas Piggin \op .Lreg,\offset+\width*.Lreg(\base) 247aebd1fb4SNicholas Piggin .Lreg=.Lreg+1 248aebd1fb4SNicholas Piggin .endr 249aebd1fb4SNicholas Piggin.endm 250aebd1fb4SNicholas Piggin 251aebd1fb4SNicholas Piggin#define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0 252aebd1fb4SNicholas Piggin#define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0 253aebd1fb4SNicholas Piggin#define SAVE_GPR(n, base) SAVE_GPRS(n, n, base) 254aebd1fb4SNicholas Piggin#define REST_GPR(n, base) REST_GPRS(n, n, base) 25593d39210SCédric Le Goater 25693d39210SCédric Le Goater/* prom handles the jump into and return from firmware. The prom args pointer 25793d39210SCédric Le Goater is loaded in r3. */ 25893d39210SCédric Le Goater.globl prom 25993d39210SCédric Le Goaterprom: 26093d39210SCédric Le Goater mflr r0 26193d39210SCédric Le Goater std r0,16(r1) 26293d39210SCédric Le Goater stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ 26393d39210SCédric Le Goater 26493d39210SCédric Le Goater SAVE_GPR(2, r1) 265aebd1fb4SNicholas Piggin SAVE_GPRS(13, 31, r1) 26693d39210SCédric Le Goater mfcr r10 26793d39210SCédric Le Goater std r10,8*32(r1) 26893d39210SCédric Le Goater mfmsr r10 26993d39210SCédric Le Goater std r10,8*33(r1) 27093d39210SCédric Le Goater 27193d39210SCédric Le Goater /* remove MSR_LE from msr but keep MSR_SF */ 27293d39210SCédric Le Goater mfmsr r10 27393d39210SCédric Le Goater rldicr r10,r10,0,62 27493d39210SCédric Le Goater mtsrr1 r10 27593d39210SCédric Le Goater 27693d39210SCédric Le Goater /* Load FW address, set LR to label 1, and jump to FW */ 277*cd99dac6SNicholas Piggin bcl 20,31,0f 27893d39210SCédric Le Goater0: mflr r10 27993d39210SCédric Le Goater addi r11,r10,(1f-0b) 28093d39210SCédric Le Goater mtlr r11 28193d39210SCédric Le Goater 28293d39210SCédric Le Goater ld r10,(p_prom-0b)(r10) 28393d39210SCédric Le Goater mtsrr0 r10 28493d39210SCédric Le Goater 28593d39210SCédric Le Goater rfid 28693d39210SCédric Le Goater 28793d39210SCédric Le Goater1: /* Return from OF */ 288147c0516SCédric Le Goater FIXUP_ENDIAN 28993d39210SCédric Le Goater 29093d39210SCédric Le Goater /* Restore registers and return. */ 29193d39210SCédric Le Goater rldicl r1,r1,0,32 29293d39210SCédric Le Goater 29393d39210SCédric Le Goater /* Restore the MSR (back to 64 bits) */ 29493d39210SCédric Le Goater ld r10,8*(33)(r1) 29593d39210SCédric Le Goater mtmsr r10 29693d39210SCédric Le Goater isync 29793d39210SCédric Le Goater 29893d39210SCédric Le Goater /* Restore other registers */ 29993d39210SCédric Le Goater REST_GPR(2, r1) 300aebd1fb4SNicholas Piggin REST_GPRS(13, 31, r1) 30193d39210SCédric Le Goater ld r10,8*32(r1) 30293d39210SCédric Le Goater mtcr r10 30393d39210SCédric Le Goater 30493d39210SCédric Le Goater addi r1,r1,PROM_FRAME_SIZE 30593d39210SCédric Le Goater ld r0,16(r1) 30693d39210SCédric Le Goater mtlr r0 30793d39210SCédric Le Goater blr 30893d39210SCédric Le Goater#endif 309