Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0-or-later */
0002 /*
0003  * Copyright (C) Paul Mackerras 1997.
0004  *
0005  * Adapted for 64 bit LE PowerPC by Andrew Tauferner
0006  */
0007 
0008 #include "ppc_asm.h"
0009 
0010 RELA = 7
0011 RELASZ = 8
0012 RELAENT = 9
0013 
0014     .data
0015     /* A procedure descriptor used when booting this as a COFF file.
0016      * When making COFF, this comes first in the link and we're
0017      * linked at 0x500000.
0018      */
0019     .globl  _zimage_start_opd
0020 _zimage_start_opd:
0021     .long   0x500000, 0, 0, 0
0022     .text
0023     b   _zimage_start
0024 
0025 #ifdef __powerpc64__
0026 .balign 8
0027 p_start:    .8byte  _start
0028 p_etext:    .8byte  _etext
0029 p_bss_start:    .8byte  __bss_start
0030 p_end:      .8byte  _end
0031 
0032 p_toc:      .8byte  .TOC. - p_base
0033 p_dyn:      .8byte  __dynamic_start - p_base
0034 p_rela:     .8byte  __rela_dyn_start - p_base
0035 p_prom:     .8byte  0
0036     .weak   _platform_stack_top
0037 p_pstack:   .8byte  _platform_stack_top
0038 #else
0039 p_start:    .long   _start
0040 p_etext:    .long   _etext
0041 p_bss_start:    .long   __bss_start
0042 p_end:      .long   _end
0043 
0044     .weak   _platform_stack_top
0045 p_pstack:   .long   _platform_stack_top
0046 #endif
0047 
0048     .weak   _zimage_start
0049 _zimage_start:
0050     .globl  _zimage_start_lib
0051 _zimage_start_lib:
0052     /* Work out the offset between the address we were linked at
0053        and the address where we're running. */
0054     bl  .+4
0055 p_base: mflr    r10     /* r10 now points to runtime addr of p_base */
0056 #ifndef __powerpc64__
0057     /* grab the link address of the dynamic section in r11 */
0058     addis   r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
0059     lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
0060     cmpwi   r11,0
0061     beq 3f      /* if not linked -pie */
0062     /* get the runtime address of the dynamic section in r12 */
0063     .weak   __dynamic_start
0064     addis   r12,r10,(__dynamic_start-p_base)@ha
0065     addi    r12,r12,(__dynamic_start-p_base)@l
0066     subf    r11,r11,r12 /* runtime - linktime offset */
0067 
0068     /* The dynamic section contains a series of tagged entries.
0069      * We need the RELA and RELACOUNT entries. */
0070     li  r9,0
0071     li  r0,0
0072 9:  lwz r8,0(r12)   /* get tag */
0073     cmpwi   r8,0
0074     beq 10f     /* end of list */
0075     cmpwi   r8,RELA
0076     bne 11f
0077     lwz r9,4(r12)   /* get RELA pointer in r9 */
0078     b   12f
0079 11: cmpwi   r8,RELASZ
0080     bne .Lcheck_for_relaent
0081     lwz r0,4(r12)       /* get RELASZ value in r0 */
0082     b   12f
0083 .Lcheck_for_relaent:
0084     cmpwi   r8,RELAENT
0085     bne 12f
0086     lwz     r14,4(r12)      /* get RELAENT value in r14 */
0087 12: addi    r12,r12,8
0088     b   9b
0089 
0090     /* The relocation section contains a list of relocations.
0091      * We now do the R_PPC_RELATIVE ones, which point to words
0092      * which need to be initialized with addend + offset */
0093 10: /* skip relocation if we don't have both */
0094     cmpwi   r0,0
0095     beq 3f
0096     cmpwi   r9,0
0097     beq 3f
0098     cmpwi   r14,0
0099     beq 3f
0100 
0101     add r9,r9,r11   /* Relocate RELA pointer */
0102     divwu   r0,r0,r14       /* RELASZ / RELAENT */
0103     mtctr   r0
0104 2:  lbz r0,4+3(r9)  /* ELF32_R_INFO(reloc->r_info) */
0105     cmpwi   r0,22       /* R_PPC_RELATIVE */
0106     bne .Lnext
0107     lwz r12,0(r9)   /* reloc->r_offset */
0108     lwz r0,8(r9)    /* reloc->r_addend */
0109     add r0,r0,r11
0110     stwx    r0,r11,r12
0111 .Lnext: add r9,r9,r14
0112     bdnz    2b
0113 
0114     /* Do a cache flush for our text, in case the loader didn't */
0115 3:  lwz r9,p_start-p_base(r10)  /* note: these are relocated now */
0116     lwz r8,p_etext-p_base(r10)
0117 4:  dcbf    r0,r9
0118     icbi    r0,r9
0119     addi    r9,r9,0x20
0120     cmplw   cr0,r9,r8
0121     blt 4b
0122     sync
0123     isync
0124 
0125     /* Clear the BSS */
0126     lwz r9,p_bss_start-p_base(r10)
0127     lwz r8,p_end-p_base(r10)
0128     li  r0,0
0129 5:  stw r0,0(r9)
0130     addi    r9,r9,4
0131     cmplw   cr0,r9,r8
0132     blt 5b
0133 
0134     /* Possibly set up a custom stack */
0135     lwz r8,p_pstack-p_base(r10)
0136     cmpwi   r8,0
0137     beq 6f
0138     lwz r1,0(r8)
0139     li  r0,0
0140     stwu    r0,-16(r1)  /* establish a stack frame */
0141 6:
0142 #else /* __powerpc64__ */
0143     /* Save the prom pointer at p_prom. */
0144     std r5,(p_prom-p_base)(r10)
0145 
0146     /* Set r2 to the TOC. */
0147     ld  r2,(p_toc-p_base)(r10)
0148     add r2,r2,r10
0149 
0150     /* Grab the link address of the dynamic section in r11. */
0151     ld  r11,-32768(r2)
0152     cmpwi   r11,0
0153     beq 3f              /* if not linked -pie then no dynamic section */
0154 
0155     ld  r11,(p_dyn-p_base)(r10)
0156     add r11,r11,r10
0157     ld  r9,(p_rela-p_base)(r10)
0158     add r9,r9,r10
0159 
0160     li  r13,0
0161     li  r8,0
0162 9:  ld  r12,0(r11)       /* get tag */
0163     cmpdi   r12,0
0164     beq 12f              /* end of list */
0165     cmpdi   r12,RELA
0166     bne 10f
0167     ld  r13,8(r11)       /* get RELA pointer in r13 */
0168     b   11f
0169 10: cmpwi   r12,RELASZ
0170     bne .Lcheck_for_relaent
0171     lwz r8,8(r11)   /* get RELASZ pointer in r8 */
0172     b   11f
0173 .Lcheck_for_relaent:
0174     cmpwi   r12,RELAENT
0175     bne     11f
0176     lwz     r14,8(r11)      /* get RELAENT pointer in r14 */
0177 11: addi    r11,r11,16
0178     b   9b
0179 12:
0180     cmpdi   r13,0            /* check we have both RELA, RELASZ, RELAENT*/
0181     cmpdi   cr1,r8,0
0182     beq 3f
0183     beq cr1,3f
0184     cmpdi   r14,0
0185     beq 3f
0186 
0187     /* Calcuate the runtime offset. */
0188     subf    r13,r13,r9
0189 
0190     /* Run through the list of relocations and process the
0191      * R_PPC64_RELATIVE ones. */
0192     divdu   r8,r8,r14       /* RELASZ / RELAENT */
0193     mtctr   r8
0194 13: ld  r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
0195     cmpdi   r0,22           /* R_PPC64_RELATIVE */
0196     bne .Lnext
0197     ld  r12,0(r9)        /* reloc->r_offset */
0198     ld  r0,16(r9)       /* reloc->r_addend */
0199     add r0,r0,r13
0200     stdx    r0,r13,r12
0201 .Lnext: add r9,r9,r14
0202     bdnz    13b
0203 
0204     /* Do a cache flush for our text, in case the loader didn't */
0205 3:  ld  r9,p_start-p_base(r10)  /* note: these are relocated now */
0206     ld  r8,p_etext-p_base(r10)
0207 4:  dcbf    r0,r9
0208     icbi    r0,r9
0209     addi    r9,r9,0x20
0210     cmpld   cr0,r9,r8
0211     blt 4b
0212     sync
0213     isync
0214 
0215     /* Clear the BSS */
0216     ld  r9,p_bss_start-p_base(r10)
0217     ld  r8,p_end-p_base(r10)
0218     li  r0,0
0219 5:  std r0,0(r9)
0220     addi    r9,r9,8
0221     cmpld   cr0,r9,r8
0222     blt 5b
0223 
0224     /* Possibly set up a custom stack */
0225     ld  r8,p_pstack-p_base(r10)
0226     cmpdi   r8,0
0227     beq 6f
0228     ld  r1,0(r8)
0229     li  r0,0
0230     stdu    r0,-112(r1) /* establish a stack frame */
0231 6:
0232 #endif  /* __powerpc64__ */
0233     /* Call platform_init() */
0234     bl  platform_init
0235 
0236     /* Call start */
0237     b   start
0238 
0239 #ifdef __powerpc64__
0240 
0241 #define PROM_FRAME_SIZE 512
0242 
0243 .macro OP_REGS op, width, start, end, base, offset
0244     .Lreg=\start
0245     .rept (\end - \start + 1)
0246     \op .Lreg,\offset+\width*.Lreg(\base)
0247     .Lreg=.Lreg+1
0248     .endr
0249 .endm
0250 
0251 #define SAVE_GPRS(start, end, base) OP_REGS std, 8, start, end, base, 0
0252 #define REST_GPRS(start, end, base) OP_REGS ld, 8, start, end, base, 0
0253 #define SAVE_GPR(n, base)       SAVE_GPRS(n, n, base)
0254 #define REST_GPR(n, base)       REST_GPRS(n, n, base)
0255 
0256 /* prom handles the jump into and return from firmware.  The prom args pointer
0257    is loaded in r3. */
0258 .globl prom
0259 prom:
0260     mflr    r0
0261     std r0,16(r1)
0262     stdu    r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
0263 
0264     SAVE_GPR(2, r1)
0265     SAVE_GPRS(13, 31, r1)
0266     mfcr    r10
0267     std     r10,8*32(r1)
0268     mfmsr   r10
0269     std     r10,8*33(r1)
0270 
0271     /* remove MSR_LE from msr but keep MSR_SF */
0272     mfmsr   r10
0273     rldicr  r10,r10,0,62
0274     mtsrr1  r10
0275 
0276     /* Load FW address, set LR to label 1, and jump to FW */
0277     bl  0f
0278 0:  mflr    r10
0279     addi    r11,r10,(1f-0b)
0280     mtlr    r11
0281 
0282     ld  r10,(p_prom-0b)(r10)
0283     mtsrr0  r10
0284 
0285     rfid
0286 
0287 1:  /* Return from OF */
0288     FIXUP_ENDIAN
0289 
0290     /* Restore registers and return. */
0291     rldicl  r1,r1,0,32
0292 
0293     /* Restore the MSR (back to 64 bits) */
0294     ld      r10,8*(33)(r1)
0295     mtmsr   r10
0296     isync
0297 
0298     /* Restore other registers */
0299     REST_GPR(2, r1)
0300     REST_GPRS(13, 31, r1)
0301     ld      r10,8*32(r1)
0302     mtcr    r10
0303 
0304     addi    r1,r1,PROM_FRAME_SIZE
0305     ld      r0,16(r1)
0306     mtlr    r0
0307     blr
0308 #endif