xref: /openbmc/linux/arch/powerpc/boot/crt0.S (revision a3ad84da)
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
11f16e9684SCédric Le GoaterRELACOUNT = 0x6ffffff9
12f16e9684SCédric Le Goater
135564597dSPaul Mackerras	.data
146975a783SMichael Ellerman	/* A procedure descriptor used when booting this as a COFF file.
156975a783SMichael Ellerman	 * When making COFF, this comes first in the link and we're
166975a783SMichael Ellerman	 * linked at 0x500000.
176975a783SMichael Ellerman	 */
18f40e524eSPaul Mackerras	.globl	_zimage_start_opd
1966a45dd3SPaul Mackerras_zimage_start_opd:
206975a783SMichael Ellerman	.long	0x500000, 0, 0, 0
215564597dSPaul Mackerras	.text
225564597dSPaul Mackerras	b	_zimage_start
236975a783SMichael Ellerman
24f16e9684SCédric Le Goater#ifdef __powerpc64__
25f16e9684SCédric Le Goater.balign 8
26eb039161STobin C. Hardingp_start:	.8byte	_start
27eb039161STobin C. Hardingp_etext:	.8byte	_etext
28eb039161STobin C. Hardingp_bss_start:	.8byte	__bss_start
29eb039161STobin C. Hardingp_end:		.8byte	_end
30f16e9684SCédric Le Goater
31*a3ad84daSAlan Modrap_toc:		.8byte	.TOC. - p_base
32eb039161STobin C. Hardingp_dyn:		.8byte	__dynamic_start - p_base
33eb039161STobin C. Hardingp_rela:		.8byte	__rela_dyn_start - p_base
34eb039161STobin C. Hardingp_prom:		.8byte	0
35f16e9684SCédric Le Goater	.weak	_platform_stack_top
36eb039161STobin C. Hardingp_pstack:	.8byte	_platform_stack_top
37f16e9684SCédric Le Goater#else
386975a783SMichael Ellermanp_start:	.long	_start
396975a783SMichael Ellermanp_etext:	.long	_etext
406975a783SMichael Ellermanp_bss_start:	.long	__bss_start
416975a783SMichael Ellermanp_end:		.long	_end
426975a783SMichael Ellerman
436975a783SMichael Ellerman	.weak	_platform_stack_top
446975a783SMichael Ellermanp_pstack:	.long	_platform_stack_top
45f16e9684SCédric Le Goater#endif
4666a45dd3SPaul Mackerras
47ee9d21b3SJoel Stanley	.weak	_zimage_start
4894b212c2SPaul Mackerras_zimage_start:
49160cc3ecSMilton Miller	.globl	_zimage_start_lib
50160cc3ecSMilton Miller_zimage_start_lib:
5166a45dd3SPaul Mackerras	/* Work out the offset between the address we were linked at
5266a45dd3SPaul Mackerras	   and the address where we're running. */
536975a783SMichael Ellerman	bl	.+4
546975a783SMichael Ellermanp_base:	mflr	r10		/* r10 now points to runtime addr of p_base */
55f16e9684SCédric Le Goater#ifndef __powerpc64__
566975a783SMichael Ellerman	/* grab the link address of the dynamic section in r11 */
576975a783SMichael Ellerman	addis	r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
586975a783SMichael Ellerman	lwz	r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
596975a783SMichael Ellerman	cmpwi	r11,0
606975a783SMichael Ellerman	beq	3f		/* if not linked -pie */
616975a783SMichael Ellerman	/* get the runtime address of the dynamic section in r12 */
626975a783SMichael Ellerman	.weak	__dynamic_start
636975a783SMichael Ellerman	addis	r12,r10,(__dynamic_start-p_base)@ha
646975a783SMichael Ellerman	addi	r12,r12,(__dynamic_start-p_base)@l
656975a783SMichael Ellerman	subf	r11,r11,r12	/* runtime - linktime offset */
6694b212c2SPaul Mackerras
676975a783SMichael Ellerman	/* The dynamic section contains a series of tagged entries.
686975a783SMichael Ellerman	 * We need the RELA and RELACOUNT entries. */
696975a783SMichael Ellerman	li	r9,0
706975a783SMichael Ellerman	li	r0,0
716975a783SMichael Ellerman9:	lwz	r8,0(r12)	/* get tag */
726975a783SMichael Ellerman	cmpwi	r8,0
736975a783SMichael Ellerman	beq	10f		/* end of list */
746975a783SMichael Ellerman	cmpwi	r8,RELA
756975a783SMichael Ellerman	bne	11f
766975a783SMichael Ellerman	lwz	r9,4(r12)	/* get RELA pointer in r9 */
776975a783SMichael Ellerman	b	12f
786975a783SMichael Ellerman11:	addis	r8,r8,(-RELACOUNT)@ha
796975a783SMichael Ellerman	cmpwi	r8,RELACOUNT@l
806975a783SMichael Ellerman	bne	12f
816975a783SMichael Ellerman	lwz	r0,4(r12)	/* get RELACOUNT value in r0 */
826975a783SMichael Ellerman12:	addi	r12,r12,8
836975a783SMichael Ellerman	b	9b
846975a783SMichael Ellerman
856975a783SMichael Ellerman	/* The relocation section contains a list of relocations.
866975a783SMichael Ellerman	 * We now do the R_PPC_RELATIVE ones, which point to words
876975a783SMichael Ellerman	 * which need to be initialized with addend + offset.
886975a783SMichael Ellerman	 * The R_PPC_RELATIVE ones come first and there are RELACOUNT
896975a783SMichael Ellerman	 * of them. */
906975a783SMichael Ellerman10:	/* skip relocation if we don't have both */
916975a783SMichael Ellerman	cmpwi	r0,0
9268643cfbSOlaf Hering	beq	3f
936975a783SMichael Ellerman	cmpwi	r9,0
946975a783SMichael Ellerman	beq	3f
956975a783SMichael Ellerman
966975a783SMichael Ellerman	add	r9,r9,r11	/* Relocate RELA pointer */
976975a783SMichael Ellerman	mtctr	r0
986975a783SMichael Ellerman2:	lbz	r0,4+3(r9)	/* ELF32_R_INFO(reloc->r_info) */
996975a783SMichael Ellerman	cmpwi	r0,22		/* R_PPC_RELATIVE */
1006975a783SMichael Ellerman	bne	3f
1016975a783SMichael Ellerman	lwz	r12,0(r9)	/* reloc->r_offset */
1026975a783SMichael Ellerman	lwz	r0,8(r9)	/* reloc->r_addend */
1036975a783SMichael Ellerman	add	r0,r0,r11
1046975a783SMichael Ellerman	stwx	r0,r11,r12
1056975a783SMichael Ellerman	addi	r9,r9,12
10668643cfbSOlaf Hering	bdnz	2b
10794b212c2SPaul Mackerras
108cd197ffcSDavid Gibson	/* Do a cache flush for our text, in case the loader didn't */
1096975a783SMichael Ellerman3:	lwz	r9,p_start-p_base(r10)	/* note: these are relocated now */
1106975a783SMichael Ellerman	lwz	r8,p_etext-p_base(r10)
11168643cfbSOlaf Hering4:	dcbf	r0,r9
11294b212c2SPaul Mackerras	icbi	r0,r9
11394b212c2SPaul Mackerras	addi	r9,r9,0x20
114eacb1962SOlaf Hering	cmplw	cr0,r9,r8
11568643cfbSOlaf Hering	blt	4b
11694b212c2SPaul Mackerras	sync
11794b212c2SPaul Mackerras	isync
11894b212c2SPaul Mackerras
119cd197ffcSDavid Gibson	/* Clear the BSS */
1206975a783SMichael Ellerman	lwz	r9,p_bss_start-p_base(r10)
1216975a783SMichael Ellerman	lwz	r8,p_end-p_base(r10)
1226975a783SMichael Ellerman	li	r0,0
1236975a783SMichael Ellerman5:	stw	r0,0(r9)
124cd197ffcSDavid Gibson	addi	r9,r9,4
125cd197ffcSDavid Gibson	cmplw	cr0,r9,r8
126cd197ffcSDavid Gibson	blt	5b
12794b212c2SPaul Mackerras
128cd197ffcSDavid Gibson	/* Possibly set up a custom stack */
1296975a783SMichael Ellerman	lwz	r8,p_pstack-p_base(r10)
130cd197ffcSDavid Gibson	cmpwi	r8,0
131cd197ffcSDavid Gibson	beq	6f
132cd197ffcSDavid Gibson	lwz	r1,0(r8)
133cd197ffcSDavid Gibson	li	r0,0
134cd197ffcSDavid Gibson	stwu	r0,-16(r1)	/* establish a stack frame */
135cd197ffcSDavid Gibson6:
136f16e9684SCédric Le Goater#else /* __powerpc64__ */
137f16e9684SCédric Le Goater	/* Save the prom pointer at p_prom. */
138f16e9684SCédric Le Goater	std	r5,(p_prom-p_base)(r10)
139cd197ffcSDavid Gibson
140f16e9684SCédric Le Goater	/* Set r2 to the TOC. */
141f16e9684SCédric Le Goater	ld	r2,(p_toc-p_base)(r10)
142f16e9684SCédric Le Goater	add	r2,r2,r10
143f16e9684SCédric Le Goater
144f16e9684SCédric Le Goater	/* Grab the link address of the dynamic section in r11. */
145f16e9684SCédric Le Goater	ld	r11,-32768(r2)
146f16e9684SCédric Le Goater	cmpwi	r11,0
147f16e9684SCédric Le Goater	beq	3f              /* if not linked -pie then no dynamic section */
148f16e9684SCédric Le Goater
149f16e9684SCédric Le Goater	ld	r11,(p_dyn-p_base)(r10)
150f16e9684SCédric Le Goater	add	r11,r11,r10
151f16e9684SCédric Le Goater	ld	r9,(p_rela-p_base)(r10)
152f16e9684SCédric Le Goater	add	r9,r9,r10
153f16e9684SCédric Le Goater
1547f664cf9SJeremy Kerr	li	r13,0
155f16e9684SCédric Le Goater	li	r8,0
1567f664cf9SJeremy Kerr9:	ld	r12,0(r11)       /* get tag */
1577f664cf9SJeremy Kerr	cmpdi	r12,0
158f16e9684SCédric Le Goater	beq	12f              /* end of list */
1597f664cf9SJeremy Kerr	cmpdi	r12,RELA
160f16e9684SCédric Le Goater	bne	10f
1617f664cf9SJeremy Kerr	ld	r13,8(r11)       /* get RELA pointer in r13 */
162f16e9684SCédric Le Goater	b	11f
1637f664cf9SJeremy Kerr10:	addis	r12,r12,(-RELACOUNT)@ha
1647f664cf9SJeremy Kerr	cmpdi	r12,RELACOUNT@l
165f16e9684SCédric Le Goater	bne	11f
166f16e9684SCédric Le Goater	ld	r8,8(r11)       /* get RELACOUNT value in r8 */
167f16e9684SCédric Le Goater11:	addi	r11,r11,16
168f16e9684SCédric Le Goater	b	9b
169f16e9684SCédric Le Goater12:
1707f664cf9SJeremy Kerr	cmpdi	r13,0            /* check we have both RELA and RELACOUNT */
171f16e9684SCédric Le Goater	cmpdi	cr1,r8,0
172f16e9684SCédric Le Goater	beq	3f
173f16e9684SCédric Le Goater	beq	cr1,3f
174f16e9684SCédric Le Goater
175f16e9684SCédric Le Goater	/* Calcuate the runtime offset. */
1767f664cf9SJeremy Kerr	subf	r13,r13,r9
177f16e9684SCédric Le Goater
178f16e9684SCédric Le Goater	/* Run through the list of relocations and process the
179f16e9684SCédric Le Goater	 * R_PPC64_RELATIVE ones. */
180f16e9684SCédric Le Goater	mtctr	r8
181f16e9684SCédric Le Goater13:	ld	r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
182f16e9684SCédric Le Goater	cmpdi	r0,22           /* R_PPC64_RELATIVE */
183f16e9684SCédric Le Goater	bne	3f
1847f664cf9SJeremy Kerr	ld	r12,0(r9)        /* reloc->r_offset */
185f16e9684SCédric Le Goater	ld	r0,16(r9)       /* reloc->r_addend */
1867f664cf9SJeremy Kerr	add	r0,r0,r13
1877f664cf9SJeremy Kerr	stdx	r0,r13,r12
188f16e9684SCédric Le Goater	addi	r9,r9,24
189f16e9684SCédric Le Goater	bdnz	13b
190f16e9684SCédric Le Goater
191f16e9684SCédric Le Goater	/* Do a cache flush for our text, in case the loader didn't */
192f16e9684SCédric Le Goater3:	ld	r9,p_start-p_base(r10)	/* note: these are relocated now */
193f16e9684SCédric Le Goater	ld	r8,p_etext-p_base(r10)
194f16e9684SCédric Le Goater4:	dcbf	r0,r9
195f16e9684SCédric Le Goater	icbi	r0,r9
196f16e9684SCédric Le Goater	addi	r9,r9,0x20
197f16e9684SCédric Le Goater	cmpld	cr0,r9,r8
198f16e9684SCédric Le Goater	blt	4b
199f16e9684SCédric Le Goater	sync
200f16e9684SCédric Le Goater	isync
201f16e9684SCédric Le Goater
202f16e9684SCédric Le Goater	/* Clear the BSS */
203f16e9684SCédric Le Goater	ld	r9,p_bss_start-p_base(r10)
204f16e9684SCédric Le Goater	ld	r8,p_end-p_base(r10)
205f16e9684SCédric Le Goater	li	r0,0
206f16e9684SCédric Le Goater5:	std	r0,0(r9)
207f16e9684SCédric Le Goater	addi	r9,r9,8
208f16e9684SCédric Le Goater	cmpld	cr0,r9,r8
209f16e9684SCédric Le Goater	blt	5b
210f16e9684SCédric Le Goater
211f16e9684SCédric Le Goater	/* Possibly set up a custom stack */
212f16e9684SCédric Le Goater	ld	r8,p_pstack-p_base(r10)
213f16e9684SCédric Le Goater	cmpdi	r8,0
214f16e9684SCédric Le Goater	beq	6f
215f16e9684SCédric Le Goater	ld	r1,0(r8)
216f16e9684SCédric Le Goater	li	r0,0
2178c06f0d9SJeremy Kerr	stdu	r0,-112(r1)	/* establish a stack frame */
218f16e9684SCédric Le Goater6:
219f16e9684SCédric Le Goater#endif  /* __powerpc64__ */
220cd197ffcSDavid Gibson	/* Call platform_init() */
221cd197ffcSDavid Gibson	bl	platform_init
222cd197ffcSDavid Gibson
223cd197ffcSDavid Gibson	/* Call start */
224cd197ffcSDavid Gibson	b	start
22593d39210SCédric Le Goater
22693d39210SCédric Le Goater#ifdef __powerpc64__
22793d39210SCédric Le Goater
22893d39210SCédric Le Goater#define PROM_FRAME_SIZE 512
229aebd1fb4SNicholas Piggin
230aebd1fb4SNicholas Piggin.macro OP_REGS op, width, start, end, base, offset
231aebd1fb4SNicholas Piggin	.Lreg=\start
232aebd1fb4SNicholas Piggin	.rept (\end - \start + 1)
233aebd1fb4SNicholas Piggin	\op	.Lreg,\offset+\width*.Lreg(\base)
234aebd1fb4SNicholas Piggin	.Lreg=.Lreg+1
235aebd1fb4SNicholas Piggin	.endr
236aebd1fb4SNicholas Piggin.endm
237aebd1fb4SNicholas Piggin
238aebd1fb4SNicholas Piggin#define SAVE_GPRS(start, end, base)	OP_REGS std, 8, start, end, base, 0
239aebd1fb4SNicholas Piggin#define REST_GPRS(start, end, base)	OP_REGS ld, 8, start, end, base, 0
240aebd1fb4SNicholas Piggin#define SAVE_GPR(n, base)		SAVE_GPRS(n, n, base)
241aebd1fb4SNicholas Piggin#define REST_GPR(n, base)		REST_GPRS(n, n, base)
24293d39210SCédric Le Goater
24393d39210SCédric Le Goater/* prom handles the jump into and return from firmware.  The prom args pointer
24493d39210SCédric Le Goater   is loaded in r3. */
24593d39210SCédric Le Goater.globl prom
24693d39210SCédric Le Goaterprom:
24793d39210SCédric Le Goater	mflr	r0
24893d39210SCédric Le Goater	std	r0,16(r1)
24993d39210SCédric Le Goater	stdu	r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
25093d39210SCédric Le Goater
25193d39210SCédric Le Goater	SAVE_GPR(2, r1)
252aebd1fb4SNicholas Piggin	SAVE_GPRS(13, 31, r1)
25393d39210SCédric Le Goater	mfcr    r10
25493d39210SCédric Le Goater	std     r10,8*32(r1)
25593d39210SCédric Le Goater	mfmsr   r10
25693d39210SCédric Le Goater	std     r10,8*33(r1)
25793d39210SCédric Le Goater
25893d39210SCédric Le Goater	/* remove MSR_LE from msr but keep MSR_SF */
25993d39210SCédric Le Goater	mfmsr	r10
26093d39210SCédric Le Goater	rldicr	r10,r10,0,62
26193d39210SCédric Le Goater	mtsrr1	r10
26293d39210SCédric Le Goater
26393d39210SCédric Le Goater	/* Load FW address, set LR to label 1, and jump to FW */
26493d39210SCédric Le Goater	bl	0f
26593d39210SCédric Le Goater0:	mflr	r10
26693d39210SCédric Le Goater	addi	r11,r10,(1f-0b)
26793d39210SCédric Le Goater	mtlr	r11
26893d39210SCédric Le Goater
26993d39210SCédric Le Goater	ld	r10,(p_prom-0b)(r10)
27093d39210SCédric Le Goater	mtsrr0	r10
27193d39210SCédric Le Goater
27293d39210SCédric Le Goater	rfid
27393d39210SCédric Le Goater
27493d39210SCédric Le Goater1:	/* Return from OF */
275147c0516SCédric Le Goater	FIXUP_ENDIAN
27693d39210SCédric Le Goater
27793d39210SCédric Le Goater	/* Restore registers and return. */
27893d39210SCédric Le Goater	rldicl  r1,r1,0,32
27993d39210SCédric Le Goater
28093d39210SCédric Le Goater	/* Restore the MSR (back to 64 bits) */
28193d39210SCédric Le Goater	ld      r10,8*(33)(r1)
28293d39210SCédric Le Goater	mtmsr	r10
28393d39210SCédric Le Goater	isync
28493d39210SCédric Le Goater
28593d39210SCédric Le Goater	/* Restore other registers */
28693d39210SCédric Le Goater	REST_GPR(2, r1)
287aebd1fb4SNicholas Piggin	REST_GPRS(13, 31, r1)
28893d39210SCédric Le Goater	ld      r10,8*32(r1)
28993d39210SCédric Le Goater	mtcr	r10
29093d39210SCédric Le Goater
29193d39210SCédric Le Goater	addi    r1,r1,PROM_FRAME_SIZE
29293d39210SCédric Le Goater	ld      r0,16(r1)
29393d39210SCédric Le Goater	mtlr    r0
29493d39210SCédric Le Goater	blr
29593d39210SCédric Le Goater#endif
296