xref: /openbmc/linux/arch/powerpc/boot/crt0.S (revision cd99dac6)
12874c5fdSThomas Gleixner/* SPDX-License-Identifier: GPL-2.0-or-later */
294b212c2SPaul Mackerras/*
394b212c2SPaul Mackerras * Copyright (C) Paul Mackerras 1997.
494b212c2SPaul Mackerras *
5f16e9684SCédric Le Goater * Adapted for 64 bit LE PowerPC by Andrew Tauferner
694b212c2SPaul Mackerras */
794b212c2SPaul Mackerras
894b212c2SPaul Mackerras#include "ppc_asm.h"
994b212c2SPaul Mackerras
10f16e9684SCédric Le GoaterRELA = 7
11c14d31baSAlexey KardashevskiyRELASZ = 8
12c14d31baSAlexey KardashevskiyRELAENT = 9
13f16e9684SCédric Le Goater
145564597dSPaul Mackerras	.data
156975a783SMichael Ellerman	/* A procedure descriptor used when booting this as a COFF file.
166975a783SMichael Ellerman	 * When making COFF, this comes first in the link and we're
176975a783SMichael Ellerman	 * linked at 0x500000.
186975a783SMichael Ellerman	 */
19f40e524eSPaul Mackerras	.globl	_zimage_start_opd
2066a45dd3SPaul Mackerras_zimage_start_opd:
216975a783SMichael Ellerman	.long	0x500000, 0, 0, 0
225564597dSPaul Mackerras	.text
235564597dSPaul Mackerras	b	_zimage_start
246975a783SMichael Ellerman
25f16e9684SCédric Le Goater#ifdef __powerpc64__
26f16e9684SCédric Le Goater.balign 8
27eb039161STobin C. Hardingp_start:	.8byte	_start
28eb039161STobin C. Hardingp_etext:	.8byte	_etext
29eb039161STobin C. Hardingp_bss_start:	.8byte	__bss_start
30eb039161STobin C. Hardingp_end:		.8byte	_end
31f16e9684SCédric Le Goater
32a3ad84daSAlan Modrap_toc:		.8byte	.TOC. - p_base
33eb039161STobin C. Hardingp_dyn:		.8byte	__dynamic_start - p_base
34eb039161STobin C. Hardingp_rela:		.8byte	__rela_dyn_start - p_base
35eb039161STobin C. Hardingp_prom:		.8byte	0
36f16e9684SCédric Le Goater	.weak	_platform_stack_top
37eb039161STobin C. Hardingp_pstack:	.8byte	_platform_stack_top
38f16e9684SCédric Le Goater#else
396975a783SMichael Ellermanp_start:	.long	_start
406975a783SMichael Ellermanp_etext:	.long	_etext
416975a783SMichael Ellermanp_bss_start:	.long	__bss_start
426975a783SMichael Ellermanp_end:		.long	_end
436975a783SMichael Ellerman
446975a783SMichael Ellerman	.weak	_platform_stack_top
456975a783SMichael Ellermanp_pstack:	.long	_platform_stack_top
46f16e9684SCédric Le Goater#endif
4766a45dd3SPaul Mackerras
48ee9d21b3SJoel Stanley	.weak	_zimage_start
4994b212c2SPaul Mackerras_zimage_start:
50160cc3ecSMilton Miller	.globl	_zimage_start_lib
51160cc3ecSMilton Miller_zimage_start_lib:
5266a45dd3SPaul Mackerras	/* Work out the offset between the address we were linked at
5366a45dd3SPaul Mackerras	   and the address where we're running. */
54*cd99dac6SNicholas Piggin	bcl	20,31,.+4
556975a783SMichael Ellermanp_base:	mflr	r10		/* r10 now points to runtime addr of p_base */
56f16e9684SCédric Le Goater#ifndef __powerpc64__
576975a783SMichael Ellerman	/* grab the link address of the dynamic section in r11 */
586975a783SMichael Ellerman	addis	r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
596975a783SMichael Ellerman	lwz	r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
606975a783SMichael Ellerman	cmpwi	r11,0
616975a783SMichael Ellerman	beq	3f		/* if not linked -pie */
626975a783SMichael Ellerman	/* get the runtime address of the dynamic section in r12 */
636975a783SMichael Ellerman	.weak	__dynamic_start
646975a783SMichael Ellerman	addis	r12,r10,(__dynamic_start-p_base)@ha
656975a783SMichael Ellerman	addi	r12,r12,(__dynamic_start-p_base)@l
666975a783SMichael Ellerman	subf	r11,r11,r12	/* runtime - linktime offset */
6794b212c2SPaul Mackerras
686975a783SMichael Ellerman	/* The dynamic section contains a series of tagged entries.
696975a783SMichael Ellerman	 * We need the RELA and RELACOUNT entries. */
706975a783SMichael Ellerman	li	r9,0
716975a783SMichael Ellerman	li	r0,0
726975a783SMichael Ellerman9:	lwz	r8,0(r12)	/* get tag */
736975a783SMichael Ellerman	cmpwi	r8,0
746975a783SMichael Ellerman	beq	10f		/* end of list */
756975a783SMichael Ellerman	cmpwi	r8,RELA
766975a783SMichael Ellerman	bne	11f
776975a783SMichael Ellerman	lwz	r9,4(r12)	/* get RELA pointer in r9 */
786975a783SMichael Ellerman	b	12f
79c14d31baSAlexey Kardashevskiy11:	cmpwi	r8,RELASZ
80c14d31baSAlexey Kardashevskiy	bne	.Lcheck_for_relaent
81c14d31baSAlexey Kardashevskiy	lwz	r0,4(r12)       /* get RELASZ value in r0 */
82c14d31baSAlexey Kardashevskiy	b	12f
83c14d31baSAlexey Kardashevskiy.Lcheck_for_relaent:
84c14d31baSAlexey Kardashevskiy	cmpwi	r8,RELAENT
856975a783SMichael Ellerman	bne	12f
86c14d31baSAlexey Kardashevskiy	lwz     r14,4(r12)      /* get RELAENT value in r14 */
876975a783SMichael Ellerman12:	addi	r12,r12,8
886975a783SMichael Ellerman	b	9b
896975a783SMichael Ellerman
906975a783SMichael Ellerman	/* The relocation section contains a list of relocations.
916975a783SMichael Ellerman	 * We now do the R_PPC_RELATIVE ones, which point to words
92c14d31baSAlexey Kardashevskiy	 * which need to be initialized with addend + offset */
936975a783SMichael Ellerman10:	/* skip relocation if we don't have both */
946975a783SMichael Ellerman	cmpwi	r0,0
9568643cfbSOlaf Hering	beq	3f
966975a783SMichael Ellerman	cmpwi	r9,0
976975a783SMichael Ellerman	beq	3f
98c14d31baSAlexey Kardashevskiy	cmpwi	r14,0
99c14d31baSAlexey Kardashevskiy	beq	3f
1006975a783SMichael Ellerman
1016975a783SMichael Ellerman	add	r9,r9,r11	/* Relocate RELA pointer */
102c14d31baSAlexey Kardashevskiy	divwu   r0,r0,r14       /* RELASZ / RELAENT */
1036975a783SMichael Ellerman	mtctr	r0
1046975a783SMichael Ellerman2:	lbz	r0,4+3(r9)	/* ELF32_R_INFO(reloc->r_info) */
1056975a783SMichael Ellerman	cmpwi	r0,22		/* R_PPC_RELATIVE */
106c14d31baSAlexey Kardashevskiy	bne	.Lnext
1076975a783SMichael Ellerman	lwz	r12,0(r9)	/* reloc->r_offset */
1086975a783SMichael Ellerman	lwz	r0,8(r9)	/* reloc->r_addend */
1096975a783SMichael Ellerman	add	r0,r0,r11
1106975a783SMichael Ellerman	stwx	r0,r11,r12
111c14d31baSAlexey Kardashevskiy.Lnext:	add	r9,r9,r14
11268643cfbSOlaf Hering	bdnz	2b
11394b212c2SPaul Mackerras
114cd197ffcSDavid Gibson	/* Do a cache flush for our text, in case the loader didn't */
1156975a783SMichael Ellerman3:	lwz	r9,p_start-p_base(r10)	/* note: these are relocated now */
1166975a783SMichael Ellerman	lwz	r8,p_etext-p_base(r10)
11768643cfbSOlaf Hering4:	dcbf	r0,r9
11894b212c2SPaul Mackerras	icbi	r0,r9
11994b212c2SPaul Mackerras	addi	r9,r9,0x20
120eacb1962SOlaf Hering	cmplw	cr0,r9,r8
12168643cfbSOlaf Hering	blt	4b
12294b212c2SPaul Mackerras	sync
12394b212c2SPaul Mackerras	isync
12494b212c2SPaul Mackerras
125cd197ffcSDavid Gibson	/* Clear the BSS */
1266975a783SMichael Ellerman	lwz	r9,p_bss_start-p_base(r10)
1276975a783SMichael Ellerman	lwz	r8,p_end-p_base(r10)
1286975a783SMichael Ellerman	li	r0,0
1296975a783SMichael Ellerman5:	stw	r0,0(r9)
130cd197ffcSDavid Gibson	addi	r9,r9,4
131cd197ffcSDavid Gibson	cmplw	cr0,r9,r8
132cd197ffcSDavid Gibson	blt	5b
13394b212c2SPaul Mackerras
134cd197ffcSDavid Gibson	/* Possibly set up a custom stack */
1356975a783SMichael Ellerman	lwz	r8,p_pstack-p_base(r10)
136cd197ffcSDavid Gibson	cmpwi	r8,0
137cd197ffcSDavid Gibson	beq	6f
138cd197ffcSDavid Gibson	lwz	r1,0(r8)
139cd197ffcSDavid Gibson	li	r0,0
140cd197ffcSDavid Gibson	stwu	r0,-16(r1)	/* establish a stack frame */
141cd197ffcSDavid Gibson6:
142f16e9684SCédric Le Goater#else /* __powerpc64__ */
143f16e9684SCédric Le Goater	/* Save the prom pointer at p_prom. */
144f16e9684SCédric Le Goater	std	r5,(p_prom-p_base)(r10)
145cd197ffcSDavid Gibson
146f16e9684SCédric Le Goater	/* Set r2 to the TOC. */
147f16e9684SCédric Le Goater	ld	r2,(p_toc-p_base)(r10)
148f16e9684SCédric Le Goater	add	r2,r2,r10
149f16e9684SCédric Le Goater
150f16e9684SCédric Le Goater	/* Grab the link address of the dynamic section in r11. */
151f16e9684SCédric Le Goater	ld	r11,-32768(r2)
152f16e9684SCédric Le Goater	cmpwi	r11,0
153f16e9684SCédric Le Goater	beq	3f              /* if not linked -pie then no dynamic section */
154f16e9684SCédric Le Goater
155f16e9684SCédric Le Goater	ld	r11,(p_dyn-p_base)(r10)
156f16e9684SCédric Le Goater	add	r11,r11,r10
157f16e9684SCédric Le Goater	ld	r9,(p_rela-p_base)(r10)
158f16e9684SCédric Le Goater	add	r9,r9,r10
159f16e9684SCédric Le Goater
1607f664cf9SJeremy Kerr	li	r13,0
161f16e9684SCédric Le Goater	li	r8,0
1627f664cf9SJeremy Kerr9:	ld	r12,0(r11)       /* get tag */
1637f664cf9SJeremy Kerr	cmpdi	r12,0
164f16e9684SCédric Le Goater	beq	12f              /* end of list */
1657f664cf9SJeremy Kerr	cmpdi	r12,RELA
166f16e9684SCédric Le Goater	bne	10f
1677f664cf9SJeremy Kerr	ld	r13,8(r11)       /* get RELA pointer in r13 */
168f16e9684SCédric Le Goater	b	11f
169c14d31baSAlexey Kardashevskiy10:	cmpwi   r12,RELASZ
170c14d31baSAlexey Kardashevskiy	bne	.Lcheck_for_relaent
171c14d31baSAlexey Kardashevskiy	lwz	r8,8(r11)	/* get RELASZ pointer in r8 */
172c14d31baSAlexey Kardashevskiy	b	11f
173c14d31baSAlexey Kardashevskiy.Lcheck_for_relaent:
174c14d31baSAlexey Kardashevskiy	cmpwi	r12,RELAENT
175f16e9684SCédric Le Goater	bne     11f
176c14d31baSAlexey Kardashevskiy	lwz     r14,8(r11)      /* get RELAENT pointer in r14 */
177f16e9684SCédric Le Goater11:	addi	r11,r11,16
178f16e9684SCédric Le Goater	b	9b
179f16e9684SCédric Le Goater12:
180c14d31baSAlexey Kardashevskiy	cmpdi	r13,0            /* check we have both RELA, RELASZ, RELAENT*/
181f16e9684SCédric Le Goater	cmpdi	cr1,r8,0
182f16e9684SCédric Le Goater	beq	3f
183f16e9684SCédric Le Goater	beq	cr1,3f
184c14d31baSAlexey Kardashevskiy	cmpdi	r14,0
185c14d31baSAlexey Kardashevskiy	beq	3f
186f16e9684SCédric Le Goater
187f16e9684SCédric Le Goater	/* Calcuate the runtime offset. */
1887f664cf9SJeremy Kerr	subf	r13,r13,r9
189f16e9684SCédric Le Goater
190f16e9684SCédric Le Goater	/* Run through the list of relocations and process the
191f16e9684SCédric Le Goater	 * R_PPC64_RELATIVE ones. */
192c14d31baSAlexey Kardashevskiy	divdu   r8,r8,r14       /* RELASZ / RELAENT */
193f16e9684SCédric Le Goater	mtctr	r8
194f16e9684SCédric Le Goater13:	ld	r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
195f16e9684SCédric Le Goater	cmpdi	r0,22           /* R_PPC64_RELATIVE */
196c14d31baSAlexey Kardashevskiy	bne	.Lnext
1977f664cf9SJeremy Kerr	ld	r12,0(r9)        /* reloc->r_offset */
198f16e9684SCédric Le Goater	ld	r0,16(r9)       /* reloc->r_addend */
1997f664cf9SJeremy Kerr	add	r0,r0,r13
2007f664cf9SJeremy Kerr	stdx	r0,r13,r12
201c14d31baSAlexey Kardashevskiy.Lnext:	add	r9,r9,r14
202f16e9684SCédric Le Goater	bdnz	13b
203f16e9684SCédric Le Goater
204f16e9684SCédric Le Goater	/* Do a cache flush for our text, in case the loader didn't */
205f16e9684SCédric Le Goater3:	ld	r9,p_start-p_base(r10)	/* note: these are relocated now */
206f16e9684SCédric Le Goater	ld	r8,p_etext-p_base(r10)
207f16e9684SCédric Le Goater4:	dcbf	r0,r9
208f16e9684SCédric Le Goater	icbi	r0,r9
209f16e9684SCédric Le Goater	addi	r9,r9,0x20
210f16e9684SCédric Le Goater	cmpld	cr0,r9,r8
211f16e9684SCédric Le Goater	blt	4b
212f16e9684SCédric Le Goater	sync
213f16e9684SCédric Le Goater	isync
214f16e9684SCédric Le Goater
215f16e9684SCédric Le Goater	/* Clear the BSS */
216f16e9684SCédric Le Goater	ld	r9,p_bss_start-p_base(r10)
217f16e9684SCédric Le Goater	ld	r8,p_end-p_base(r10)
218f16e9684SCédric Le Goater	li	r0,0
219f16e9684SCédric Le Goater5:	std	r0,0(r9)
220f16e9684SCédric Le Goater	addi	r9,r9,8
221f16e9684SCédric Le Goater	cmpld	cr0,r9,r8
222f16e9684SCédric Le Goater	blt	5b
223f16e9684SCédric Le Goater
224f16e9684SCédric Le Goater	/* Possibly set up a custom stack */
225f16e9684SCédric Le Goater	ld	r8,p_pstack-p_base(r10)
226f16e9684SCédric Le Goater	cmpdi	r8,0
227f16e9684SCédric Le Goater	beq	6f
228f16e9684SCédric Le Goater	ld	r1,0(r8)
229f16e9684SCédric Le Goater	li	r0,0
2308c06f0d9SJeremy Kerr	stdu	r0,-112(r1)	/* establish a stack frame */
231f16e9684SCédric Le Goater6:
232f16e9684SCédric Le Goater#endif  /* __powerpc64__ */
233cd197ffcSDavid Gibson	/* Call platform_init() */
234cd197ffcSDavid Gibson	bl	platform_init
235cd197ffcSDavid Gibson
236cd197ffcSDavid Gibson	/* Call start */
237cd197ffcSDavid Gibson	b	start
23893d39210SCédric Le Goater
23993d39210SCédric Le Goater#ifdef __powerpc64__
24093d39210SCédric Le Goater
24193d39210SCédric Le Goater#define PROM_FRAME_SIZE 512
242aebd1fb4SNicholas Piggin
243aebd1fb4SNicholas Piggin.macro OP_REGS op, width, start, end, base, offset
244aebd1fb4SNicholas Piggin	.Lreg=\start
245aebd1fb4SNicholas Piggin	.rept (\end - \start + 1)
246aebd1fb4SNicholas Piggin	\op	.Lreg,\offset+\width*.Lreg(\base)
247aebd1fb4SNicholas Piggin	.Lreg=.Lreg+1
248aebd1fb4SNicholas Piggin	.endr
249aebd1fb4SNicholas Piggin.endm
250aebd1fb4SNicholas Piggin
251aebd1fb4SNicholas Piggin#define SAVE_GPRS(start, end, base)	OP_REGS std, 8, start, end, base, 0
252aebd1fb4SNicholas Piggin#define REST_GPRS(start, end, base)	OP_REGS ld, 8, start, end, base, 0
253aebd1fb4SNicholas Piggin#define SAVE_GPR(n, base)		SAVE_GPRS(n, n, base)
254aebd1fb4SNicholas Piggin#define REST_GPR(n, base)		REST_GPRS(n, n, base)
25593d39210SCédric Le Goater
25693d39210SCédric Le Goater/* prom handles the jump into and return from firmware.  The prom args pointer
25793d39210SCédric Le Goater   is loaded in r3. */
25893d39210SCédric Le Goater.globl prom
25993d39210SCédric Le Goaterprom:
26093d39210SCédric Le Goater	mflr	r0
26193d39210SCédric Le Goater	std	r0,16(r1)
26293d39210SCédric Le Goater	stdu	r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
26393d39210SCédric Le Goater
26493d39210SCédric Le Goater	SAVE_GPR(2, r1)
265aebd1fb4SNicholas Piggin	SAVE_GPRS(13, 31, r1)
26693d39210SCédric Le Goater	mfcr    r10
26793d39210SCédric Le Goater	std     r10,8*32(r1)
26893d39210SCédric Le Goater	mfmsr   r10
26993d39210SCédric Le Goater	std     r10,8*33(r1)
27093d39210SCédric Le Goater
27193d39210SCédric Le Goater	/* remove MSR_LE from msr but keep MSR_SF */
27293d39210SCédric Le Goater	mfmsr	r10
27393d39210SCédric Le Goater	rldicr	r10,r10,0,62
27493d39210SCédric Le Goater	mtsrr1	r10
27593d39210SCédric Le Goater
27693d39210SCédric Le Goater	/* Load FW address, set LR to label 1, and jump to FW */
277*cd99dac6SNicholas Piggin	bcl	20,31,0f
27893d39210SCédric Le Goater0:	mflr	r10
27993d39210SCédric Le Goater	addi	r11,r10,(1f-0b)
28093d39210SCédric Le Goater	mtlr	r11
28193d39210SCédric Le Goater
28293d39210SCédric Le Goater	ld	r10,(p_prom-0b)(r10)
28393d39210SCédric Le Goater	mtsrr0	r10
28493d39210SCédric Le Goater
28593d39210SCédric Le Goater	rfid
28693d39210SCédric Le Goater
28793d39210SCédric Le Goater1:	/* Return from OF */
288147c0516SCédric Le Goater	FIXUP_ENDIAN
28993d39210SCédric Le Goater
29093d39210SCédric Le Goater	/* Restore registers and return. */
29193d39210SCédric Le Goater	rldicl  r1,r1,0,32
29293d39210SCédric Le Goater
29393d39210SCédric Le Goater	/* Restore the MSR (back to 64 bits) */
29493d39210SCédric Le Goater	ld      r10,8*(33)(r1)
29593d39210SCédric Le Goater	mtmsr	r10
29693d39210SCédric Le Goater	isync
29793d39210SCédric Le Goater
29893d39210SCédric Le Goater	/* Restore other registers */
29993d39210SCédric Le Goater	REST_GPR(2, r1)
300aebd1fb4SNicholas Piggin	REST_GPRS(13, 31, r1)
30193d39210SCédric Le Goater	ld      r10,8*32(r1)
30293d39210SCédric Le Goater	mtcr	r10
30393d39210SCédric Le Goater
30493d39210SCédric Le Goater	addi    r1,r1,PROM_FRAME_SIZE
30593d39210SCédric Le Goater	ld      r0,16(r1)
30693d39210SCédric Le Goater	mtlr    r0
30793d39210SCédric Le Goater	blr
30893d39210SCédric Le Goater#endif
309