locore-v4.S revision 236524
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>
40236524Simp
41129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 236524 2012-06-03 18:34:32Z imp $");
42129198Scognet
43159849Simp/* What size should this really be ? It is only used by initarm() */
44129198Scognet#define INIT_ARM_STACK_SIZE	2048
45129198Scognet
46129198Scognet#define	CPWAIT_BRANCH							 \
47129198Scognet	sub	pc, pc, #4
48129198Scognet
49129198Scognet#define	CPWAIT(tmp)							 \
50129198Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
51129198Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
52129198Scognet	CPWAIT_BRANCH			/* branch to next insn */
53129198Scognet
54235277Simp/*
55235277Simp * This is for kvm_mkdb, and should be the address of the beginning
56235277Simp * of the kernel text segment (not necessarily the same as kernbase).
57235277Simp */
58129198Scognet	.text
59129198Scognet	.align	0
60129198Scognet.globl kernbase
61129198Scognet.set kernbase,KERNBASE
62150863Scognet.globl physaddr
63150863Scognet.set physaddr,PHYSADDR
64129198Scognet
65183878Sraj/*
66236524Simp * On entry for FreeBSD boot ABI:
67236524Simp *	r0 - metadata pointer or 0 (boothowto on AT91's boot2)
68218227Smarcel *	r1 - if (r0 == 0) then metadata pointer
69236524Simp * On entry for Linux boot ABI:
70236524Simp *	r0 - 0
71236524Simp *	r1 - machine type (passed as arg2 to initarm)
72236524Simp *	r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
73236524Simp *
74236524Simp * For both types of boot we gather up the args, put them in a struct arm_boot_params
75236524Simp * structure and pass that to initarm.
76183878Sraj */
77236524SimpENTRY_NP(btext)
78218227SmarcelASENTRY_NP(_start)
79236524Simp	mov	r9, r0		/* 0 or boot mode from boot2 */
80236524Simp	mov	r8, r1		/* Save Machine type */
81236524Simp	mov	ip, r2		/* Save meta data */
82236524Simp	mov	fp, r3		/* Future expantion */
83183878Sraj
84193846Smarcel	/* Make sure interrupts are disabled. */
85193846Smarcel	mrs	r7, cpsr
86193846Smarcel	orr	r7, r7, #(I32_bit|F32_bit)
87193846Smarcel	msr	cpsr_c, r7
88193846Smarcel
89166819Scognet#if defined (FLASHADDR) && defined(LOADERRAMADDR)
90166819Scognet	/* Check if we're running from flash. */
91166819Scognet	ldr	r7, =FLASHADDR
92175983Sraj	/*
93166819Scognet	 * If we're running with MMU disabled, test against the
94166819Scognet	 * physical address instead.
95166819Scognet	 */
96166819Scognet	mrc     p15, 0, r2, c1, c0, 0
97166819Scognet	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
98236524Simp	ldreq	r6, =PHYSADDR
99236524Simp	ldrne	r6, =LOADERRAMADDR
100236524Simp	cmp	r7, r6
101166819Scognet	bls 	flash_lower
102166819Scognet	cmp	r7, pc
103166819Scognet	bhi	from_ram
104166819Scognet	b	do_copy
105166819Scognet
106166819Scognetflash_lower:
107236524Simp	cmp	r6, pc
108166819Scognet	bls	from_ram
109166819Scognetdo_copy:
110236524Simp	ldr	r7, =KERNBASE
111175983Sraj	adr	r1, _start
112166819Scognet	ldr	r0, Lreal_start
113166819Scognet	ldr	r2, Lend
114166819Scognet	sub	r2, r2, r0
115236524Simp	sub	r0, r0, r7
116236524Simp	add	r0, r0, r6
117166819Scognet	mov	r4, r0
118166819Scognet	bl	memcpy
119166819Scognet	ldr	r0, Lram_offset
120166819Scognet	add	pc, r4, r0
121166819ScognetLram_offset:	.word from_ram-_C_LABEL(_start)
122166819Scognetfrom_ram:
123166819Scognet	nop
124135640Scognet#endif
125135640Scognet	adr	r7, Lunmapped
126190602Scognet	bic     r7, r7, #0xf0000000
127153616Scognet	orr     r7, r7, #PHYSADDR
128143681Sjmg
129175983Sraj
130166819Scognetdisable_mmu:
131135640Scognet	/* Disable MMU for a while */
132143681Sjmg	mrc     p15, 0, r2, c1, c0, 0
133153550Scognet	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
134153550Scognet	    CPU_CONTROL_WBUF_ENABLE)
135153550Scognet	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
136153550Scognet	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
137135640Scognet	mcr     p15, 0, r2, c1, c0, 0
138129198Scognet
139135640Scognet	nop
140135640Scognet	nop
141135640Scognet	nop
142135640Scognet	mov	pc, r7
143135640ScognetLunmapped:
144135640Scognet#ifdef STARTUP_PAGETABLE_ADDR
145129198Scognet	/* build page table from scratch */
146129198Scognet	ldr	r0, Lstartup_pagetable
147129198Scognet	adr	r4, mmu_init_table
148129198Scognet	b	3f
149129198Scognet
150129198Scognet2:
151129198Scognet	str	r3, [r0, r2]
152129198Scognet	add	r2, r2, #4
153129198Scognet	add	r3, r3, #(L1_S_SIZE)
154129198Scognet	adds	r1, r1, #-1
155129198Scognet	bhi	2b
156143681Sjmg3:
157172356Scognet	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
158129198Scognet	cmp	r1, #0
159140683Scognet	adrne	r5, 2b
160190602Scognet	bicne	r5, r5, #0xf0000000
161140683Scognet	orrne	r5, r5, #PHYSADDR
162140683Scognet	movne	pc, r5
163129198Scognet
164129198Scognet	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
165129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
166129198Scognet
167129198Scognet	/* Set the Domain Access register.  Very important! */
168143681Sjmg	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
169129198Scognet	mcr	p15, 0, r0, c3, c0, 0
170129198Scognet	/* Enable MMU */
171129198Scognet	mrc	p15, 0, r0, c1, c0, 0
172129198Scognet	orr	r0, r0, #CPU_CONTROL_MMU_ENABLE
173129198Scognet	mcr	p15, 0, r0, c1, c0, 0
174153550Scognet	nop
175153550Scognet	nop
176153550Scognet	nop
177129198Scognet	CPWAIT(r0)
178129198Scognet
179153550Scognet#endif
180129198Scognetmmu_done:
181153550Scognet	nop
182129198Scognet	adr	r1, .Lstart
183129198Scognet	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
184129198Scognet	sub	r2, r2, r1		/* get zero init data */
185129198Scognet	mov	r3, #0
186129198Scognet.L1:
187150863Scognet	str	r3, [r1], #0x0004	/* get zero init data */
188129198Scognet	subs	r2, r2, #4
189129198Scognet	bgt	.L1
190153550Scognet	ldr	pc, .Lvirt_done
191129198Scognet
192142145Scognetvirt_done:
193236524Simp	mov	r1, #20			/* loader info size is 20 bytes also second arg */
194236524Simp	subs	sp, sp, r1		/* allocate arm_boot_params struct on stack */
195236524Simp	mov	r0, sp			/* loader info pointer is first arg */
196236524Simp	str	r1, [r0]		/* Store length of loader info */
197236524Simp	str	r9, [r0, #4]		/* Store r0 from boot loader */
198236524Simp	str	r8, [r0, #8]		/* Store r1 from boot loader */
199236524Simp	str	ip, [r0, #12]		/* store r2 from boot loader */
200236524Simp	str	fp, [r0, #16]		/* store r3 from boot loader */
201175983Sraj	mov	fp, #0			/* trace back starts here */
202129198Scognet	bl	_C_LABEL(initarm)	/* Off we go */
203129198Scognet
204129198Scognet	/* init arm will return the new stack pointer. */
205129198Scognet	mov	sp, r0
206129198Scognet
207129198Scognet	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
208129198Scognet
209129198Scognet	adr	r0, .Lmainreturned
210130164Sphk	b	_C_LABEL(panic)
211175983Sraj	/* NOTREACHED */
212129198Scognet#ifdef STARTUP_PAGETABLE_ADDR
213129198Scognet#define MMU_INIT(va,pa,n_sec,attr) \
214129198Scognet	.word	n_sec					    ; \
215129198Scognet	.word	4*((va)>>L1_S_SHIFT)			    ; \
216129198Scognet	.word	(pa)|(attr)				    ;
217129198Scognet
218150863ScognetLvirtaddr:
219150863Scognet	.word	KERNVIRTADDR
220150863ScognetLphysaddr:
221150863Scognet	.word	KERNPHYSADDR
222166819ScognetLreal_start:
223166819Scognet	.word	_start
224166819ScognetLend:
225166819Scognet	.word	_edata
226129198ScognetLstartup_pagetable:
227129198Scognet	.word	STARTUP_PAGETABLE_ADDR
228143681Sjmgmmu_init_table:
229129198Scognet	/* fill all table VA==PA */
230129198Scognet	/* map SDRAM VA==PA, WT cacheable */
231135640Scognet	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
232135640Scognet	/* map VA 0xc0000000..0xc3ffffff to PA */
233135640Scognet	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
234129198Scognet
235129198Scognet	.word 0	/* end of table */
236129198Scognet#endif
237129198Scognet.Lstart:
238129198Scognet	.word	_edata
239129198Scognet	.word	_end
240129198Scognet	.word	svcstk + INIT_ARM_STACK_SIZE
241129198Scognet
242153550Scognet.Lvirt_done:
243153550Scognet	.word	virt_done
244129198Scognet.Lmainreturned:
245129198Scognet	.asciz	"main() returned"
246129198Scognet	.align	0
247129198Scognet
248129198Scognet	.bss
249129198Scognetsvcstk:
250129198Scognet	.space	INIT_ARM_STACK_SIZE
251129198Scognet
252129198Scognet	.text
253129198Scognet	.align	0
254129198Scognet
255143681Sjmg.Lcpufuncs:
256129198Scognet	.word	_C_LABEL(cpufuncs)
257129198Scognet
258135640ScognetENTRY_NP(cpu_halt)
259129198Scognet	mrs     r2, cpsr
260129198Scognet	bic	r2, r2, #(PSR_MODE)
261129198Scognet	orr     r2, r2, #(PSR_SVC32_MODE)
262129198Scognet	orr	r2, r2, #(I32_bit | F32_bit)
263129198Scognet	msr     cpsr_all, r2
264129198Scognet
265129198Scognet	ldr	r4, .Lcpu_reset_address
266129198Scognet	ldr	r4, [r4]
267129198Scognet
268129198Scognet	ldr	r0, .Lcpufuncs
269129198Scognet	mov	lr, pc
270129198Scognet	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
271183839Sraj	mov	lr, pc
272183839Sraj	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
273129198Scognet
274129198Scognet	/*
275129198Scognet	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
276129198Scognet	 * necessary.
277129198Scognet	 */
278129198Scognet
279129198Scognet	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
280129198Scognet	ldr	r1, [r1]
281129198Scognet	cmp	r1, #0
282129198Scognet	mov	r2, #0
283129198Scognet
284129198Scognet	/*
285175983Sraj	 * MMU & IDC off, 32 bit program & data space
286129198Scognet	 * Hurl ourselves into the ROM
287129198Scognet	 */
288129198Scognet	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
289129198Scognet	mcr     15, 0, r0, c1, c0, 0
290129198Scognet	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
291129198Scognet	mov     pc, r4
292129198Scognet
293129198Scognet	/*
294129198Scognet	 * _cpu_reset_address contains the address to branch to, to complete
295129198Scognet	 * the cpu reset after turning the MMU off
296129198Scognet	 * This variable is provided by the hardware specific code
297129198Scognet	 */
298129198Scognet.Lcpu_reset_address:
299129198Scognet	.word	_C_LABEL(cpu_reset_address)
300129198Scognet
301129198Scognet	/*
302129198Scognet	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
303129198Scognet	 * v4 MMU disable instruction needs executing... it is an illegal instruction
304129198Scognet	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
305129198Scognet	 * instruction / data-abort / reset loop.
306129198Scognet	 */
307129198Scognet.Lcpu_reset_needs_v4_MMU_disable:
308129198Scognet	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
309129198Scognet
310129198Scognet
311129198Scognet/*
312129198Scognet * setjump + longjmp
313129198Scognet */
314129198ScognetENTRY(setjmp)
315129198Scognet	stmia	r0, {r4-r14}
316129198Scognet	mov	r0, #0x00000000
317137463Scognet	RET
318129198Scognet
319129198ScognetENTRY(longjmp)
320129198Scognet	ldmia	r0, {r4-r14}
321129198Scognet	mov	r0, #0x00000001
322137463Scognet	RET
323129198Scognet
324129198Scognet	.data
325129198Scognet	.global _C_LABEL(esym)
326129198Scognet_C_LABEL(esym):	.word	_C_LABEL(end)
327129198Scognet
328129198ScognetENTRY_NP(abort)
329129198Scognet	b	_C_LABEL(abort)
330129198Scognet
331135640ScognetENTRY_NP(sigcode)
332135640Scognet	mov	r0, sp
333135640Scognet	swi	SYS_sigreturn
334135640Scognet
335135640Scognet	/* Well if that failed we better exit quick ! */
336135640Scognet
337135640Scognet	swi	SYS_exit
338135640Scognet	b	. - 8
339135640Scognet
340135640Scognet	.align	0
341135640Scognet	.global _C_LABEL(esigcode)
342135640Scognet		_C_LABEL(esigcode):
343143681Sjmg
344135640Scognet	.data
345135640Scognet	.global szsigcode
346135640Scognetszsigcode:
347135640Scognet	.long esigcode-sigcode
348129198Scognet/* End of locore.S */
349