194b212c2SPaul Mackerras/* 294b212c2SPaul Mackerras * Copyright (C) Paul Mackerras 1997. 394b212c2SPaul Mackerras * 4f16e9684SCédric Le Goater * Adapted for 64 bit LE PowerPC by Andrew Tauferner 5f16e9684SCédric Le Goater * 694b212c2SPaul Mackerras * This program is free software; you can redistribute it and/or 794b212c2SPaul Mackerras * modify it under the terms of the GNU General Public License 894b212c2SPaul Mackerras * as published by the Free Software Foundation; either version 994b212c2SPaul Mackerras * 2 of the License, or (at your option) any later version. 1094b212c2SPaul Mackerras * 1194b212c2SPaul Mackerras */ 1294b212c2SPaul Mackerras 1394b212c2SPaul Mackerras#include "ppc_asm.h" 1494b212c2SPaul Mackerras 15f16e9684SCédric Le GoaterRELA = 7 16f16e9684SCédric Le GoaterRELACOUNT = 0x6ffffff9 17f16e9684SCédric Le Goater 1894b212c2SPaul Mackerras .text 196975a783SMichael Ellerman /* A procedure descriptor used when booting this as a COFF file. 206975a783SMichael Ellerman * When making COFF, this comes first in the link and we're 216975a783SMichael Ellerman * linked at 0x500000. 226975a783SMichael Ellerman */ 23f40e524eSPaul Mackerras .globl _zimage_start_opd 2466a45dd3SPaul Mackerras_zimage_start_opd: 256975a783SMichael Ellerman .long 0x500000, 0, 0, 0 266975a783SMichael Ellerman 27f16e9684SCédric Le Goater#ifdef __powerpc64__ 28f16e9684SCédric Le Goater.balign 8 29eb039161STobin C. Hardingp_start: .8byte _start 30eb039161STobin C. Hardingp_etext: .8byte _etext 31eb039161STobin C. Hardingp_bss_start: .8byte __bss_start 32eb039161STobin C. Hardingp_end: .8byte _end 33f16e9684SCédric Le Goater 34eb039161STobin C. Hardingp_toc: .8byte __toc_start + 0x8000 - p_base 35eb039161STobin C. Hardingp_dyn: .8byte __dynamic_start - p_base 36eb039161STobin C. Hardingp_rela: .8byte __rela_dyn_start - p_base 37eb039161STobin C. Hardingp_prom: .8byte 0 38f16e9684SCédric Le Goater .weak _platform_stack_top 39eb039161STobin C. Hardingp_pstack: .8byte _platform_stack_top 40f16e9684SCédric Le Goater#else 416975a783SMichael Ellermanp_start: .long _start 426975a783SMichael Ellermanp_etext: .long _etext 436975a783SMichael Ellermanp_bss_start: .long __bss_start 446975a783SMichael Ellermanp_end: .long _end 456975a783SMichael Ellerman 466975a783SMichael Ellerman .weak _platform_stack_top 476975a783SMichael Ellermanp_pstack: .long _platform_stack_top 48f16e9684SCédric Le Goater#endif 4966a45dd3SPaul Mackerras 50cd197ffcSDavid Gibson .weak _zimage_start 5194b212c2SPaul Mackerras .globl _zimage_start 5294b212c2SPaul Mackerras_zimage_start: 53160cc3ecSMilton Miller .globl _zimage_start_lib 54160cc3ecSMilton Miller_zimage_start_lib: 5566a45dd3SPaul Mackerras /* Work out the offset between the address we were linked at 5666a45dd3SPaul Mackerras and the address where we're running. */ 576975a783SMichael Ellerman bl .+4 586975a783SMichael Ellermanp_base: mflr r10 /* r10 now points to runtime addr of p_base */ 59f16e9684SCédric Le Goater#ifndef __powerpc64__ 606975a783SMichael Ellerman /* grab the link address of the dynamic section in r11 */ 616975a783SMichael Ellerman addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha 626975a783SMichael Ellerman lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) 636975a783SMichael Ellerman cmpwi r11,0 646975a783SMichael Ellerman beq 3f /* if not linked -pie */ 656975a783SMichael Ellerman /* get the runtime address of the dynamic section in r12 */ 666975a783SMichael Ellerman .weak __dynamic_start 676975a783SMichael Ellerman addis r12,r10,(__dynamic_start-p_base)@ha 686975a783SMichael Ellerman addi r12,r12,(__dynamic_start-p_base)@l 696975a783SMichael Ellerman subf r11,r11,r12 /* runtime - linktime offset */ 7094b212c2SPaul Mackerras 716975a783SMichael Ellerman /* The dynamic section contains a series of tagged entries. 726975a783SMichael Ellerman * We need the RELA and RELACOUNT entries. */ 736975a783SMichael Ellerman li r9,0 746975a783SMichael Ellerman li r0,0 756975a783SMichael Ellerman9: lwz r8,0(r12) /* get tag */ 766975a783SMichael Ellerman cmpwi r8,0 776975a783SMichael Ellerman beq 10f /* end of list */ 786975a783SMichael Ellerman cmpwi r8,RELA 796975a783SMichael Ellerman bne 11f 806975a783SMichael Ellerman lwz r9,4(r12) /* get RELA pointer in r9 */ 816975a783SMichael Ellerman b 12f 826975a783SMichael Ellerman11: addis r8,r8,(-RELACOUNT)@ha 836975a783SMichael Ellerman cmpwi r8,RELACOUNT@l 846975a783SMichael Ellerman bne 12f 856975a783SMichael Ellerman lwz r0,4(r12) /* get RELACOUNT value in r0 */ 866975a783SMichael Ellerman12: addi r12,r12,8 876975a783SMichael Ellerman b 9b 886975a783SMichael Ellerman 896975a783SMichael Ellerman /* The relocation section contains a list of relocations. 906975a783SMichael Ellerman * We now do the R_PPC_RELATIVE ones, which point to words 916975a783SMichael Ellerman * which need to be initialized with addend + offset. 926975a783SMichael Ellerman * The R_PPC_RELATIVE ones come first and there are RELACOUNT 936975a783SMichael Ellerman * of them. */ 946975a783SMichael Ellerman10: /* skip relocation if we don't have both */ 956975a783SMichael Ellerman cmpwi r0,0 9668643cfbSOlaf Hering beq 3f 976975a783SMichael Ellerman cmpwi r9,0 986975a783SMichael Ellerman beq 3f 996975a783SMichael Ellerman 1006975a783SMichael Ellerman add r9,r9,r11 /* Relocate RELA pointer */ 1016975a783SMichael Ellerman mtctr r0 1026975a783SMichael Ellerman2: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ 1036975a783SMichael Ellerman cmpwi r0,22 /* R_PPC_RELATIVE */ 1046975a783SMichael Ellerman bne 3f 1056975a783SMichael Ellerman lwz r12,0(r9) /* reloc->r_offset */ 1066975a783SMichael Ellerman lwz r0,8(r9) /* reloc->r_addend */ 1076975a783SMichael Ellerman add r0,r0,r11 1086975a783SMichael Ellerman stwx r0,r11,r12 1096975a783SMichael Ellerman addi r9,r9,12 11068643cfbSOlaf Hering bdnz 2b 11194b212c2SPaul Mackerras 112cd197ffcSDavid Gibson /* Do a cache flush for our text, in case the loader didn't */ 1136975a783SMichael Ellerman3: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ 1146975a783SMichael Ellerman lwz r8,p_etext-p_base(r10) 11568643cfbSOlaf Hering4: dcbf r0,r9 11694b212c2SPaul Mackerras icbi r0,r9 11794b212c2SPaul Mackerras addi r9,r9,0x20 118eacb1962SOlaf Hering cmplw cr0,r9,r8 11968643cfbSOlaf Hering blt 4b 12094b212c2SPaul Mackerras sync 12194b212c2SPaul Mackerras isync 12294b212c2SPaul Mackerras 123cd197ffcSDavid Gibson /* Clear the BSS */ 1246975a783SMichael Ellerman lwz r9,p_bss_start-p_base(r10) 1256975a783SMichael Ellerman lwz r8,p_end-p_base(r10) 1266975a783SMichael Ellerman li r0,0 1276975a783SMichael Ellerman5: stw r0,0(r9) 128cd197ffcSDavid Gibson addi r9,r9,4 129cd197ffcSDavid Gibson cmplw cr0,r9,r8 130cd197ffcSDavid Gibson blt 5b 13194b212c2SPaul Mackerras 132cd197ffcSDavid Gibson /* Possibly set up a custom stack */ 1336975a783SMichael Ellerman lwz r8,p_pstack-p_base(r10) 134cd197ffcSDavid Gibson cmpwi r8,0 135cd197ffcSDavid Gibson beq 6f 136cd197ffcSDavid Gibson lwz r1,0(r8) 137cd197ffcSDavid Gibson li r0,0 138cd197ffcSDavid Gibson stwu r0,-16(r1) /* establish a stack frame */ 139cd197ffcSDavid Gibson6: 140f16e9684SCédric Le Goater#else /* __powerpc64__ */ 141f16e9684SCédric Le Goater /* Save the prom pointer at p_prom. */ 142f16e9684SCédric Le Goater std r5,(p_prom-p_base)(r10) 143cd197ffcSDavid Gibson 144f16e9684SCédric Le Goater /* Set r2 to the TOC. */ 145f16e9684SCédric Le Goater ld r2,(p_toc-p_base)(r10) 146f16e9684SCédric Le Goater add r2,r2,r10 147f16e9684SCédric Le Goater 148f16e9684SCédric Le Goater /* Grab the link address of the dynamic section in r11. */ 149f16e9684SCédric Le Goater ld r11,-32768(r2) 150f16e9684SCédric Le Goater cmpwi r11,0 151f16e9684SCédric Le Goater beq 3f /* if not linked -pie then no dynamic section */ 152f16e9684SCédric Le Goater 153f16e9684SCédric Le Goater ld r11,(p_dyn-p_base)(r10) 154f16e9684SCédric Le Goater add r11,r11,r10 155f16e9684SCédric Le Goater ld r9,(p_rela-p_base)(r10) 156f16e9684SCédric Le Goater add r9,r9,r10 157f16e9684SCédric Le Goater 1587f664cf9SJeremy Kerr li r13,0 159f16e9684SCédric Le Goater li r8,0 1607f664cf9SJeremy Kerr9: ld r12,0(r11) /* get tag */ 1617f664cf9SJeremy Kerr cmpdi r12,0 162f16e9684SCédric Le Goater beq 12f /* end of list */ 1637f664cf9SJeremy Kerr cmpdi r12,RELA 164f16e9684SCédric Le Goater bne 10f 1657f664cf9SJeremy Kerr ld r13,8(r11) /* get RELA pointer in r13 */ 166f16e9684SCédric Le Goater b 11f 1677f664cf9SJeremy Kerr10: addis r12,r12,(-RELACOUNT)@ha 1687f664cf9SJeremy Kerr cmpdi r12,RELACOUNT@l 169f16e9684SCédric Le Goater bne 11f 170f16e9684SCédric Le Goater ld r8,8(r11) /* get RELACOUNT value in r8 */ 171f16e9684SCédric Le Goater11: addi r11,r11,16 172f16e9684SCédric Le Goater b 9b 173f16e9684SCédric Le Goater12: 1747f664cf9SJeremy Kerr cmpdi r13,0 /* check we have both RELA and RELACOUNT */ 175f16e9684SCédric Le Goater cmpdi cr1,r8,0 176f16e9684SCédric Le Goater beq 3f 177f16e9684SCédric Le Goater beq cr1,3f 178f16e9684SCédric Le Goater 179f16e9684SCédric Le Goater /* Calcuate the runtime offset. */ 1807f664cf9SJeremy Kerr subf r13,r13,r9 181f16e9684SCédric Le Goater 182f16e9684SCédric Le Goater /* Run through the list of relocations and process the 183f16e9684SCédric Le Goater * R_PPC64_RELATIVE ones. */ 184f16e9684SCédric Le Goater mtctr r8 185f16e9684SCédric Le Goater13: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */ 186f16e9684SCédric Le Goater cmpdi r0,22 /* R_PPC64_RELATIVE */ 187f16e9684SCédric Le Goater bne 3f 1887f664cf9SJeremy Kerr ld r12,0(r9) /* reloc->r_offset */ 189f16e9684SCédric Le Goater ld r0,16(r9) /* reloc->r_addend */ 1907f664cf9SJeremy Kerr add r0,r0,r13 1917f664cf9SJeremy Kerr stdx r0,r13,r12 192f16e9684SCédric Le Goater addi r9,r9,24 193f16e9684SCédric Le Goater bdnz 13b 194f16e9684SCédric Le Goater 195f16e9684SCédric Le Goater /* Do a cache flush for our text, in case the loader didn't */ 196f16e9684SCédric Le Goater3: ld r9,p_start-p_base(r10) /* note: these are relocated now */ 197f16e9684SCédric Le Goater ld r8,p_etext-p_base(r10) 198f16e9684SCédric Le Goater4: dcbf r0,r9 199f16e9684SCédric Le Goater icbi r0,r9 200f16e9684SCédric Le Goater addi r9,r9,0x20 201f16e9684SCédric Le Goater cmpld cr0,r9,r8 202f16e9684SCédric Le Goater blt 4b 203f16e9684SCédric Le Goater sync 204f16e9684SCédric Le Goater isync 205f16e9684SCédric Le Goater 206f16e9684SCédric Le Goater /* Clear the BSS */ 207f16e9684SCédric Le Goater ld r9,p_bss_start-p_base(r10) 208f16e9684SCédric Le Goater ld r8,p_end-p_base(r10) 209f16e9684SCédric Le Goater li r0,0 210f16e9684SCédric Le Goater5: std r0,0(r9) 211f16e9684SCédric Le Goater addi r9,r9,8 212f16e9684SCédric Le Goater cmpld cr0,r9,r8 213f16e9684SCédric Le Goater blt 5b 214f16e9684SCédric Le Goater 215f16e9684SCédric Le Goater /* Possibly set up a custom stack */ 216f16e9684SCédric Le Goater ld r8,p_pstack-p_base(r10) 217f16e9684SCédric Le Goater cmpdi r8,0 218f16e9684SCédric Le Goater beq 6f 219f16e9684SCédric Le Goater ld r1,0(r8) 220f16e9684SCédric Le Goater li r0,0 2218c06f0d9SJeremy Kerr stdu r0,-112(r1) /* establish a stack frame */ 222f16e9684SCédric Le Goater6: 223f16e9684SCédric Le Goater#endif /* __powerpc64__ */ 224cd197ffcSDavid Gibson /* Call platform_init() */ 225cd197ffcSDavid Gibson bl platform_init 226cd197ffcSDavid Gibson 227cd197ffcSDavid Gibson /* Call start */ 228cd197ffcSDavid Gibson b start 22993d39210SCédric Le Goater 23093d39210SCédric Le Goater#ifdef __powerpc64__ 23193d39210SCédric Le Goater 23293d39210SCédric Le Goater#define PROM_FRAME_SIZE 512 23393d39210SCédric Le Goater#define SAVE_GPR(n, base) std n,8*(n)(base) 23493d39210SCédric Le Goater#define REST_GPR(n, base) ld n,8*(n)(base) 23593d39210SCédric Le Goater#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) 23693d39210SCédric Le Goater#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) 23793d39210SCédric Le Goater#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) 23893d39210SCédric Le Goater#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) 23993d39210SCédric Le Goater#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) 24093d39210SCédric Le Goater#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) 24193d39210SCédric Le Goater#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) 24293d39210SCédric Le Goater#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) 24393d39210SCédric Le Goater 24493d39210SCédric Le Goater/* prom handles the jump into and return from firmware. The prom args pointer 24593d39210SCédric Le Goater is loaded in r3. */ 24693d39210SCédric Le Goater.globl prom 24793d39210SCédric Le Goaterprom: 24893d39210SCédric Le Goater mflr r0 24993d39210SCédric Le Goater std r0,16(r1) 25093d39210SCédric Le Goater stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ 25193d39210SCédric Le Goater 25293d39210SCédric Le Goater SAVE_GPR(2, r1) 25393d39210SCédric Le Goater SAVE_GPR(13, r1) 25493d39210SCédric Le Goater SAVE_8GPRS(14, r1) 25593d39210SCédric Le Goater SAVE_10GPRS(22, r1) 25693d39210SCédric Le Goater mfcr r10 25793d39210SCédric Le Goater std r10,8*32(r1) 25893d39210SCédric Le Goater mfmsr r10 25993d39210SCédric Le Goater std r10,8*33(r1) 26093d39210SCédric Le Goater 26193d39210SCédric Le Goater /* remove MSR_LE from msr but keep MSR_SF */ 26293d39210SCédric Le Goater mfmsr r10 26393d39210SCédric Le Goater rldicr r10,r10,0,62 26493d39210SCédric Le Goater mtsrr1 r10 26593d39210SCédric Le Goater 26693d39210SCédric Le Goater /* Load FW address, set LR to label 1, and jump to FW */ 26793d39210SCédric Le Goater bl 0f 26893d39210SCédric Le Goater0: mflr r10 26993d39210SCédric Le Goater addi r11,r10,(1f-0b) 27093d39210SCédric Le Goater mtlr r11 27193d39210SCédric Le Goater 27293d39210SCédric Le Goater ld r10,(p_prom-0b)(r10) 27393d39210SCédric Le Goater mtsrr0 r10 27493d39210SCédric Le Goater 27593d39210SCédric Le Goater rfid 27693d39210SCédric Le Goater 27793d39210SCédric Le Goater1: /* Return from OF */ 278147c0516SCédric Le Goater FIXUP_ENDIAN 27993d39210SCédric Le Goater 28093d39210SCédric Le Goater /* Restore registers and return. */ 28193d39210SCédric Le Goater rldicl r1,r1,0,32 28293d39210SCédric Le Goater 28393d39210SCédric Le Goater /* Restore the MSR (back to 64 bits) */ 28493d39210SCédric Le Goater ld r10,8*(33)(r1) 28593d39210SCédric Le Goater mtmsr r10 28693d39210SCédric Le Goater isync 28793d39210SCédric Le Goater 28893d39210SCédric Le Goater /* Restore other registers */ 28993d39210SCédric Le Goater REST_GPR(2, r1) 29093d39210SCédric Le Goater REST_GPR(13, r1) 29193d39210SCédric Le Goater REST_8GPRS(14, r1) 29293d39210SCédric Le Goater REST_10GPRS(22, r1) 29393d39210SCédric Le Goater ld r10,8*32(r1) 29493d39210SCédric Le Goater mtcr r10 29593d39210SCédric Le Goater 29693d39210SCédric Le Goater addi r1,r1,PROM_FRAME_SIZE 29793d39210SCédric Le Goater ld r0,16(r1) 29893d39210SCédric Le Goater mtlr r0 29993d39210SCédric Le Goater blr 30093d39210SCédric Le Goater#endif 301