xref: /openbmc/linux/arch/powerpc/boot/crt0.S (revision 93d39210)
1/*
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 *
9 * NOTE: this code runs in 32 bit mode, is position-independent,
10 * and is packaged as ELF32.
11 */
12
13#include "ppc_asm.h"
14
15	.text
16	/* 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	 */
20	.globl	_zimage_start_opd
21_zimage_start_opd:
22	.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
31
32	.weak	_zimage_start
33	.globl	_zimage_start
34_zimage_start:
35	.globl	_zimage_start_lib
36_zimage_start_lib:
37	/* Work out the offset between the address we were linked at
38	   and the address where we're running. */
39	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 */
51
52	/* 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
79	beq	3f
80	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
93	bdnz	2b
94
95	/* Do a cache flush for our text, in case the loader didn't */
963:	lwz	r9,p_start-p_base(r10)	/* note: these are relocated now */
97	lwz	r8,p_etext-p_base(r10)
984:	dcbf	r0,r9
99	icbi	r0,r9
100	addi	r9,r9,0x20
101	cmplw	cr0,r9,r8
102	blt	4b
103	sync
104	isync
105
106	/* Clear the BSS */
107	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)
111	addi	r9,r9,4
112	cmplw	cr0,r9,r8
113	blt	5b
114
115	/* Possibly set up a custom stack */
116	lwz	r8,p_pstack-p_base(r10)
117	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 */
128	b	start
129
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
200