blob: 32dfe6d083f3257c41b8e0de835eff8ccd16491c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
Cédric Le Goaterf16e9682014-04-24 09:23:37 +02004 * Adapted for 64 bit LE PowerPC by Andrew Tauferner
5 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 * 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 *
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
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020015RELA = 7
16RELACOUNT = 0x6ffffff9
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 .text
Michael Ellerman6975a782011-04-12 20:38:55 +000019 /* 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 */
Paul Mackerrasf40e5242007-06-07 22:21:31 +100023 .globl _zimage_start_opd
Paul Mackerras66a45dd2006-01-14 15:04:06 +110024_zimage_start_opd:
Michael Ellerman6975a782011-04-12 20:38:55 +000025 .long 0x500000, 0, 0, 0
26
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020027#ifdef __powerpc64__
28.balign 8
Tobin C. Hardingeb039162017-03-09 16:42:12 +110029p_start: .8byte _start
30p_etext: .8byte _etext
31p_bss_start: .8byte __bss_start
32p_end: .8byte _end
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020033
Tobin C. Hardingeb039162017-03-09 16:42:12 +110034p_toc: .8byte __toc_start + 0x8000 - p_base
35p_dyn: .8byte __dynamic_start - p_base
36p_rela: .8byte __rela_dyn_start - p_base
37p_prom: .8byte 0
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020038 .weak _platform_stack_top
Tobin C. Hardingeb039162017-03-09 16:42:12 +110039p_pstack: .8byte _platform_stack_top
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020040#else
Michael Ellerman6975a782011-04-12 20:38:55 +000041p_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
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020048#endif
Paul Mackerras66a45dd2006-01-14 15:04:06 +110049
Olaf Hering67a1b682005-10-28 17:46:49 -070050 .globl _zimage_start
Joel Stanleyee9d21b2018-09-14 13:36:47 +093051 /* Clang appears to require the .weak directive to be after the symbol
52 * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921 */
53 .weak _zimage_start
Olaf Hering67a1b682005-10-28 17:46:49 -070054_zimage_start:
Milton Miller160cc3e2007-03-21 09:02:53 -060055 .globl _zimage_start_lib
56_zimage_start_lib:
Paul Mackerras66a45dd2006-01-14 15:04:06 +110057 /* Work out the offset between the address we were linked at
58 and the address where we're running. */
Michael Ellerman6975a782011-04-12 20:38:55 +000059 bl .+4
60p_base: mflr r10 /* r10 now points to runtime addr of p_base */
Cédric Le Goaterf16e9682014-04-24 09:23:37 +020061#ifndef __powerpc64__
Michael Ellerman6975a782011-04-12 20:38:55 +000062 /* grab the link address of the dynamic section in r11 */
63 addis r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
64 lwz r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
65 cmpwi r11,0
66 beq 3f /* if not linked -pie */
67 /* get the runtime address of the dynamic section in r12 */
68 .weak __dynamic_start
69 addis r12,r10,(__dynamic_start-p_base)@ha
70 addi r12,r12,(__dynamic_start-p_base)@l
71 subf r11,r11,r12 /* runtime - linktime offset */
Olaf Heringa4497232005-10-28 17:46:48 -070072
Michael Ellerman6975a782011-04-12 20:38:55 +000073 /* The dynamic section contains a series of tagged entries.
74 * We need the RELA and RELACOUNT entries. */
Michael Ellerman6975a782011-04-12 20:38:55 +000075 li r9,0
76 li r0,0
779: lwz r8,0(r12) /* get tag */
78 cmpwi r8,0
79 beq 10f /* end of list */
80 cmpwi r8,RELA
81 bne 11f
82 lwz r9,4(r12) /* get RELA pointer in r9 */
83 b 12f
8411: addis r8,r8,(-RELACOUNT)@ha
85 cmpwi r8,RELACOUNT@l
86 bne 12f
87 lwz r0,4(r12) /* get RELACOUNT value in r0 */
8812: addi r12,r12,8
89 b 9b
90
91 /* The relocation section contains a list of relocations.
92 * We now do the R_PPC_RELATIVE ones, which point to words
93 * which need to be initialized with addend + offset.
94 * The R_PPC_RELATIVE ones come first and there are RELACOUNT
95 * of them. */
9610: /* skip relocation if we don't have both */
97 cmpwi r0,0
Olaf Hering68643cf2005-11-17 22:09:02 +010098 beq 3f
Michael Ellerman6975a782011-04-12 20:38:55 +000099 cmpwi r9,0
100 beq 3f
101
102 add r9,r9,r11 /* Relocate RELA pointer */
103 mtctr r0
1042: lbz r0,4+3(r9) /* ELF32_R_INFO(reloc->r_info) */
105 cmpwi r0,22 /* R_PPC_RELATIVE */
106 bne 3f
107 lwz r12,0(r9) /* reloc->r_offset */
108 lwz r0,8(r9) /* reloc->r_addend */
109 add r0,r0,r11
110 stwx r0,r11,r12
111 addi r9,r9,12
Olaf Hering68643cf2005-11-17 22:09:02 +0100112 bdnz 2b
Olaf Heringa4497232005-10-28 17:46:48 -0700113
David Gibsoncd197ff2007-03-05 14:24:52 +1100114 /* Do a cache flush for our text, in case the loader didn't */
Michael Ellerman6975a782011-04-12 20:38:55 +00001153: lwz r9,p_start-p_base(r10) /* note: these are relocated now */
116 lwz r8,p_etext-p_base(r10)
Olaf Hering68643cf2005-11-17 22:09:02 +01001174: dcbf r0,r9
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 icbi r0,r9
119 addi r9,r9,0x20
Olaf Heringeacb1962006-03-04 13:15:40 +0100120 cmplw cr0,r9,r8
Olaf Hering68643cf2005-11-17 22:09:02 +0100121 blt 4b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 sync
123 isync
124
David Gibsoncd197ff2007-03-05 14:24:52 +1100125 /* Clear the BSS */
Michael Ellerman6975a782011-04-12 20:38:55 +0000126 lwz r9,p_bss_start-p_base(r10)
127 lwz r8,p_end-p_base(r10)
128 li r0,0
1295: stw r0,0(r9)
David Gibsoncd197ff2007-03-05 14:24:52 +1100130 addi r9,r9,4
131 cmplw cr0,r9,r8
132 blt 5b
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133
David Gibsoncd197ff2007-03-05 14:24:52 +1100134 /* Possibly set up a custom stack */
Michael Ellerman6975a782011-04-12 20:38:55 +0000135 lwz r8,p_pstack-p_base(r10)
David Gibsoncd197ff2007-03-05 14:24:52 +1100136 cmpwi r8,0
137 beq 6f
138 lwz r1,0(r8)
139 li r0,0
140 stwu r0,-16(r1) /* establish a stack frame */
1416:
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200142#else /* __powerpc64__ */
143 /* Save the prom pointer at p_prom. */
144 std r5,(p_prom-p_base)(r10)
David Gibsoncd197ff2007-03-05 14:24:52 +1100145
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200146 /* Set r2 to the TOC. */
147 ld r2,(p_toc-p_base)(r10)
148 add r2,r2,r10
149
150 /* Grab the link address of the dynamic section in r11. */
151 ld r11,-32768(r2)
152 cmpwi r11,0
153 beq 3f /* if not linked -pie then no dynamic section */
154
155 ld r11,(p_dyn-p_base)(r10)
156 add r11,r11,r10
157 ld r9,(p_rela-p_base)(r10)
158 add r9,r9,r10
159
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800160 li r13,0
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200161 li r8,0
Jeremy Kerr7f664cf2015-02-11 12:55:44 +08001629: ld r12,0(r11) /* get tag */
163 cmpdi r12,0
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200164 beq 12f /* end of list */
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800165 cmpdi r12,RELA
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200166 bne 10f
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800167 ld r13,8(r11) /* get RELA pointer in r13 */
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200168 b 11f
Jeremy Kerr7f664cf2015-02-11 12:55:44 +080016910: addis r12,r12,(-RELACOUNT)@ha
170 cmpdi r12,RELACOUNT@l
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200171 bne 11f
172 ld r8,8(r11) /* get RELACOUNT value in r8 */
17311: addi r11,r11,16
174 b 9b
17512:
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800176 cmpdi r13,0 /* check we have both RELA and RELACOUNT */
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200177 cmpdi cr1,r8,0
178 beq 3f
179 beq cr1,3f
180
181 /* Calcuate the runtime offset. */
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800182 subf r13,r13,r9
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200183
184 /* Run through the list of relocations and process the
185 * R_PPC64_RELATIVE ones. */
186 mtctr r8
18713: ld r0,8(r9) /* ELF64_R_TYPE(reloc->r_info) */
188 cmpdi r0,22 /* R_PPC64_RELATIVE */
189 bne 3f
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800190 ld r12,0(r9) /* reloc->r_offset */
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200191 ld r0,16(r9) /* reloc->r_addend */
Jeremy Kerr7f664cf2015-02-11 12:55:44 +0800192 add r0,r0,r13
193 stdx r0,r13,r12
Cédric Le Goaterf16e9682014-04-24 09:23:37 +0200194 addi r9,r9,24
195 bdnz 13b
196
197 /* Do a cache flush for our text, in case the loader didn't */
1983: ld r9,p_start-p_base(r10) /* note: these are relocated now */
199 ld r8,p_etext-p_base(r10)
2004: dcbf r0,r9
201 icbi r0,r9
202 addi r9,r9,0x20
203 cmpld cr0,r9,r8
204 blt 4b
205 sync
206 isync
207
208 /* Clear the BSS */
209 ld r9,p_bss_start-p_base(r10)
210 ld r8,p_end-p_base(r10)
211 li r0,0
2125: std r0,0(r9)
213 addi r9,r9,8
214 cmpld cr0,r9,r8
215 blt 5b
216
217 /* Possibly set up a custom stack */
218 ld r8,p_pstack-p_base(r10)
219 cmpdi r8,0
220 beq 6f
221 ld r1,0(r8)
222 li r0,0
Jeremy Kerr8c06f0d2015-02-11 12:55:44 +0800223 stdu r0,-112(r1) /* establish a stack frame */
Cédric Le Goaterf16e9682014-04-24 09:23:37 +02002246:
225#endif /* __powerpc64__ */
David Gibsoncd197ff2007-03-05 14:24:52 +1100226 /* Call platform_init() */
227 bl platform_init
228
229 /* Call start */
David Gibsoncd197ff2007-03-05 14:24:52 +1100230 b start
Cédric Le Goater93d39212014-04-24 09:23:36 +0200231
232#ifdef __powerpc64__
233
234#define PROM_FRAME_SIZE 512
235#define SAVE_GPR(n, base) std n,8*(n)(base)
236#define REST_GPR(n, base) ld n,8*(n)(base)
237#define SAVE_2GPRS(n, base) SAVE_GPR(n, base); SAVE_GPR(n+1, base)
238#define SAVE_4GPRS(n, base) SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
239#define SAVE_8GPRS(n, base) SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
240#define SAVE_10GPRS(n, base) SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
241#define REST_2GPRS(n, base) REST_GPR(n, base); REST_GPR(n+1, base)
242#define REST_4GPRS(n, base) REST_2GPRS(n, base); REST_2GPRS(n+2, base)
243#define REST_8GPRS(n, base) REST_4GPRS(n, base); REST_4GPRS(n+4, base)
244#define REST_10GPRS(n, base) REST_8GPRS(n, base); REST_2GPRS(n+8, base)
245
246/* prom handles the jump into and return from firmware. The prom args pointer
247 is loaded in r3. */
248.globl prom
249prom:
250 mflr r0
251 std r0,16(r1)
252 stdu r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
253
254 SAVE_GPR(2, r1)
255 SAVE_GPR(13, r1)
256 SAVE_8GPRS(14, r1)
257 SAVE_10GPRS(22, r1)
258 mfcr r10
259 std r10,8*32(r1)
260 mfmsr r10
261 std r10,8*33(r1)
262
263 /* remove MSR_LE from msr but keep MSR_SF */
264 mfmsr r10
265 rldicr r10,r10,0,62
266 mtsrr1 r10
267
268 /* Load FW address, set LR to label 1, and jump to FW */
269 bl 0f
2700: mflr r10
271 addi r11,r10,(1f-0b)
272 mtlr r11
273
274 ld r10,(p_prom-0b)(r10)
275 mtsrr0 r10
276
277 rfid
278
2791: /* Return from OF */
Cédric Le Goater147c0512014-04-24 09:23:39 +0200280 FIXUP_ENDIAN
Cédric Le Goater93d39212014-04-24 09:23:36 +0200281
282 /* Restore registers and return. */
283 rldicl r1,r1,0,32
284
285 /* Restore the MSR (back to 64 bits) */
286 ld r10,8*(33)(r1)
287 mtmsr r10
288 isync
289
290 /* Restore other registers */
291 REST_GPR(2, r1)
292 REST_GPR(13, r1)
293 REST_8GPRS(14, r1)
294 REST_10GPRS(22, r1)
295 ld r10,8*32(r1)
296 mtcr r10
297
298 addi r1,r1,PROM_FRAME_SIZE
299 ld r0,16(r1)
300 mtlr r0
301 blr
302#endif