xref: /freebsd/sys/arm/arm/locore.S (revision 9336e0699bda8a301cd2bfa37106b6ec5e32012e)
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/*
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#if defined (FLASHADDR) && defined(LOADERRAMADDR)
70	/* Check if we're running from flash. */
71	ldr	r7, =FLASHADDR
72	/*
73	 * If we're running with MMU disabled, test against the
74	 * physical address instead.
75	 */
76	mrc     p15, 0, r2, c1, c0, 0
77	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
78	ldreq	r8, =PHYSADDR
79	ldrne	r8, =LOADERRAMADDR
80	cmp	r7, r8
81	bls 	flash_lower
82	cmp	r7, pc
83	bhi	from_ram
84	b	do_copy
85
86flash_lower:
87	cmp	r8, pc
88	bls	from_ram
89do_copy:
90	ldr	r9, =KERNBASE
91	adr	r1, _start
92	ldr	r0, Lreal_start
93	ldr	r2, Lend
94	sub	r2, r2, r0
95	sub	r0, r0, r9
96	add	r0, r0, r8
97	mov	r4, r0
98	bl	memcpy
99	ldr	r0, Lram_offset
100	add	pc, r4, r0
101Lram_offset:	.word from_ram-_C_LABEL(_start)
102from_ram:
103	nop
104#endif
105	adr	r7, Lunmapped
106	bic     r7, r7, #0xff000000
107	orr     r7, r7, #PHYSADDR
108
109
110disable_mmu:
111	/* Disable MMU for a while */
112	mrc     p15, 0, r2, c1, c0, 0
113	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
114	    CPU_CONTROL_WBUF_ENABLE)
115	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
116	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
117	mcr     p15, 0, r2, c1, c0, 0
118
119	nop
120	nop
121	nop
122	mov	pc, r7
123Lunmapped:
124#ifdef STARTUP_PAGETABLE_ADDR
125	/* build page table from scratch */
126	ldr	r0, Lstartup_pagetable
127	adr	r4, mmu_init_table
128	b	3f
129
1302:
131	str	r3, [r0, r2]
132	add	r2, r2, #4
133	add	r3, r3, #(L1_S_SIZE)
134	adds	r1, r1, #-1
135	bhi	2b
1363:
137	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
138	cmp	r1, #0
139	adrne	r5, 2b
140	bicne	r5, r5, #0xff000000
141	orrne	r5, r5, #PHYSADDR
142	movne	pc, r5
143
144	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
145	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
146
147	/* Set the Domain Access register.  Very important! */
148	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
149	mcr	p15, 0, r0, c3, c0, 0
150	/* Enable MMU */
151	mrc	p15, 0, r0, c1, c0, 0
152	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
153	mcr	p15, 0, r0, c1, c0, 0
154	nop
155	nop
156	nop
157	CPWAIT(r0)
158
159#endif
160mmu_done:
161	nop
162	adr	r1, .Lstart
163	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
164	sub	r2, r2, r1		/* get zero init data */
165	mov	r3, #0
166.L1:
167	str	r3, [r1], #0x0004	/* get zero init data */
168	subs	r2, r2, #4
169	bgt	.L1
170	ldr	pc, .Lvirt_done
171
172virt_done:
173	mov	fp, #0		/* trace back starts here */
174	bl	_C_LABEL(initarm)	/* Off we go */
175
176	/* init arm will return the new stack pointer. */
177	mov	sp, r0
178
179	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
180
181	adr	r0, .Lmainreturned
182	b	_C_LABEL(panic)
183	/* NOTEACHED */
184#ifdef STARTUP_PAGETABLE_ADDR
185#define MMU_INIT(va,pa,n_sec,attr) \
186	.word	n_sec					    ; \
187	.word	4*((va)>>L1_S_SHIFT)			    ; \
188	.word	(pa)|(attr)				    ;
189
190Lvirtaddr:
191	.word	KERNVIRTADDR
192Lphysaddr:
193	.word	KERNPHYSADDR
194Lreal_start:
195	.word	_start
196Lend:
197	.word	_edata
198Lstartup_pagetable:
199	.word	STARTUP_PAGETABLE_ADDR
200mmu_init_table:
201	/* fill all table VA==PA */
202	/* map SDRAM VA==PA, WT cacheable */
203	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
204	/* map VA 0xc0000000..0xc3ffffff to PA */
205	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
206
207	.word 0	/* end of table */
208#endif
209.Lstart:
210	.word	_edata
211	.word	_end
212	.word	svcstk + INIT_ARM_STACK_SIZE
213
214#if defined(FLASHADDR) && defined(LOADERRAMADDR)
215.L_arm_memcpy:
216        .word   _C_LABEL(_arm_memcpy)
217#endif
218
219.Lvirt_done:
220	.word	virt_done
221.Lmainreturned:
222	.asciz	"main() returned"
223	.align	0
224
225	.bss
226svcstk:
227	.space	INIT_ARM_STACK_SIZE
228
229	.text
230	.align	0
231
232#ifndef OFW
233	/* OFW based systems will used OF_boot() */
234
235.Lcpufuncs:
236	.word	_C_LABEL(cpufuncs)
237
238ENTRY_NP(cpu_halt)
239	mrs     r2, cpsr
240	bic	r2, r2, #(PSR_MODE)
241	orr     r2, r2, #(PSR_SVC32_MODE)
242	orr	r2, r2, #(I32_bit | F32_bit)
243	msr     cpsr_all, r2
244
245	ldr	r4, .Lcpu_reset_address
246	ldr	r4, [r4]
247
248	ldr	r0, .Lcpufuncs
249	mov	lr, pc
250	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
251
252	/*
253	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
254	 * necessary.
255	 */
256
257	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
258	ldr	r1, [r1]
259	cmp	r1, #0
260	mov	r2, #0
261
262	/*
263 	 * MMU & IDC off, 32 bit program & data space
264	 * Hurl ourselves into the ROM
265	 */
266	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
267	mcr     15, 0, r0, c1, c0, 0
268	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
269	mov     pc, r4
270
271	/*
272	 * _cpu_reset_address contains the address to branch to, to complete
273	 * the cpu reset after turning the MMU off
274	 * This variable is provided by the hardware specific code
275	 */
276.Lcpu_reset_address:
277	.word	_C_LABEL(cpu_reset_address)
278
279	/*
280	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
281	 * v4 MMU disable instruction needs executing... it is an illegal instruction
282	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
283	 * instruction / data-abort / reset loop.
284	 */
285.Lcpu_reset_needs_v4_MMU_disable:
286	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
287
288#endif	/* OFW */
289
290#ifdef IPKDB
291/*
292 * Execute(inst, psr, args, sp)
293 *
294 * Execute INSTruction with PSR and ARGS[0] - ARGS[3] making
295 * available stack at SP for next undefined instruction trap.
296 *
297 * Move the instruction onto the stack and jump to it.
298 */
299ENTRY_NP(Execute)
300	mov	ip, sp
301	stmfd	sp!, {r2, r4-r7, fp, ip, lr, pc}
302	sub	fp, ip, #4
303	mov	ip, r3
304	ldr	r7, .Lreturn
305	stmfd	sp!, {r0, r7}
306	adr	r7, #.LExec
307	mov	r5, r1
308	mrs	r4, cpsr
309	ldmia	r2, {r0-r3}
310	mov	r6, sp
311	mov	sp, ip
312	msr	cpsr_all, r5
313	mov	pc, r6
314.LExec:
315	mrs	r5, cpsr
316/* XXX Cannot switch thus easily back from user mode */
317	msr	cpsr_all, r4
318	add	sp, r6, #8
319	ldmfd	sp!, {r6}
320	stmia	r6, {r0-r3}
321	mov	r0, r5
322	ldmdb	fp, {r4-r7, fp, sp, pc}
323.Lreturn:
324	mov	pc, r7
325#endif
326
327/*
328 * setjump + longjmp
329 */
330ENTRY(setjmp)
331	stmia	r0, {r4-r14}
332	mov	r0, #0x00000000
333	RET
334
335ENTRY(longjmp)
336	ldmia	r0, {r4-r14}
337	mov	r0, #0x00000001
338	RET
339
340	.data
341	.global _C_LABEL(esym)
342_C_LABEL(esym):	.word	_C_LABEL(end)
343
344ENTRY_NP(abort)
345	b	_C_LABEL(abort)
346
347ENTRY_NP(sigcode)
348	mov	r0, sp
349	swi	SYS_sigreturn
350
351	/* Well if that failed we better exit quick ! */
352
353	swi	SYS_exit
354	b	. - 8
355
356	.align	0
357	.global _C_LABEL(esigcode)
358		_C_LABEL(esigcode):
359
360	.data
361	.global szsigcode
362szsigcode:
363	.long esigcode-sigcode
364/* End of locore.S */
365