Linux-libre 3.2.72-gnu1
[librecmc/linux-libre.git] / arch / powerpc / boot / crt0.S
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
24 p_start:        .long   _start
25 p_etext:        .long   _etext
26 p_bss_start:    .long   __bss_start
27 p_end:          .long   _end
28
29         .weak   _platform_stack_top
30 p_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
40 p_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. */
54 RELA = 7
55 RELACOUNT = 0x6ffffff9
56         li      r9,0
57         li      r0,0
58 9:      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
65 11:     addis   r8,r8,(-RELACOUNT)@ha
66         cmpwi   r8,RELACOUNT@l
67         bne     12f
68         lwz     r0,4(r12)       /* get RELACOUNT value in r0 */
69 12:     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. */
77 10:     /* 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
85 2:      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 */
96 3:      lwz     r9,p_start-p_base(r10)  /* note: these are relocated now */
97         lwz     r8,p_etext-p_base(r10)
98 4:      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
110 5:      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 */
122 6:
123
124         /* Call platform_init() */
125         bl      platform_init
126
127         /* Call start */
128         b       start