1/* 2 * Copyright (C) Paul Mackerras 1997. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * NOTE: this code runs in 32 bit mode, is position-independent, 10 * and is packaged as ELF32. 11 */ 12 13#include "ppc_asm.h" 14 15 .text 16 /* A procedure descriptor used when booting this as a COFF file. 17 * When making COFF, this comes first in the link and we're 18 * linked at 0x500000. 19 */ 20 .globl _zimage_start_opd 21_zimage_start_opd: 22 .long 0x500000, 0, 0, 0 23 24p_start: .long _start 25p_etext: .long _etext 26p_bss_start: .long __bss_start 27p_end: .long _end 28 29 .weak _platform_stack_top 30p_pstack: .long _platform_stack_top 31 32 .weak _zimage_start 33 .globl _zimage_start 34_zimage_start: 35 .globl _zimage_start_lib 36_zimage_start_lib: 37 /* Work out the offset between the address we were linked at 38 and the address where we're running. */ 39 bl .+4 40p_base: mflr r10 /* r10 now points to runtime addr of p_base */ 41 /* grab the link address of the dynamic section in r11 */ 42 addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha 43 lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11) 44 cmpwi r11,0 45 beq 3f /* if not linked -pie */ 46 /* get the runtime address of the dynamic section in r12 */ 47 .weak __dynamic_start 48 addis r12,r10,(__dynamic_start-p_base)@ha 49 addi r12,r12,(__dynamic_start-p_base)@l 50 subf r11,r11,r12 /* runtime - linktime offset */ 51 52 /* The dynamic section contains a series of tagged entries. 53 * We need the RELA and RELACOUNT entries. */ 54RELA = 7 55RELACOUNT = 0x6ffffff9 56 li r9,0 57 li r0,0 589: lwz r8,0(r12) /* get tag */ 59 cmpwi r8,0 60 beq 10f /* end of list */ 61 cmpwi r8,RELA 62 bne 11f 63 lwz r9,4(r12) /* get RELA pointer in r9 */ 64 b 12f 6511: addis r8,r8,(-RELACOUNT)@ha 66 cmpwi r8,RELACOUNT@l 67 bne 12f 68 lwz r0,4(r12) /* get RELACOUNT value in r0 */ 6912: addi r12,r12,8 70 b 9b 71 72 /* The relocation section contains a list of relocations. 73 * We now do the R_PPC_RELATIVE ones, which point to words 74 * which need to be initialized with addend + offset. 75 * The R_PPC_RELATIVE ones come first and there are RELACOUNT 76 * of them. */ 7710: /* skip relocation if we don't have both */ 78 cmpwi r0,0 79 beq 3f 80 cmpwi r9,0 81 beq 3f 82 83 add r9,r9,r11 /* Relocate RELA pointer */ 84 mtctr r0 852: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */ 86 cmpwi r0,22 /* R_PPC_RELATIVE */ 87 bne 3f 88 lwz r12,0(r9) /* reloc->r_offset */ 89 lwz r0,8(r9) /* reloc->r_addend */ 90 add r0,r0,r11 91 stwx r0,r11,r12 92 addi r9,r9,12 93 bdnz 2b 94 95 /* Do a cache flush for our text, in case the loader didn't */ 963: lwz r9,p_start-p_base(r10) /* note: these are relocated now */ 97 lwz r8,p_etext-p_base(r10) 984: dcbf r0,r9 99 icbi r0,r9 100 addi r9,r9,0x20 101 cmplw cr0,r9,r8 102 blt 4b 103 sync 104 isync 105 106 /* Clear the BSS */ 107 lwz r9,p_bss_start-p_base(r10) 108 lwz r8,p_end-p_base(r10) 109 li r0,0 1105: stw r0,0(r9) 111 addi r9,r9,4 112 cmplw cr0,r9,r8 113 blt 5b 114 115 /* Possibly set up a custom stack */ 116 lwz r8,p_pstack-p_base(r10) 117 cmpwi r8,0 118 beq 6f 119 lwz r1,0(r8) 120 li r0,0 121 stwu r0,-16(r1) /* establish a stack frame */ 1226: 123 124 /* Call platform_init() */ 125 bl platform_init 126 127 /* Call start */ 128 b start 129 130#ifdef __powerpc64__ 131 132#define PROM_FRAME_SIZE 512 133#define SAVE_GPR(n, base) std n,8*(n)(base) 134#define REST_GPR(n, base) ld n,8*(n)(base) 135#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base) 136#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base) 137#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base) 138#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base) 139#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base) 140#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base) 141#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base) 142#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base) 143 144/* prom handles the jump into and return from firmware. The prom args pointer 145 is loaded in r3. */ 146.globl prom 147prom: 148 mflr r0 149 std r0,16(r1) 150 stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */ 151 152 SAVE_GPR(2, r1) 153 SAVE_GPR(13, r1) 154 SAVE_8GPRS(14, r1) 155 SAVE_10GPRS(22, r1) 156 mfcr r10 157 std r10,8*32(r1) 158 mfmsr r10 159 std r10,8*33(r1) 160 161 /* remove MSR_LE from msr but keep MSR_SF */ 162 mfmsr r10 163 rldicr r10,r10,0,62 164 mtsrr1 r10 165 166 /* Load FW address, set LR to label 1, and jump to FW */ 167 bl 0f 1680: mflr r10 169 addi r11,r10,(1f-0b) 170 mtlr r11 171 172 ld r10,(p_prom-0b)(r10) 173 mtsrr0 r10 174 175 rfid 176 1771: /* Return from OF */ 178 179 /* Restore registers and return. */ 180 rldicl r1,r1,0,32 181 182 /* Restore the MSR (back to 64 bits) */ 183 ld r10,8*(33)(r1) 184 mtmsr r10 185 isync 186 187 /* Restore other registers */ 188 REST_GPR(2, r1) 189 REST_GPR(13, r1) 190 REST_8GPRS(14, r1) 191 REST_10GPRS(22, r1) 192 ld r10,8*32(r1) 193 mtcr r10 194 195 addi r1,r1,PROM_FRAME_SIZE 196 ld r0,16(r1) 197 mtlr r0 198 blr 199#endif 200