locore-v4.S revision 193846
1/*	$NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $	*/
2
3/*-
4 * Copyright (C) 1994-1997 Mark Brinicombe
5 * Copyright (C) 1994 Brini
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by Brini.
19 * 4. The name of Brini may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 */
34
35#include "assym.s"
36#include <sys/syscall.h>
37#include <machine/asm.h>
38#include <machine/armreg.h>
39#include <machine/pte.h>
40__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 193846 2009-06-09 17:21:47Z marcel $");
41
42/* What size should this really be ? It is only used by initarm() */
43#define INIT_ARM_STACK_SIZE	2048
44
45/*
46 * This is for kvm_mkdb, and should be the address of the beginning
47 * of the kernel text segment (not necessarily the same as kernbase).
48 */
49
50
51#define	CPWAIT_BRANCH							 \
52	sub	pc, pc, #4
53
54#define	CPWAIT(tmp)							 \
55	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
56	mov	tmp, tmp		/* wait for it to complete */	;\
57	CPWAIT_BRANCH			/* branch to next insn */
58
59	.text
60	.align	0
61.globl kernbase
62.set kernbase,KERNBASE
63.globl physaddr
64.set physaddr,PHYSADDR
65
66ENTRY_NP(btext)
67
68ASENTRY_NP(_start)
69
70/*
71 * Move metadata ptr to r12 (ip)
72 */
73
74	mov	ip, r0
75
76	/* Make sure interrupts are disabled. */
77	mrs	r7, cpsr
78	orr	r7, r7, #(I32_bit|F32_bit)
79	msr	cpsr_c, r7
80
81#if defined (FLASHADDR) && defined(LOADERRAMADDR)
82	/* Check if we're running from flash. */
83	ldr	r7, =FLASHADDR
84	/*
85	 * If we're running with MMU disabled, test against the
86	 * physical address instead.
87	 */
88	mrc     p15, 0, r2, c1, c0, 0
89	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
90	ldreq	r8, =PHYSADDR
91	ldrne	r8, =LOADERRAMADDR
92	cmp	r7, r8
93	bls 	flash_lower
94	cmp	r7, pc
95	bhi	from_ram
96	b	do_copy
97
98flash_lower:
99	cmp	r8, pc
100	bls	from_ram
101do_copy:
102	ldr	r9, =KERNBASE
103	adr	r1, _start
104	ldr	r0, Lreal_start
105	ldr	r2, Lend
106	sub	r2, r2, r0
107	sub	r0, r0, r9
108	add	r0, r0, r8
109	mov	r4, r0
110	bl	memcpy
111	ldr	r0, Lram_offset
112	add	pc, r4, r0
113Lram_offset:	.word from_ram-_C_LABEL(_start)
114from_ram:
115	nop
116#endif
117	adr	r7, Lunmapped
118	bic     r7, r7, #0xf0000000
119	orr     r7, r7, #PHYSADDR
120
121
122disable_mmu:
123	/* Disable MMU for a while */
124	mrc     p15, 0, r2, c1, c0, 0
125	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
126	    CPU_CONTROL_WBUF_ENABLE)
127	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
128	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
129	mcr     p15, 0, r2, c1, c0, 0
130
131	nop
132	nop
133	nop
134	mov	pc, r7
135Lunmapped:
136#ifdef STARTUP_PAGETABLE_ADDR
137	/* build page table from scratch */
138	ldr	r0, Lstartup_pagetable
139	adr	r4, mmu_init_table
140	b	3f
141
1422:
143	str	r3, [r0, r2]
144	add	r2, r2, #4
145	add	r3, r3, #(L1_S_SIZE)
146	adds	r1, r1, #-1
147	bhi	2b
1483:
149	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
150	cmp	r1, #0
151	adrne	r5, 2b
152	bicne	r5, r5, #0xf0000000
153	orrne	r5, r5, #PHYSADDR
154	movne	pc, r5
155
156	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
157	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
158
159	/* Set the Domain Access register.  Very important! */
160	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
161	mcr	p15, 0, r0, c3, c0, 0
162	/* Enable MMU */
163	mrc	p15, 0, r0, c1, c0, 0
164	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
165	mcr	p15, 0, r0, c1, c0, 0
166	nop
167	nop
168	nop
169	CPWAIT(r0)
170
171#endif
172mmu_done:
173	nop
174	adr	r1, .Lstart
175	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
176	sub	r2, r2, r1		/* get zero init data */
177	mov	r3, #0
178.L1:
179	str	r3, [r1], #0x0004	/* get zero init data */
180	subs	r2, r2, #4
181	bgt	.L1
182	ldr	pc, .Lvirt_done
183
184virt_done:
185	mov	r0, ip			/* Load argument: metadata ptr */
186
187	mov	fp, #0			/* trace back starts here */
188	bl	_C_LABEL(initarm)	/* Off we go */
189
190	/* init arm will return the new stack pointer. */
191	mov	sp, r0
192
193	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
194
195	adr	r0, .Lmainreturned
196	b	_C_LABEL(panic)
197	/* NOTREACHED */
198#ifdef STARTUP_PAGETABLE_ADDR
199#define MMU_INIT(va,pa,n_sec,attr) \
200	.word	n_sec					    ; \
201	.word	4*((va)>>L1_S_SHIFT)			    ; \
202	.word	(pa)|(attr)				    ;
203
204Lvirtaddr:
205	.word	KERNVIRTADDR
206Lphysaddr:
207	.word	KERNPHYSADDR
208Lreal_start:
209	.word	_start
210Lend:
211	.word	_edata
212Lstartup_pagetable:
213	.word	STARTUP_PAGETABLE_ADDR
214mmu_init_table:
215	/* fill all table VA==PA */
216	/* map SDRAM VA==PA, WT cacheable */
217	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
218	/* map VA 0xc0000000..0xc3ffffff to PA */
219	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
220
221	.word 0	/* end of table */
222#endif
223.Lstart:
224	.word	_edata
225	.word	_end
226	.word	svcstk + INIT_ARM_STACK_SIZE
227
228#if defined(FLASHADDR) && defined(LOADERRAMADDR)
229.L_arm_memcpy:
230        .word   _C_LABEL(_arm_memcpy)
231#endif
232
233.Lvirt_done:
234	.word	virt_done
235.Lmainreturned:
236	.asciz	"main() returned"
237	.align	0
238
239	.bss
240svcstk:
241	.space	INIT_ARM_STACK_SIZE
242
243	.text
244	.align	0
245
246.Lcpufuncs:
247	.word	_C_LABEL(cpufuncs)
248
249ENTRY_NP(cpu_halt)
250	mrs     r2, cpsr
251	bic	r2, r2, #(PSR_MODE)
252	orr     r2, r2, #(PSR_SVC32_MODE)
253	orr	r2, r2, #(I32_bit | F32_bit)
254	msr     cpsr_all, r2
255
256	ldr	r4, .Lcpu_reset_address
257	ldr	r4, [r4]
258
259	ldr	r0, .Lcpufuncs
260	mov	lr, pc
261	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
262	mov	lr, pc
263	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
264
265	/*
266	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
267	 * necessary.
268	 */
269
270	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
271	ldr	r1, [r1]
272	cmp	r1, #0
273	mov	r2, #0
274
275	/*
276	 * MMU & IDC off, 32 bit program & data space
277	 * Hurl ourselves into the ROM
278	 */
279	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
280	mcr     15, 0, r0, c1, c0, 0
281	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
282	mov     pc, r4
283
284	/*
285	 * _cpu_reset_address contains the address to branch to, to complete
286	 * the cpu reset after turning the MMU off
287	 * This variable is provided by the hardware specific code
288	 */
289.Lcpu_reset_address:
290	.word	_C_LABEL(cpu_reset_address)
291
292	/*
293	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
294	 * v4 MMU disable instruction needs executing... it is an illegal instruction
295	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
296	 * instruction / data-abort / reset loop.
297	 */
298.Lcpu_reset_needs_v4_MMU_disable:
299	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
300
301
302/*
303 * setjump + longjmp
304 */
305ENTRY(setjmp)
306	stmia	r0, {r4-r14}
307	mov	r0, #0x00000000
308	RET
309
310ENTRY(longjmp)
311	ldmia	r0, {r4-r14}
312	mov	r0, #0x00000001
313	RET
314
315	.data
316	.global _C_LABEL(esym)
317_C_LABEL(esym):	.word	_C_LABEL(end)
318
319ENTRY_NP(abort)
320	b	_C_LABEL(abort)
321
322ENTRY_NP(sigcode)
323	mov	r0, sp
324	swi	SYS_sigreturn
325
326	/* Well if that failed we better exit quick ! */
327
328	swi	SYS_exit
329	b	. - 8
330
331	.align	0
332	.global _C_LABEL(esigcode)
333		_C_LABEL(esigcode):
334
335	.data
336	.global szsigcode
337szsigcode:
338	.long esigcode-sigcode
339/* End of locore.S */
340