xref: /openbmc/linux/arch/powerpc/boot/crt0.S (revision 2874c5fd)
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
31eb039161STobin C. Hardingp_toc:		.8byte	__toc_start + 0x8000 - 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
4794b212c2SPaul Mackerras	.globl	_zimage_start
48ee9d21b3SJoel Stanley	/* Clang appears to require the .weak directive to be after the symbol
49ee9d21b3SJoel Stanley	 * is defined. See https://bugs.llvm.org/show_bug.cgi?id=38921  */
50ee9d21b3SJoel Stanley	.weak	_zimage_start
5194b212c2SPaul Mackerras_zimage_start:
52160cc3ecSMilton Miller	.globl	_zimage_start_lib
53160cc3ecSMilton Miller_zimage_start_lib:
5466a45dd3SPaul Mackerras	/* Work out the offset between the address we were linked at
5566a45dd3SPaul Mackerras	   and the address where we're running. */
566975a783SMichael Ellerman	bl	.+4
576975a783SMichael Ellermanp_base:	mflr	r10		/* r10 now points to runtime addr of p_base */
58f16e9684SCédric Le Goater#ifndef __powerpc64__
596975a783SMichael Ellerman	/* grab the link address of the dynamic section in r11 */
606975a783SMichael Ellerman	addis	r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
616975a783SMichael Ellerman	lwz	r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
626975a783SMichael Ellerman	cmpwi	r11,0
636975a783SMichael Ellerman	beq	3f		/* if not linked -pie */
646975a783SMichael Ellerman	/* get the runtime address of the dynamic section in r12 */
656975a783SMichael Ellerman	.weak	__dynamic_start
666975a783SMichael Ellerman	addis	r12,r10,(__dynamic_start-p_base)@ha
676975a783SMichael Ellerman	addi	r12,r12,(__dynamic_start-p_base)@l
686975a783SMichael Ellerman	subf	r11,r11,r12	/* runtime - linktime offset */
6994b212c2SPaul Mackerras
706975a783SMichael Ellerman	/* The dynamic section contains a series of tagged entries.
716975a783SMichael Ellerman	 * We need the RELA and RELACOUNT entries. */
726975a783SMichael Ellerman	li	r9,0
736975a783SMichael Ellerman	li	r0,0
746975a783SMichael Ellerman9:	lwz	r8,0(r12)	/* get tag */
756975a783SMichael Ellerman	cmpwi	r8,0
766975a783SMichael Ellerman	beq	10f		/* end of list */
776975a783SMichael Ellerman	cmpwi	r8,RELA
786975a783SMichael Ellerman	bne	11f
796975a783SMichael Ellerman	lwz	r9,4(r12)	/* get RELA pointer in r9 */
806975a783SMichael Ellerman	b	12f
816975a783SMichael Ellerman11:	addis	r8,r8,(-RELACOUNT)@ha
826975a783SMichael Ellerman	cmpwi	r8,RELACOUNT@l
836975a783SMichael Ellerman	bne	12f
846975a783SMichael Ellerman	lwz	r0,4(r12)	/* get RELACOUNT value in r0 */
856975a783SMichael Ellerman12:	addi	r12,r12,8
866975a783SMichael Ellerman	b	9b
876975a783SMichael Ellerman
886975a783SMichael Ellerman	/* The relocation section contains a list of relocations.
896975a783SMichael Ellerman	 * We now do the R_PPC_RELATIVE ones, which point to words
906975a783SMichael Ellerman	 * which need to be initialized with addend + offset.
916975a783SMichael Ellerman	 * The R_PPC_RELATIVE ones come first and there are RELACOUNT
926975a783SMichael Ellerman	 * of them. */
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
986975a783SMichael Ellerman
996975a783SMichael Ellerman	add	r9,r9,r11	/* Relocate RELA pointer */
1006975a783SMichael Ellerman	mtctr	r0
1016975a783SMichael Ellerman2:	lbz	r0,4+3(r9)	/* ELF32_R_INFO(reloc->r_info) */
1026975a783SMichael Ellerman	cmpwi	r0,22		/* R_PPC_RELATIVE */
1036975a783SMichael Ellerman	bne	3f
1046975a783SMichael Ellerman	lwz	r12,0(r9)	/* reloc->r_offset */
1056975a783SMichael Ellerman	lwz	r0,8(r9)	/* reloc->r_addend */
1066975a783SMichael Ellerman	add	r0,r0,r11
1076975a783SMichael Ellerman	stwx	r0,r11,r12
1086975a783SMichael Ellerman	addi	r9,r9,12
10968643cfbSOlaf Hering	bdnz	2b
11094b212c2SPaul Mackerras
111cd197ffcSDavid Gibson	/* Do a cache flush for our text, in case the loader didn't */
1126975a783SMichael Ellerman3:	lwz	r9,p_start-p_base(r10)	/* note: these are relocated now */
1136975a783SMichael Ellerman	lwz	r8,p_etext-p_base(r10)
11468643cfbSOlaf Hering4:	dcbf	r0,r9
11594b212c2SPaul Mackerras	icbi	r0,r9
11694b212c2SPaul Mackerras	addi	r9,r9,0x20
117eacb1962SOlaf Hering	cmplw	cr0,r9,r8
11868643cfbSOlaf Hering	blt	4b
11994b212c2SPaul Mackerras	sync
12094b212c2SPaul Mackerras	isync
12194b212c2SPaul Mackerras
122cd197ffcSDavid Gibson	/* Clear the BSS */
1236975a783SMichael Ellerman	lwz	r9,p_bss_start-p_base(r10)
1246975a783SMichael Ellerman	lwz	r8,p_end-p_base(r10)
1256975a783SMichael Ellerman	li	r0,0
1266975a783SMichael Ellerman5:	stw	r0,0(r9)
127cd197ffcSDavid Gibson	addi	r9,r9,4
128cd197ffcSDavid Gibson	cmplw	cr0,r9,r8
129cd197ffcSDavid Gibson	blt	5b
13094b212c2SPaul Mackerras
131cd197ffcSDavid Gibson	/* Possibly set up a custom stack */
1326975a783SMichael Ellerman	lwz	r8,p_pstack-p_base(r10)
133cd197ffcSDavid Gibson	cmpwi	r8,0
134cd197ffcSDavid Gibson	beq	6f
135cd197ffcSDavid Gibson	lwz	r1,0(r8)
136cd197ffcSDavid Gibson	li	r0,0
137cd197ffcSDavid Gibson	stwu	r0,-16(r1)	/* establish a stack frame */
138cd197ffcSDavid Gibson6:
139f16e9684SCédric Le Goater#else /* __powerpc64__ */
140f16e9684SCédric Le Goater	/* Save the prom pointer at p_prom. */
141f16e9684SCédric Le Goater	std	r5,(p_prom-p_base)(r10)
142cd197ffcSDavid Gibson
143f16e9684SCédric Le Goater	/* Set r2 to the TOC. */
144f16e9684SCédric Le Goater	ld	r2,(p_toc-p_base)(r10)
145f16e9684SCédric Le Goater	add	r2,r2,r10
146f16e9684SCédric Le Goater
147f16e9684SCédric Le Goater	/* Grab the link address of the dynamic section in r11. */
148f16e9684SCédric Le Goater	ld	r11,-32768(r2)
149f16e9684SCédric Le Goater	cmpwi	r11,0
150f16e9684SCédric Le Goater	beq	3f              /* if not linked -pie then no dynamic section */
151f16e9684SCédric Le Goater
152f16e9684SCédric Le Goater	ld	r11,(p_dyn-p_base)(r10)
153f16e9684SCédric Le Goater	add	r11,r11,r10
154f16e9684SCédric Le Goater	ld	r9,(p_rela-p_base)(r10)
155f16e9684SCédric Le Goater	add	r9,r9,r10
156f16e9684SCédric Le Goater
1577f664cf9SJeremy Kerr	li	r13,0
158f16e9684SCédric Le Goater	li	r8,0
1597f664cf9SJeremy Kerr9:	ld	r12,0(r11)       /* get tag */
1607f664cf9SJeremy Kerr	cmpdi	r12,0
161f16e9684SCédric Le Goater	beq	12f              /* end of list */
1627f664cf9SJeremy Kerr	cmpdi	r12,RELA
163f16e9684SCédric Le Goater	bne	10f
1647f664cf9SJeremy Kerr	ld	r13,8(r11)       /* get RELA pointer in r13 */
165f16e9684SCédric Le Goater	b	11f
1667f664cf9SJeremy Kerr10:	addis	r12,r12,(-RELACOUNT)@ha
1677f664cf9SJeremy Kerr	cmpdi	r12,RELACOUNT@l
168f16e9684SCédric Le Goater	bne	11f
169f16e9684SCédric Le Goater	ld	r8,8(r11)       /* get RELACOUNT value in r8 */
170f16e9684SCédric Le Goater11:	addi	r11,r11,16
171f16e9684SCédric Le Goater	b	9b
172f16e9684SCédric Le Goater12:
1737f664cf9SJeremy Kerr	cmpdi	r13,0            /* check we have both RELA and RELACOUNT */
174f16e9684SCédric Le Goater	cmpdi	cr1,r8,0
175f16e9684SCédric Le Goater	beq	3f
176f16e9684SCédric Le Goater	beq	cr1,3f
177f16e9684SCédric Le Goater
178f16e9684SCédric Le Goater	/* Calcuate the runtime offset. */
1797f664cf9SJeremy Kerr	subf	r13,r13,r9
180f16e9684SCédric Le Goater
181f16e9684SCédric Le Goater	/* Run through the list of relocations and process the
182f16e9684SCédric Le Goater	 * R_PPC64_RELATIVE ones. */
183f16e9684SCédric Le Goater	mtctr	r8
184f16e9684SCédric Le Goater13:	ld	r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
185f16e9684SCédric Le Goater	cmpdi	r0,22           /* R_PPC64_RELATIVE */
186f16e9684SCédric Le Goater	bne	3f
1877f664cf9SJeremy Kerr	ld	r12,0(r9)        /* reloc->r_offset */
188f16e9684SCédric Le Goater	ld	r0,16(r9)       /* reloc->r_addend */
1897f664cf9SJeremy Kerr	add	r0,r0,r13
1907f664cf9SJeremy Kerr	stdx	r0,r13,r12
191f16e9684SCédric Le Goater	addi	r9,r9,24
192f16e9684SCédric Le Goater	bdnz	13b
193f16e9684SCédric Le Goater
194f16e9684SCédric Le Goater	/* Do a cache flush for our text, in case the loader didn't */
195f16e9684SCédric Le Goater3:	ld	r9,p_start-p_base(r10)	/* note: these are relocated now */
196f16e9684SCédric Le Goater	ld	r8,p_etext-p_base(r10)
197f16e9684SCédric Le Goater4:	dcbf	r0,r9
198f16e9684SCédric Le Goater	icbi	r0,r9
199f16e9684SCédric Le Goater	addi	r9,r9,0x20
200f16e9684SCédric Le Goater	cmpld	cr0,r9,r8
201f16e9684SCédric Le Goater	blt	4b
202f16e9684SCédric Le Goater	sync
203f16e9684SCédric Le Goater	isync
204f16e9684SCédric Le Goater
205f16e9684SCédric Le Goater	/* Clear the BSS */
206f16e9684SCédric Le Goater	ld	r9,p_bss_start-p_base(r10)
207f16e9684SCédric Le Goater	ld	r8,p_end-p_base(r10)
208f16e9684SCédric Le Goater	li	r0,0
209f16e9684SCédric Le Goater5:	std	r0,0(r9)
210f16e9684SCédric Le Goater	addi	r9,r9,8
211f16e9684SCédric Le Goater	cmpld	cr0,r9,r8
212f16e9684SCédric Le Goater	blt	5b
213f16e9684SCédric Le Goater
214f16e9684SCédric Le Goater	/* Possibly set up a custom stack */
215f16e9684SCédric Le Goater	ld	r8,p_pstack-p_base(r10)
216f16e9684SCédric Le Goater	cmpdi	r8,0
217f16e9684SCédric Le Goater	beq	6f
218f16e9684SCédric Le Goater	ld	r1,0(r8)
219f16e9684SCédric Le Goater	li	r0,0
2208c06f0d9SJeremy Kerr	stdu	r0,-112(r1)	/* establish a stack frame */
221f16e9684SCédric Le Goater6:
222f16e9684SCédric Le Goater#endif  /* __powerpc64__ */
223cd197ffcSDavid Gibson	/* Call platform_init() */
224cd197ffcSDavid Gibson	bl	platform_init
225cd197ffcSDavid Gibson
226cd197ffcSDavid Gibson	/* Call start */
227cd197ffcSDavid Gibson	b	start
22893d39210SCédric Le Goater
22993d39210SCédric Le Goater#ifdef __powerpc64__
23093d39210SCédric Le Goater
23193d39210SCédric Le Goater#define PROM_FRAME_SIZE 512
23293d39210SCédric Le Goater#define SAVE_GPR(n, base)       std     n,8*(n)(base)
23393d39210SCédric Le Goater#define REST_GPR(n, base)       ld      n,8*(n)(base)
23493d39210SCédric Le Goater#define SAVE_2GPRS(n, base)     SAVE_GPR(n, base); SAVE_GPR(n+1, base)
23593d39210SCédric Le Goater#define SAVE_4GPRS(n, base)     SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
23693d39210SCédric Le Goater#define SAVE_8GPRS(n, base)     SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
23793d39210SCédric Le Goater#define SAVE_10GPRS(n, base)    SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
23893d39210SCédric Le Goater#define REST_2GPRS(n, base)     REST_GPR(n, base); REST_GPR(n+1, base)
23993d39210SCédric Le Goater#define REST_4GPRS(n, base)     REST_2GPRS(n, base); REST_2GPRS(n+2, base)
24093d39210SCédric Le Goater#define REST_8GPRS(n, base)     REST_4GPRS(n, base); REST_4GPRS(n+4, base)
24193d39210SCédric Le Goater#define REST_10GPRS(n, base)    REST_8GPRS(n, base); REST_2GPRS(n+8, 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)
25293d39210SCédric Le Goater	SAVE_GPR(13, r1)
25393d39210SCédric Le Goater	SAVE_8GPRS(14, r1)
25493d39210SCédric Le Goater	SAVE_10GPRS(22, r1)
25593d39210SCédric Le Goater	mfcr    r10
25693d39210SCédric Le Goater	std     r10,8*32(r1)
25793d39210SCédric Le Goater	mfmsr   r10
25893d39210SCédric Le Goater	std     r10,8*33(r1)
25993d39210SCédric Le Goater
26093d39210SCédric Le Goater	/* remove MSR_LE from msr but keep MSR_SF */
26193d39210SCédric Le Goater	mfmsr	r10
26293d39210SCédric Le Goater	rldicr	r10,r10,0,62
26393d39210SCédric Le Goater	mtsrr1	r10
26493d39210SCédric Le Goater
26593d39210SCédric Le Goater	/* Load FW address, set LR to label 1, and jump to FW */
26693d39210SCédric Le Goater	bl	0f
26793d39210SCédric Le Goater0:	mflr	r10
26893d39210SCédric Le Goater	addi	r11,r10,(1f-0b)
26993d39210SCédric Le Goater	mtlr	r11
27093d39210SCédric Le Goater
27193d39210SCédric Le Goater	ld	r10,(p_prom-0b)(r10)
27293d39210SCédric Le Goater	mtsrr0	r10
27393d39210SCédric Le Goater
27493d39210SCédric Le Goater	rfid
27593d39210SCédric Le Goater
27693d39210SCédric Le Goater1:	/* Return from OF */
277147c0516SCédric Le Goater	FIXUP_ENDIAN
27893d39210SCédric Le Goater
27993d39210SCédric Le Goater	/* Restore registers and return. */
28093d39210SCédric Le Goater	rldicl  r1,r1,0,32
28193d39210SCédric Le Goater
28293d39210SCédric Le Goater	/* Restore the MSR (back to 64 bits) */
28393d39210SCédric Le Goater	ld      r10,8*(33)(r1)
28493d39210SCédric Le Goater	mtmsr	r10
28593d39210SCédric Le Goater	isync
28693d39210SCédric Le Goater
28793d39210SCédric Le Goater	/* Restore other registers */
28893d39210SCédric Le Goater	REST_GPR(2, r1)
28993d39210SCédric Le Goater	REST_GPR(13, r1)
29093d39210SCédric Le Goater	REST_8GPRS(14, r1)
29193d39210SCédric Le Goater	REST_10GPRS(22, r1)
29293d39210SCédric Le Goater	ld      r10,8*32(r1)
29393d39210SCédric Le Goater	mtcr	r10
29493d39210SCédric Le Goater
29593d39210SCédric Le Goater	addi    r1,r1,PROM_FRAME_SIZE
29693d39210SCédric Le Goater	ld      r0,16(r1)
29793d39210SCédric Le Goater	mtlr    r0
29893d39210SCédric Le Goater	blr
29993d39210SCédric Le Goater#endif
300