locore-v4.S revision 175983
1129198Scognet/*	$NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $	*/
2129198Scognet
3139735Simp/*-
4129198Scognet * Copyright (C) 1994-1997 Mark Brinicombe
5129198Scognet * Copyright (C) 1994 Brini
6129198Scognet * All rights reserved.
7129198Scognet *
8129198Scognet * Redistribution and use in source and binary forms, with or without
9129198Scognet * modification, are permitted provided that the following conditions
10129198Scognet * are met:
11129198Scognet * 1. Redistributions of source code must retain the above copyright
12129198Scognet *    notice, this list of conditions and the following disclaimer.
13129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
14129198Scognet *    notice, this list of conditions and the following disclaimer in the
15129198Scognet *    documentation and/or other materials provided with the distribution.
16129198Scognet * 3. All advertising materials mentioning features or use of this software
17129198Scognet *    must display the following acknowledgement:
18129198Scognet *	This product includes software developed by Brini.
19129198Scognet * 4. The name of Brini may not be used to endorse or promote products
20129198Scognet *    derived from this software without specific prior written permission.
21129198Scognet *
22129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
23129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25129198Scognet * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26129198Scognet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27129198Scognet * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28129198Scognet * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29129198Scognet * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30129198Scognet * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31129198Scognet * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32129198Scognet *
33129198Scognet */
34129198Scognet
35129198Scognet#include "assym.s"
36135640Scognet#include <sys/syscall.h>
37129198Scognet#include <machine/asm.h>
38129198Scognet#include <machine/armreg.h>
39129198Scognet#include <machine/pte.h>
40129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 175983 2008-02-05 10:23:42Z raj $");
41129198Scognet
42159849Simp/* What size should this really be ? It is only used by initarm() */
43129198Scognet#define INIT_ARM_STACK_SIZE	2048
44129198Scognet
45129198Scognet/*
46129198Scognet * This is for kvm_mkdb, and should be the address of the beginning
47129198Scognet * of the kernel text segment (not necessarily the same as kernbase).
48129198Scognet */
49129198Scognet
50129198Scognet
51129198Scognet#define	CPWAIT_BRANCH							 \
52129198Scognet	sub	pc, pc, #4
53129198Scognet
54129198Scognet#define	CPWAIT(tmp)							 \
55129198Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
56129198Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
57129198Scognet	CPWAIT_BRANCH			/* branch to next insn */
58129198Scognet
59129198Scognet	.text
60129198Scognet	.align	0
61129198Scognet.globl kernbase
62129198Scognet.set kernbase,KERNBASE
63150863Scognet.globl physaddr
64150863Scognet.set physaddr,PHYSADDR
65129198Scognet
66129198ScognetENTRY_NP(btext)
67129198Scognet
68129198ScognetASENTRY_NP(_start)
69166819Scognet#if defined (FLASHADDR) && defined(LOADERRAMADDR)
70166819Scognet	/* Check if we're running from flash. */
71166819Scognet	ldr	r7, =FLASHADDR
72175983Sraj	/*
73166819Scognet	 * If we're running with MMU disabled, test against the
74166819Scognet	 * physical address instead.
75166819Scognet	 */
76166819Scognet	mrc     p15, 0, r2, c1, c0, 0
77166819Scognet	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
78166819Scognet	ldreq	r8, =PHYSADDR
79166819Scognet	ldrne	r8, =LOADERRAMADDR
80166819Scognet	cmp	r7, r8
81166819Scognet	bls 	flash_lower
82166819Scognet	cmp	r7, pc
83166819Scognet	bhi	from_ram
84166819Scognet	b	do_copy
85166819Scognet
86166819Scognetflash_lower:
87166819Scognet	cmp	r8, pc
88166819Scognet	bls	from_ram
89166819Scognetdo_copy:
90166819Scognet	ldr	r9, =KERNBASE
91175983Sraj	adr	r1, _start
92166819Scognet	ldr	r0, Lreal_start
93166819Scognet	ldr	r2, Lend
94166819Scognet	sub	r2, r2, r0
95166819Scognet	sub	r0, r0, r9
96166819Scognet	add	r0, r0, r8
97166819Scognet	mov	r4, r0
98166819Scognet	bl	memcpy
99166819Scognet	ldr	r0, Lram_offset
100166819Scognet	add	pc, r4, r0
101166819ScognetLram_offset:	.word from_ram-_C_LABEL(_start)
102166819Scognetfrom_ram:
103166819Scognet	nop
104135640Scognet#endif
105135640Scognet	adr	r7, Lunmapped
106153616Scognet	bic     r7, r7, #0xff000000
107153616Scognet	orr     r7, r7, #PHYSADDR
108143681Sjmg
109175983Sraj
110166819Scognetdisable_mmu:
111135640Scognet	/* Disable MMU for a while */
112143681Sjmg	mrc     p15, 0, r2, c1, c0, 0
113153550Scognet	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
114153550Scognet	    CPU_CONTROL_WBUF_ENABLE)
115153550Scognet	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
116153550Scognet	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
117135640Scognet	mcr     p15, 0, r2, c1, c0, 0
118129198Scognet
119135640Scognet	nop
120135640Scognet	nop
121135640Scognet	nop
122135640Scognet	mov	pc, r7
123135640ScognetLunmapped:
124135640Scognet#ifdef STARTUP_PAGETABLE_ADDR
125129198Scognet	/* build page table from scratch */
126129198Scognet	ldr	r0, Lstartup_pagetable
127129198Scognet	adr	r4, mmu_init_table
128129198Scognet	b	3f
129129198Scognet
130129198Scognet2:
131129198Scognet	str	r3, [r0, r2]
132129198Scognet	add	r2, r2, #4
133129198Scognet	add	r3, r3, #(L1_S_SIZE)
134129198Scognet	adds	r1, r1, #-1
135129198Scognet	bhi	2b
136143681Sjmg3:
137172356Scognet	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
138129198Scognet	cmp	r1, #0
139140683Scognet	adrne	r5, 2b
140140683Scognet	bicne	r5, r5, #0xff000000
141140683Scognet	orrne	r5, r5, #PHYSADDR
142140683Scognet	movne	pc, r5
143129198Scognet
144129198Scognet	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
145129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
146129198Scognet
147129198Scognet	/* Set the Domain Access register.  Very important! */
148143681Sjmg	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
149129198Scognet	mcr	p15, 0, r0, c3, c0, 0
150129198Scognet	/* Enable MMU */
151129198Scognet	mrc	p15, 0, r0, c1, c0, 0
152129198Scognet	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
153129198Scognet	mcr	p15, 0, r0, c1, c0, 0
154153550Scognet	nop
155153550Scognet	nop
156153550Scognet	nop
157129198Scognet	CPWAIT(r0)
158129198Scognet
159153550Scognet#endif
160129198Scognetmmu_done:
161153550Scognet	nop
162129198Scognet	adr	r1, .Lstart
163129198Scognet	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
164129198Scognet	sub	r2, r2, r1		/* get zero init data */
165129198Scognet	mov	r3, #0
166129198Scognet.L1:
167150863Scognet	str	r3, [r1], #0x0004	/* get zero init data */
168129198Scognet	subs	r2, r2, #4
169129198Scognet	bgt	.L1
170153550Scognet	ldr	pc, .Lvirt_done
171129198Scognet
172142145Scognetvirt_done:
173175983Sraj	mov	fp, #0			/* trace back starts here */
174129198Scognet	bl	_C_LABEL(initarm)	/* Off we go */
175129198Scognet
176129198Scognet	/* init arm will return the new stack pointer. */
177129198Scognet	mov	sp, r0
178129198Scognet
179129198Scognet	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
180129198Scognet
181129198Scognet	adr	r0, .Lmainreturned
182130164Sphk	b	_C_LABEL(panic)
183175983Sraj	/* NOTREACHED */
184129198Scognet#ifdef STARTUP_PAGETABLE_ADDR
185129198Scognet#define MMU_INIT(va,pa,n_sec,attr) \
186129198Scognet	.word	n_sec					    ; \
187129198Scognet	.word	4*((va)>>L1_S_SHIFT)			    ; \
188129198Scognet	.word	(pa)|(attr)				    ;
189129198Scognet
190150863ScognetLvirtaddr:
191150863Scognet	.word	KERNVIRTADDR
192150863ScognetLphysaddr:
193150863Scognet	.word	KERNPHYSADDR
194166819ScognetLreal_start:
195166819Scognet	.word	_start
196166819ScognetLend:
197166819Scognet	.word	_edata
198129198ScognetLstartup_pagetable:
199129198Scognet	.word	STARTUP_PAGETABLE_ADDR
200143681Sjmgmmu_init_table:
201129198Scognet	/* fill all table VA==PA */
202129198Scognet	/* map SDRAM VA==PA, WT cacheable */
203135640Scognet	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
204135640Scognet	/* map VA 0xc0000000..0xc3ffffff to PA */
205135640Scognet	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
206129198Scognet
207129198Scognet	.word 0	/* end of table */
208129198Scognet#endif
209129198Scognet.Lstart:
210129198Scognet	.word	_edata
211129198Scognet	.word	_end
212129198Scognet	.word	svcstk + INIT_ARM_STACK_SIZE
213129198Scognet
214166819Scognet#if defined(FLASHADDR) && defined(LOADERRAMADDR)
215166819Scognet.L_arm_memcpy:
216166819Scognet        .word   _C_LABEL(_arm_memcpy)
217166819Scognet#endif
218166819Scognet
219153550Scognet.Lvirt_done:
220153550Scognet	.word	virt_done
221129198Scognet.Lmainreturned:
222129198Scognet	.asciz	"main() returned"
223129198Scognet	.align	0
224129198Scognet
225129198Scognet	.bss
226129198Scognetsvcstk:
227129198Scognet	.space	INIT_ARM_STACK_SIZE
228129198Scognet
229129198Scognet	.text
230129198Scognet	.align	0
231129198Scognet
232143681Sjmg.Lcpufuncs:
233129198Scognet	.word	_C_LABEL(cpufuncs)
234129198Scognet
235135640ScognetENTRY_NP(cpu_halt)
236129198Scognet	mrs     r2, cpsr
237129198Scognet	bic	r2, r2, #(PSR_MODE)
238129198Scognet	orr     r2, r2, #(PSR_SVC32_MODE)
239129198Scognet	orr	r2, r2, #(I32_bit | F32_bit)
240129198Scognet	msr     cpsr_all, r2
241129198Scognet
242129198Scognet	ldr	r4, .Lcpu_reset_address
243129198Scognet	ldr	r4, [r4]
244129198Scognet
245129198Scognet	ldr	r0, .Lcpufuncs
246129198Scognet	mov	lr, pc
247129198Scognet	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
248129198Scognet
249129198Scognet	/*
250129198Scognet	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
251129198Scognet	 * necessary.
252129198Scognet	 */
253129198Scognet
254129198Scognet	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
255129198Scognet	ldr	r1, [r1]
256129198Scognet	cmp	r1, #0
257129198Scognet	mov	r2, #0
258129198Scognet
259129198Scognet	/*
260175983Sraj	 * MMU & IDC off, 32 bit program & data space
261129198Scognet	 * Hurl ourselves into the ROM
262129198Scognet	 */
263129198Scognet	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
264129198Scognet	mcr     15, 0, r0, c1, c0, 0
265129198Scognet	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
266129198Scognet	mov     pc, r4
267129198Scognet
268129198Scognet	/*
269129198Scognet	 * _cpu_reset_address contains the address to branch to, to complete
270129198Scognet	 * the cpu reset after turning the MMU off
271129198Scognet	 * This variable is provided by the hardware specific code
272129198Scognet	 */
273129198Scognet.Lcpu_reset_address:
274129198Scognet	.word	_C_LABEL(cpu_reset_address)
275129198Scognet
276129198Scognet	/*
277129198Scognet	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
278129198Scognet	 * v4 MMU disable instruction needs executing... it is an illegal instruction
279129198Scognet	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
280129198Scognet	 * instruction / data-abort / reset loop.
281129198Scognet	 */
282129198Scognet.Lcpu_reset_needs_v4_MMU_disable:
283129198Scognet	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
284129198Scognet
285129198Scognet
286129198Scognet#ifdef IPKDB
287129198Scognet/*
288129198Scognet * Execute(inst, psr, args, sp)
289129198Scognet *
290129198Scognet * Execute INSTruction with PSR and ARGS[0] - ARGS[3] making
291129198Scognet * available stack at SP for next undefined instruction trap.
292129198Scognet *
293129198Scognet * Move the instruction onto the stack and jump to it.
294129198Scognet */
295129198ScognetENTRY_NP(Execute)
296129198Scognet	mov	ip, sp
297129198Scognet	stmfd	sp!, {r2, r4-r7, fp, ip, lr, pc}
298129198Scognet	sub	fp, ip, #4
299129198Scognet	mov	ip, r3
300129198Scognet	ldr	r7, .Lreturn
301129198Scognet	stmfd	sp!, {r0, r7}
302129198Scognet	adr	r7, #.LExec
303129198Scognet	mov	r5, r1
304129198Scognet	mrs	r4, cpsr
305129198Scognet	ldmia	r2, {r0-r3}
306129198Scognet	mov	r6, sp
307129198Scognet	mov	sp, ip
308129198Scognet	msr	cpsr_all, r5
309129198Scognet	mov	pc, r6
310129198Scognet.LExec:
311129198Scognet	mrs	r5, cpsr
312129198Scognet/* XXX Cannot switch thus easily back from user mode */
313129198Scognet	msr	cpsr_all, r4
314129198Scognet	add	sp, r6, #8
315129198Scognet	ldmfd	sp!, {r6}
316129198Scognet	stmia	r6, {r0-r3}
317129198Scognet	mov	r0, r5
318129198Scognet	ldmdb	fp, {r4-r7, fp, sp, pc}
319129198Scognet.Lreturn:
320129198Scognet	mov	pc, r7
321129198Scognet#endif
322129198Scognet
323129198Scognet/*
324129198Scognet * setjump + longjmp
325129198Scognet */
326129198ScognetENTRY(setjmp)
327129198Scognet	stmia	r0, {r4-r14}
328129198Scognet	mov	r0, #0x00000000
329137463Scognet	RET
330129198Scognet
331129198ScognetENTRY(longjmp)
332129198Scognet	ldmia	r0, {r4-r14}
333129198Scognet	mov	r0, #0x00000001
334137463Scognet	RET
335129198Scognet
336129198Scognet	.data
337129198Scognet	.global _C_LABEL(esym)
338129198Scognet_C_LABEL(esym):	.word	_C_LABEL(end)
339129198Scognet
340129198ScognetENTRY_NP(abort)
341129198Scognet	b	_C_LABEL(abort)
342129198Scognet
343135640ScognetENTRY_NP(sigcode)
344135640Scognet	mov	r0, sp
345135640Scognet	swi	SYS_sigreturn
346135640Scognet
347135640Scognet	/* Well if that failed we better exit quick ! */
348135640Scognet
349135640Scognet	swi	SYS_exit
350135640Scognet	b	. - 8
351135640Scognet
352135640Scognet	.align	0
353135640Scognet	.global _C_LABEL(esigcode)
354135640Scognet		_C_LABEL(esigcode):
355143681Sjmg
356135640Scognet	.data
357135640Scognet	.global szsigcode
358135640Scognetszsigcode:
359135640Scognet	.long esigcode-sigcode
360129198Scognet/* End of locore.S */
361