linux/arch/powerpc/boot/crt0.S
<<
>>
Prefs
   1/*
   2 * Copyright (C) Paul Mackerras 1997.
   3 *
   4 * Adapted for 64 bit LE PowerPC by Andrew Tauferner
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 *
  11 */
  12
  13#include "ppc_asm.h"
  14
  15RELA = 7
  16RELACOUNT = 0x6ffffff9
  17
  18        .text
  19        /* A procedure descriptor used when booting this as a COFF file.
  20         * When making COFF, this comes first in the link and we're
  21         * linked at 0x500000.
  22         */
  23        .globl  _zimage_start_opd
  24_zimage_start_opd:
  25        .long   0x500000, 0, 0, 0
  26
  27#ifdef __powerpc64__
  28.balign 8
  29p_start:        .llong  _start
  30p_etext:        .llong  _etext
  31p_bss_start:    .llong  __bss_start
  32p_end:          .llong  _end
  33
  34p_toc:          .llong  __toc_start + 0x8000 - p_base
  35p_dyn:          .llong  __dynamic_start - p_base
  36p_rela:         .llong  __rela_dyn_start - p_base
  37p_prom:         .llong  0
  38        .weak   _platform_stack_top
  39p_pstack:       .llong  _platform_stack_top
  40#else
  41p_start:        .long   _start
  42p_etext:        .long   _etext
  43p_bss_start:    .long   __bss_start
  44p_end:          .long   _end
  45
  46        .weak   _platform_stack_top
  47p_pstack:       .long   _platform_stack_top
  48#endif
  49
  50        .weak   _zimage_start
  51        .globl  _zimage_start
  52_zimage_start:
  53        .globl  _zimage_start_lib
  54_zimage_start_lib:
  55        /* Work out the offset between the address we were linked at
  56           and the address where we're running. */
  57        bl      .+4
  58p_base: mflr    r10             /* r10 now points to runtime addr of p_base */
  59#ifndef __powerpc64__
  60        /* grab the link address of the dynamic section in r11 */
  61        addis   r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
  62        lwz     r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
  63        cmpwi   r11,0
  64        beq     3f              /* if not linked -pie */
  65        /* get the runtime address of the dynamic section in r12 */
  66        .weak   __dynamic_start
  67        addis   r12,r10,(__dynamic_start-p_base)@ha
  68        addi    r12,r12,(__dynamic_start-p_base)@l
  69        subf    r11,r11,r12     /* runtime - linktime offset */
  70
  71        /* The dynamic section contains a series of tagged entries.
  72         * We need the RELA and RELACOUNT entries. */
  73        li      r9,0
  74        li      r0,0
  759:      lwz     r8,0(r12)       /* get tag */
  76        cmpwi   r8,0
  77        beq     10f             /* end of list */
  78        cmpwi   r8,RELA
  79        bne     11f
  80        lwz     r9,4(r12)       /* get RELA pointer in r9 */
  81        b       12f
  8211:     addis   r8,r8,(-RELACOUNT)@ha
  83        cmpwi   r8,RELACOUNT@l
  84        bne     12f
  85        lwz     r0,4(r12)       /* get RELACOUNT value in r0 */
  8612:     addi    r12,r12,8
  87        b       9b
  88
  89        /* The relocation section contains a list of relocations.
  90         * We now do the R_PPC_RELATIVE ones, which point to words
  91         * which need to be initialized with addend + offset.
  92         * The R_PPC_RELATIVE ones come first and there are RELACOUNT
  93         * of them. */
  9410:     /* skip relocation if we don't have both */
  95        cmpwi   r0,0
  96        beq     3f
  97        cmpwi   r9,0
  98        beq     3f
  99
 100        add     r9,r9,r11       /* Relocate RELA pointer */
 101        mtctr   r0
 1022:      lbz     r0,4+3(r9)      /* ELF32_R_INFO(reloc->r_info) */
 103        cmpwi   r0,22           /* R_PPC_RELATIVE */
 104        bne     3f
 105        lwz     r12,0(r9)       /* reloc->r_offset */
 106        lwz     r0,8(r9)        /* reloc->r_addend */
 107        add     r0,r0,r11
 108        stwx    r0,r11,r12
 109        addi    r9,r9,12
 110        bdnz    2b
 111
 112        /* Do a cache flush for our text, in case the loader didn't */
 1133:      lwz     r9,p_start-p_base(r10)  /* note: these are relocated now */
 114        lwz     r8,p_etext-p_base(r10)
 1154:      dcbf    r0,r9
 116        icbi    r0,r9
 117        addi    r9,r9,0x20
 118        cmplw   cr0,r9,r8
 119        blt     4b
 120        sync
 121        isync
 122
 123        /* Clear the BSS */
 124        lwz     r9,p_bss_start-p_base(r10)
 125        lwz     r8,p_end-p_base(r10)
 126        li      r0,0
 1275:      stw     r0,0(r9)
 128        addi    r9,r9,4
 129        cmplw   cr0,r9,r8
 130        blt     5b
 131
 132        /* Possibly set up a custom stack */
 133        lwz     r8,p_pstack-p_base(r10)
 134        cmpwi   r8,0
 135        beq     6f
 136        lwz     r1,0(r8)
 137        li      r0,0
 138        stwu    r0,-16(r1)      /* establish a stack frame */
 1396:
 140#else /* __powerpc64__ */
 141        /* Save the prom pointer at p_prom. */
 142        std     r5,(p_prom-p_base)(r10)
 143
 144        /* Set r2 to the TOC. */
 145        ld      r2,(p_toc-p_base)(r10)
 146        add     r2,r2,r10
 147
 148        /* Grab the link address of the dynamic section in r11. */
 149        ld      r11,-32768(r2)
 150        cmpwi   r11,0
 151        beq     3f              /* if not linked -pie then no dynamic section */
 152
 153        ld      r11,(p_dyn-p_base)(r10)
 154        add     r11,r11,r10
 155        ld      r9,(p_rela-p_base)(r10)
 156        add     r9,r9,r10
 157
 158        li      r13,0
 159        li      r8,0
 1609:      ld      r12,0(r11)       /* get tag */
 161        cmpdi   r12,0
 162        beq     12f              /* end of list */
 163        cmpdi   r12,RELA
 164        bne     10f
 165        ld      r13,8(r11)       /* get RELA pointer in r13 */
 166        b       11f
 16710:     addis   r12,r12,(-RELACOUNT)@ha
 168        cmpdi   r12,RELACOUNT@l
 169        bne     11f
 170        ld      r8,8(r11)       /* get RELACOUNT value in r8 */
 17111:     addi    r11,r11,16
 172        b       9b
 17312:
 174        cmpdi   r13,0            /* check we have both RELA and RELACOUNT */
 175        cmpdi   cr1,r8,0
 176        beq     3f
 177        beq     cr1,3f
 178
 179        /* Calcuate the runtime offset. */
 180        subf    r13,r13,r9
 181
 182        /* Run through the list of relocations and process the
 183         * R_PPC64_RELATIVE ones. */
 184        mtctr   r8
 18513:     ld      r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
 186        cmpdi   r0,22           /* R_PPC64_RELATIVE */
 187        bne     3f
 188        ld      r12,0(r9)        /* reloc->r_offset */
 189        ld      r0,16(r9)       /* reloc->r_addend */
 190        add     r0,r0,r13
 191        stdx    r0,r13,r12
 192        addi    r9,r9,24
 193        bdnz    13b
 194
 195        /* Do a cache flush for our text, in case the loader didn't */
 1963:      ld      r9,p_start-p_base(r10)  /* note: these are relocated now */
 197        ld      r8,p_etext-p_base(r10)
 1984:      dcbf    r0,r9
 199        icbi    r0,r9
 200        addi    r9,r9,0x20
 201        cmpld   cr0,r9,r8
 202        blt     4b
 203        sync
 204        isync
 205
 206        /* Clear the BSS */
 207        ld      r9,p_bss_start-p_base(r10)
 208        ld      r8,p_end-p_base(r10)
 209        li      r0,0
 2105:      std     r0,0(r9)
 211        addi    r9,r9,8
 212        cmpld   cr0,r9,r8
 213        blt     5b
 214
 215        /* Possibly set up a custom stack */
 216        ld      r8,p_pstack-p_base(r10)
 217        cmpdi   r8,0
 218        beq     6f
 219        ld      r1,0(r8)
 220        li      r0,0
 221        stdu    r0,-112(r1)     /* establish a stack frame */
 2226:
 223#endif  /* __powerpc64__ */
 224        /* Call platform_init() */
 225        bl      platform_init
 226
 227        /* Call start */
 228        b       start
 229
 230#ifdef __powerpc64__
 231
 232#define PROM_FRAME_SIZE 512
 233#define SAVE_GPR(n, base)       std     n,8*(n)(base)
 234#define REST_GPR(n, base)       ld      n,8*(n)(base)
 235#define SAVE_2GPRS(n, base)     SAVE_GPR(n, base); SAVE_GPR(n+1, base)
 236#define SAVE_4GPRS(n, base)     SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
 237#define SAVE_8GPRS(n, base)     SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
 238#define SAVE_10GPRS(n, base)    SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
 239#define REST_2GPRS(n, base)     REST_GPR(n, base); REST_GPR(n+1, base)
 240#define REST_4GPRS(n, base)     REST_2GPRS(n, base); REST_2GPRS(n+2, base)
 241#define REST_8GPRS(n, base)     REST_4GPRS(n, base); REST_4GPRS(n+4, base)
 242#define REST_10GPRS(n, base)    REST_8GPRS(n, base); REST_2GPRS(n+8, base)
 243
 244/* prom handles the jump into and return from firmware.  The prom args pointer
 245   is loaded in r3. */
 246.globl prom
 247prom:
 248        mflr    r0
 249        std     r0,16(r1)
 250        stdu    r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
 251
 252        SAVE_GPR(2, r1)
 253        SAVE_GPR(13, r1)
 254        SAVE_8GPRS(14, r1)
 255        SAVE_10GPRS(22, r1)
 256        mfcr    r10
 257        std     r10,8*32(r1)
 258        mfmsr   r10
 259        std     r10,8*33(r1)
 260
 261        /* remove MSR_LE from msr but keep MSR_SF */
 262        mfmsr   r10
 263        rldicr  r10,r10,0,62
 264        mtsrr1  r10
 265
 266        /* Load FW address, set LR to label 1, and jump to FW */
 267        bl      0f
 2680:      mflr    r10
 269        addi    r11,r10,(1f-0b)
 270        mtlr    r11
 271
 272        ld      r10,(p_prom-0b)(r10)
 273        mtsrr0  r10
 274
 275        rfid
 276
 2771:      /* Return from OF */
 278        FIXUP_ENDIAN
 279
 280        /* Restore registers and return. */
 281        rldicl  r1,r1,0,32
 282
 283        /* Restore the MSR (back to 64 bits) */
 284        ld      r10,8*(33)(r1)
 285        mtmsr   r10
 286        isync
 287
 288        /* Restore other registers */
 289        REST_GPR(2, r1)
 290        REST_GPR(13, r1)
 291        REST_8GPRS(14, r1)
 292        REST_10GPRS(22, r1)
 293        ld      r10,8*32(r1)
 294        mtcr    r10
 295
 296        addi    r1,r1,PROM_FRAME_SIZE
 297        ld      r0,16(r1)
 298        mtlr    r0
 299        blr
 300#endif
 301