xref: /freebsd/sys/arm/arm/locore.S (revision e39e854e27f53a784c3982cbeb68f4ad1cfd9162)
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$");
41
42/* What size should this really be ? It is only used by initarm() */
43#define INIT_ARM_STACK_SIZE	2048
44
45#define	CPWAIT_BRANCH							 \
46	sub	pc, pc, #4
47
48#define	CPWAIT(tmp)							 \
49	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
50	mov	tmp, tmp		/* wait for it to complete */	;\
51	CPWAIT_BRANCH			/* branch to next insn */
52
53/*
54 * This is for kvm_mkdb, and should be the address of the beginning
55 * of the kernel text segment (not necessarily the same as kernbase).
56 */
57	.text
58	.align	0
59.globl kernbase
60.set kernbase,KERNBASE
61.globl physaddr
62.set physaddr,PHYSADDR
63
64ENTRY_NP(btext)
65
66/*
67 * On entry:
68 *	r0 - metadata pointer or 0
69 *	r1 - if (r0 == 0) then metadata pointer
70 */
71ASENTRY_NP(_start)
72
73	/* Move metadata ptr to r12 (ip) */
74	mov	ip, r0
75	ldr	r0, =0
76	cmp	ip, r0
77	bne	1f
78	mov	ip, r1
791:
80	/* Make sure interrupts are disabled. */
81	mrs	r7, cpsr
82	orr	r7, r7, #(I32_bit|F32_bit)
83	msr	cpsr_c, r7
84
85#if defined (FLASHADDR) && defined(LOADERRAMADDR)
86	/* Check if we're running from flash. */
87	ldr	r7, =FLASHADDR
88	/*
89	 * If we're running with MMU disabled, test against the
90	 * physical address instead.
91	 */
92	mrc     p15, 0, r2, c1, c0, 0
93	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
94	ldreq	r8, =PHYSADDR
95	ldrne	r8, =LOADERRAMADDR
96	cmp	r7, r8
97	bls 	flash_lower
98	cmp	r7, pc
99	bhi	from_ram
100	b	do_copy
101
102flash_lower:
103	cmp	r8, pc
104	bls	from_ram
105do_copy:
106	ldr	r9, =KERNBASE
107	adr	r1, _start
108	ldr	r0, Lreal_start
109	ldr	r2, Lend
110	sub	r2, r2, r0
111	sub	r0, r0, r9
112	add	r0, r0, r8
113	mov	r4, r0
114	bl	memcpy
115	ldr	r0, Lram_offset
116	add	pc, r4, r0
117Lram_offset:	.word from_ram-_C_LABEL(_start)
118from_ram:
119	nop
120#endif
121	adr	r7, Lunmapped
122	bic     r7, r7, #0xf0000000
123	orr     r7, r7, #PHYSADDR
124
125
126disable_mmu:
127	/* Disable MMU for a while */
128	mrc     p15, 0, r2, c1, c0, 0
129	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
130	    CPU_CONTROL_WBUF_ENABLE)
131	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
132	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
133	mcr     p15, 0, r2, c1, c0, 0
134
135	nop
136	nop
137	nop
138	mov	pc, r7
139Lunmapped:
140#ifdef STARTUP_PAGETABLE_ADDR
141	/* build page table from scratch */
142	ldr	r0, Lstartup_pagetable
143	adr	r4, mmu_init_table
144	b	3f
145
1462:
147	str	r3, [r0, r2]
148	add	r2, r2, #4
149	add	r3, r3, #(L1_S_SIZE)
150	adds	r1, r1, #-1
151	bhi	2b
1523:
153	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
154	cmp	r1, #0
155	adrne	r5, 2b
156	bicne	r5, r5, #0xf0000000
157	orrne	r5, r5, #PHYSADDR
158	movne	pc, r5
159
160	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
161	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
162
163	/* Set the Domain Access register.  Very important! */
164	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
165	mcr	p15, 0, r0, c3, c0, 0
166	/* Enable MMU */
167	mrc	p15, 0, r0, c1, c0, 0
168	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
169	mcr	p15, 0, r0, c1, c0, 0
170	nop
171	nop
172	nop
173	CPWAIT(r0)
174
175#endif
176mmu_done:
177	nop
178	adr	r1, .Lstart
179	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
180	sub	r2, r2, r1		/* get zero init data */
181	mov	r3, #0
182.L1:
183	str	r3, [r1], #0x0004	/* get zero init data */
184	subs	r2, r2, #4
185	bgt	.L1
186	ldr	pc, .Lvirt_done
187
188virt_done:
189	mov	r0, ip			/* Load argument: metadata ptr */
190
191	mov	fp, #0			/* trace back starts here */
192	bl	_C_LABEL(initarm)	/* Off we go */
193
194	/* init arm will return the new stack pointer. */
195	mov	sp, r0
196
197	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
198
199	adr	r0, .Lmainreturned
200	b	_C_LABEL(panic)
201	/* NOTREACHED */
202#ifdef STARTUP_PAGETABLE_ADDR
203#define MMU_INIT(va,pa,n_sec,attr) \
204	.word	n_sec					    ; \
205	.word	4*((va)>>L1_S_SHIFT)			    ; \
206	.word	(pa)|(attr)				    ;
207
208Lvirtaddr:
209	.word	KERNVIRTADDR
210Lphysaddr:
211	.word	KERNPHYSADDR
212Lreal_start:
213	.word	_start
214Lend:
215	.word	_edata
216Lstartup_pagetable:
217	.word	STARTUP_PAGETABLE_ADDR
218mmu_init_table:
219	/* fill all table VA==PA */
220	/* map SDRAM VA==PA, WT cacheable */
221	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
222	/* map VA 0xc0000000..0xc3ffffff to PA */
223	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
224
225	.word 0	/* end of table */
226#endif
227.Lstart:
228	.word	_edata
229	.word	_end
230	.word	svcstk + INIT_ARM_STACK_SIZE
231
232.Lvirt_done:
233	.word	virt_done
234.Lmainreturned:
235	.asciz	"main() returned"
236	.align	0
237
238	.bss
239svcstk:
240	.space	INIT_ARM_STACK_SIZE
241
242	.text
243	.align	0
244
245.Lcpufuncs:
246	.word	_C_LABEL(cpufuncs)
247
248ENTRY_NP(cpu_halt)
249	mrs     r2, cpsr
250	bic	r2, r2, #(PSR_MODE)
251	orr     r2, r2, #(PSR_SVC32_MODE)
252	orr	r2, r2, #(I32_bit | F32_bit)
253	msr     cpsr_all, r2
254
255	ldr	r4, .Lcpu_reset_address
256	ldr	r4, [r4]
257
258	ldr	r0, .Lcpufuncs
259	mov	lr, pc
260	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
261	mov	lr, pc
262	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
263
264	/*
265	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
266	 * necessary.
267	 */
268
269	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
270	ldr	r1, [r1]
271	cmp	r1, #0
272	mov	r2, #0
273
274	/*
275	 * MMU & IDC off, 32 bit program & data space
276	 * Hurl ourselves into the ROM
277	 */
278	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
279	mcr     15, 0, r0, c1, c0, 0
280	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
281	mov     pc, r4
282
283	/*
284	 * _cpu_reset_address contains the address to branch to, to complete
285	 * the cpu reset after turning the MMU off
286	 * This variable is provided by the hardware specific code
287	 */
288.Lcpu_reset_address:
289	.word	_C_LABEL(cpu_reset_address)
290
291	/*
292	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
293	 * v4 MMU disable instruction needs executing... it is an illegal instruction
294	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
295	 * instruction / data-abort / reset loop.
296	 */
297.Lcpu_reset_needs_v4_MMU_disable:
298	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
299
300
301/*
302 * setjump + longjmp
303 */
304ENTRY(setjmp)
305	stmia	r0, {r4-r14}
306	mov	r0, #0x00000000
307	RET
308
309ENTRY(longjmp)
310	ldmia	r0, {r4-r14}
311	mov	r0, #0x00000001
312	RET
313
314	.data
315	.global _C_LABEL(esym)
316_C_LABEL(esym):	.word	_C_LABEL(end)
317
318ENTRY_NP(abort)
319	b	_C_LABEL(abort)
320
321ENTRY_NP(sigcode)
322	mov	r0, sp
323	swi	SYS_sigreturn
324
325	/* Well if that failed we better exit quick ! */
326
327	swi	SYS_exit
328	b	. - 8
329
330	.align	0
331	.global _C_LABEL(esigcode)
332		_C_LABEL(esigcode):
333
334	.data
335	.global szsigcode
336szsigcode:
337	.long esigcode-sigcode
338/* End of locore.S */
339