blob: dbd99d0648287e96e18280ae253866b8d1a91fe7 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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 *
Michael Ellerman6975a782011-04-12 20:38:55 +00009 * NOTE: this code runs in 32 bit mode, is position-independent,
10 * and is packaged as ELF32.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
12
Olaf Heringdecd3002005-08-08 13:24:38 +100013#include "ppc_asm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
15 .text
Michael Ellerman6975a782011-04-12 20:38:55 +000016 /* 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 */
Paul Mackerrasf40e5242007-06-07 22:21:31 +100020 .globl _zimage_start_opd
Paul Mackerras66a45dd2006-01-14 15:04:06 +110021_zimage_start_opd:
Michael Ellerman6975a782011-04-12 20:38:55 +000022 .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
Paul Mackerras66a45dd2006-01-14 15:04:06 +110031
David Gibsoncd197ff2007-03-05 14:24:52 +110032 .weak _zimage_start
Olaf Hering67a1b682005-10-28 17:46:49 -070033 .globl _zimage_start
34_zimage_start:
Milton Miller160cc3e2007-03-21 09:02:53 -060035 .globl _zimage_start_lib
36_zimage_start_lib:
Paul Mackerras66a45dd2006-01-14 15:04:06 +110037 /* Work out the offset between the address we were linked at
38 and the address where we're running. */
Michael Ellerman6975a782011-04-12 20:38:55 +000039 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 */
Olaf Heringa4497232005-10-28 17:46:48 -070051
Michael Ellerman6975a782011-04-12 20:38:55 +000052 /* 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
Olaf Hering68643cf2005-11-17 22:09:02 +010079 beq 3f
Michael Ellerman6975a782011-04-12 20:38:55 +000080 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
Olaf Hering68643cf2005-11-17 22:09:02 +010093 bdnz 2b
Olaf Heringa4497232005-10-28 17:46:48 -070094
David Gibsoncd197ff2007-03-05 14:24:52 +110095 /* Do a cache flush for our text, in case the loader didn't */
Michael Ellerman6975a782011-04-12 20:38:55 +0000963: lwz r9,p_start-p_base(r10) /* note: these are relocated now */
97 lwz r8,p_etext-p_base(r10)
Olaf Hering68643cf2005-11-17 22:09:02 +0100984: dcbf r0,r9
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 icbi r0,r9
100 addi r9,r9,0x20
Olaf Heringeacb1962006-03-04 13:15:40 +0100101 cmplw cr0,r9,r8
Olaf Hering68643cf2005-11-17 22:09:02 +0100102 blt 4b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 sync
104 isync
105
David Gibsoncd197ff2007-03-05 14:24:52 +1100106 /* Clear the BSS */
Michael Ellerman6975a782011-04-12 20:38:55 +0000107 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)
David Gibsoncd197ff2007-03-05 14:24:52 +1100111 addi r9,r9,4
112 cmplw cr0,r9,r8
113 blt 5b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
David Gibsoncd197ff2007-03-05 14:24:52 +1100115 /* Possibly set up a custom stack */
Michael Ellerman6975a782011-04-12 20:38:55 +0000116 lwz r8,p_pstack-p_base(r10)
David Gibsoncd197ff2007-03-05 14:24:52 +1100117 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 */
David Gibsoncd197ff2007-03-05 14:24:52 +1100128 b start
Cédric Le Goater93d39212014-04-24 09:23:36 +0200129
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