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