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