• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (C) Paul Mackerras 1997.
3 *
4 * Adapted for 64 bit LE PowerPC by Andrew Tauferner
5 *
6 * 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 *
11 */
12
13#include "ppc_asm.h"
14
15RELA = 7
16RELACOUNT = 0x6ffffff9
17
18	.data
19	/* 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	 */
23	.globl	_zimage_start_opd
24_zimage_start_opd:
25	.long	0x500000, 0, 0, 0
26	.text
27	b	_zimage_start
28
29#ifdef __powerpc64__
30.balign 8
31p_start:	.llong	_start
32p_etext:	.llong	_etext
33p_bss_start:	.llong	__bss_start
34p_end:		.llong	_end
35
36p_toc:		.llong	__toc_start + 0x8000 - p_base
37p_dyn:		.llong	__dynamic_start - p_base
38p_rela:		.llong	__rela_dyn_start - p_base
39p_prom:		.llong	0
40	.weak	_platform_stack_top
41p_pstack:	.llong	_platform_stack_top
42#else
43p_start:	.long	_start
44p_etext:	.long	_etext
45p_bss_start:	.long	__bss_start
46p_end:		.long	_end
47
48	.weak	_platform_stack_top
49p_pstack:	.long	_platform_stack_top
50#endif
51
52	.weak	_zimage_start
53_zimage_start:
54	.globl	_zimage_start_lib
55_zimage_start_lib:
56	/* Work out the offset between the address we were linked at
57	   and the address where we're running. */
58	bl	.+4
59p_base:	mflr	r10		/* r10 now points to runtime addr of p_base */
60#ifndef __powerpc64__
61	/* grab the link address of the dynamic section in r11 */
62	addis	r11,r10,(_GLOBAL_OFFSET_TABLE_-p_base)@ha
63	lwz	r11,(_GLOBAL_OFFSET_TABLE_-p_base)@l(r11)
64	cmpwi	r11,0
65	beq	3f		/* if not linked -pie */
66	/* get the runtime address of the dynamic section in r12 */
67	.weak	__dynamic_start
68	addis	r12,r10,(__dynamic_start-p_base)@ha
69	addi	r12,r12,(__dynamic_start-p_base)@l
70	subf	r11,r11,r12	/* runtime - linktime offset */
71
72	/* The dynamic section contains a series of tagged entries.
73	 * We need the RELA and RELACOUNT entries. */
74	li	r9,0
75	li	r0,0
769:	lwz	r8,0(r12)	/* get tag */
77	cmpwi	r8,0
78	beq	10f		/* end of list */
79	cmpwi	r8,RELA
80	bne	11f
81	lwz	r9,4(r12)	/* get RELA pointer in r9 */
82	b	12f
8311:	addis	r8,r8,(-RELACOUNT)@ha
84	cmpwi	r8,RELACOUNT@l
85	bne	12f
86	lwz	r0,4(r12)	/* get RELACOUNT value in r0 */
8712:	addi	r12,r12,8
88	b	9b
89
90	/* The relocation section contains a list of relocations.
91	 * We now do the R_PPC_RELATIVE ones, which point to words
92	 * which need to be initialized with addend + offset.
93	 * The R_PPC_RELATIVE ones come first and there are RELACOUNT
94	 * of them. */
9510:	/* skip relocation if we don't have both */
96	cmpwi	r0,0
97	beq	3f
98	cmpwi	r9,0
99	beq	3f
100
101	add	r9,r9,r11	/* Relocate RELA pointer */
102	mtctr	r0
1032:	lbz	r0,4+3(r9)	/* ELF32_R_INFO(reloc->r_info) */
104	cmpwi	r0,22		/* R_PPC_RELATIVE */
105	bne	3f
106	lwz	r12,0(r9)	/* reloc->r_offset */
107	lwz	r0,8(r9)	/* reloc->r_addend */
108	add	r0,r0,r11
109	stwx	r0,r11,r12
110	addi	r9,r9,12
111	bdnz	2b
112
113	/* Do a cache flush for our text, in case the loader didn't */
1143:	lwz	r9,p_start-p_base(r10)	/* note: these are relocated now */
115	lwz	r8,p_etext-p_base(r10)
1164:	dcbf	r0,r9
117	icbi	r0,r9
118	addi	r9,r9,0x20
119	cmplw	cr0,r9,r8
120	blt	4b
121	sync
122	isync
123
124	/* Clear the BSS */
125	lwz	r9,p_bss_start-p_base(r10)
126	lwz	r8,p_end-p_base(r10)
127	li	r0,0
1285:	stw	r0,0(r9)
129	addi	r9,r9,4
130	cmplw	cr0,r9,r8
131	blt	5b
132
133	/* Possibly set up a custom stack */
134	lwz	r8,p_pstack-p_base(r10)
135	cmpwi	r8,0
136	beq	6f
137	lwz	r1,0(r8)
138	li	r0,0
139	stwu	r0,-16(r1)	/* establish a stack frame */
1406:
141#else /* __powerpc64__ */
142	/* Save the prom pointer at p_prom. */
143	std	r5,(p_prom-p_base)(r10)
144
145	/* Set r2 to the TOC. */
146	ld	r2,(p_toc-p_base)(r10)
147	add	r2,r2,r10
148
149	/* Grab the link address of the dynamic section in r11. */
150	ld	r11,-32768(r2)
151	cmpwi	r11,0
152	beq	3f              /* if not linked -pie then no dynamic section */
153
154	ld	r11,(p_dyn-p_base)(r10)
155	add	r11,r11,r10
156	ld	r9,(p_rela-p_base)(r10)
157	add	r9,r9,r10
158
159	li	r13,0
160	li	r8,0
1619:	ld	r12,0(r11)       /* get tag */
162	cmpdi	r12,0
163	beq	12f              /* end of list */
164	cmpdi	r12,RELA
165	bne	10f
166	ld	r13,8(r11)       /* get RELA pointer in r13 */
167	b	11f
16810:	addis	r12,r12,(-RELACOUNT)@ha
169	cmpdi	r12,RELACOUNT@l
170	bne	11f
171	ld	r8,8(r11)       /* get RELACOUNT value in r8 */
17211:	addi	r11,r11,16
173	b	9b
17412:
175	cmpdi	r13,0            /* check we have both RELA and RELACOUNT */
176	cmpdi	cr1,r8,0
177	beq	3f
178	beq	cr1,3f
179
180	/* Calcuate the runtime offset. */
181	subf	r13,r13,r9
182
183	/* Run through the list of relocations and process the
184	 * R_PPC64_RELATIVE ones. */
185	mtctr	r8
18613:	ld	r0,8(r9)        /* ELF64_R_TYPE(reloc->r_info) */
187	cmpdi	r0,22           /* R_PPC64_RELATIVE */
188	bne	3f
189	ld	r12,0(r9)        /* reloc->r_offset */
190	ld	r0,16(r9)       /* reloc->r_addend */
191	add	r0,r0,r13
192	stdx	r0,r13,r12
193	addi	r9,r9,24
194	bdnz	13b
195
196	/* Do a cache flush for our text, in case the loader didn't */
1973:	ld	r9,p_start-p_base(r10)	/* note: these are relocated now */
198	ld	r8,p_etext-p_base(r10)
1994:	dcbf	r0,r9
200	icbi	r0,r9
201	addi	r9,r9,0x20
202	cmpld	cr0,r9,r8
203	blt	4b
204	sync
205	isync
206
207	/* Clear the BSS */
208	ld	r9,p_bss_start-p_base(r10)
209	ld	r8,p_end-p_base(r10)
210	li	r0,0
2115:	std	r0,0(r9)
212	addi	r9,r9,8
213	cmpld	cr0,r9,r8
214	blt	5b
215
216	/* Possibly set up a custom stack */
217	ld	r8,p_pstack-p_base(r10)
218	cmpdi	r8,0
219	beq	6f
220	ld	r1,0(r8)
221	li	r0,0
222	stdu	r0,-112(r1)	/* establish a stack frame */
2236:
224#endif  /* __powerpc64__ */
225	/* Call platform_init() */
226	bl	platform_init
227
228	/* Call start */
229	b	start
230
231#ifdef __powerpc64__
232
233#define PROM_FRAME_SIZE 512
234#define SAVE_GPR(n, base)       std     n,8*(n)(base)
235#define REST_GPR(n, base)       ld      n,8*(n)(base)
236#define SAVE_2GPRS(n, base)     SAVE_GPR(n, base); SAVE_GPR(n+1, base)
237#define SAVE_4GPRS(n, base)     SAVE_2GPRS(n, base); SAVE_2GPRS(n+2, base)
238#define SAVE_8GPRS(n, base)     SAVE_4GPRS(n, base); SAVE_4GPRS(n+4, base)
239#define SAVE_10GPRS(n, base)    SAVE_8GPRS(n, base); SAVE_2GPRS(n+8, base)
240#define REST_2GPRS(n, base)     REST_GPR(n, base); REST_GPR(n+1, base)
241#define REST_4GPRS(n, base)     REST_2GPRS(n, base); REST_2GPRS(n+2, base)
242#define REST_8GPRS(n, base)     REST_4GPRS(n, base); REST_4GPRS(n+4, base)
243#define REST_10GPRS(n, base)    REST_8GPRS(n, base); REST_2GPRS(n+8, base)
244
245/* prom handles the jump into and return from firmware.  The prom args pointer
246   is loaded in r3. */
247.globl prom
248prom:
249	mflr	r0
250	std	r0,16(r1)
251	stdu	r1,-PROM_FRAME_SIZE(r1) /* Save SP and create stack space */
252
253	SAVE_GPR(2, r1)
254	SAVE_GPR(13, r1)
255	SAVE_8GPRS(14, r1)
256	SAVE_10GPRS(22, r1)
257	mfcr    r10
258	std     r10,8*32(r1)
259	mfmsr   r10
260	std     r10,8*33(r1)
261
262	/* remove MSR_LE from msr but keep MSR_SF */
263	mfmsr	r10
264	rldicr	r10,r10,0,62
265	mtsrr1	r10
266
267	/* Load FW address, set LR to label 1, and jump to FW */
268	bl	0f
2690:	mflr	r10
270	addi	r11,r10,(1f-0b)
271	mtlr	r11
272
273	ld	r10,(p_prom-0b)(r10)
274	mtsrr0	r10
275
276	rfid
277
2781:	/* Return from OF */
279	FIXUP_ENDIAN
280
281	/* Restore registers and return. */
282	rldicl  r1,r1,0,32
283
284	/* Restore the MSR (back to 64 bits) */
285	ld      r10,8*(33)(r1)
286	mtmsr	r10
287	isync
288
289	/* Restore other registers */
290	REST_GPR(2, r1)
291	REST_GPR(13, r1)
292	REST_8GPRS(14, r1)
293	REST_10GPRS(22, r1)
294	ld      r10,8*32(r1)
295	mtcr	r10
296
297	addi    r1,r1,PROM_FRAME_SIZE
298	ld      r0,16(r1)
299	mtlr    r0
300	blr
301#endif
302