root/arch/powerpc/boot/crt0.S

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

/* [<][>][^][v][top][bottom][index][help] */