locore-v4.S revision 261393
1129198Scognet/*	$NetBSD: locore.S,v 1.14 2003/04/20 16:21:40 thorpej Exp $	*/
2129198Scognet
3139735Simp/*-
4239268Sgonzo * Copyright 2011 Semihalf
5129198Scognet * Copyright (C) 1994-1997 Mark Brinicombe
6129198Scognet * Copyright (C) 1994 Brini
7129198Scognet * All rights reserved.
8129198Scognet *
9129198Scognet * Redistribution and use in source and binary forms, with or without
10129198Scognet * modification, are permitted provided that the following conditions
11129198Scognet * are met:
12129198Scognet * 1. Redistributions of source code must retain the above copyright
13129198Scognet *    notice, this list of conditions and the following disclaimer.
14129198Scognet * 2. Redistributions in binary form must reproduce the above copyright
15129198Scognet *    notice, this list of conditions and the following disclaimer in the
16129198Scognet *    documentation and/or other materials provided with the distribution.
17129198Scognet * 3. All advertising materials mentioning features or use of this software
18129198Scognet *    must display the following acknowledgement:
19129198Scognet *	This product includes software developed by Brini.
20129198Scognet * 4. The name of Brini may not be used to endorse or promote products
21129198Scognet *    derived from this software without specific prior written permission.
22129198Scognet *
23129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR
24129198Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25129198Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26129198Scognet * IN NO EVENT SHALL BRINI BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27129198Scognet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28129198Scognet * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29129198Scognet * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30129198Scognet * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31129198Scognet * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32129198Scognet * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33129198Scognet *
34129198Scognet */
35129198Scognet
36129198Scognet#include "assym.s"
37135640Scognet#include <sys/syscall.h>
38129198Scognet#include <machine/asm.h>
39129198Scognet#include <machine/armreg.h>
40129198Scognet#include <machine/pte.h>
41236524Simp
42129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 261393 2014-02-02 00:48:15Z ian $");
43129198Scognet
44159849Simp/* What size should this really be ? It is only used by initarm() */
45239268Sgonzo#define INIT_ARM_STACK_SIZE	(2048 * 4)
46129198Scognet
47129198Scognet#define	CPWAIT_BRANCH							 \
48129198Scognet	sub	pc, pc, #4
49129198Scognet
50129198Scognet#define	CPWAIT(tmp)							 \
51129198Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
52129198Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
53129198Scognet	CPWAIT_BRANCH			/* branch to next insn */
54129198Scognet
55235277Simp/*
56235277Simp * This is for kvm_mkdb, and should be the address of the beginning
57235277Simp * of the kernel text segment (not necessarily the same as kernbase).
58235277Simp */
59129198Scognet	.text
60129198Scognet	.align	0
61129198Scognet.globl kernbase
62129198Scognet.set kernbase,KERNBASE
63150863Scognet.globl physaddr
64150863Scognet.set physaddr,PHYSADDR
65129198Scognet
66183878Sraj/*
67236524Simp * On entry for FreeBSD boot ABI:
68236524Simp *	r0 - metadata pointer or 0 (boothowto on AT91's boot2)
69218227Smarcel *	r1 - if (r0 == 0) then metadata pointer
70236524Simp * On entry for Linux boot ABI:
71236524Simp *	r0 - 0
72236524Simp *	r1 - machine type (passed as arg2 to initarm)
73236524Simp *	r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
74236524Simp *
75236524Simp * For both types of boot we gather up the args, put them in a struct arm_boot_params
76236524Simp * structure and pass that to initarm.
77183878Sraj */
78236524SimpENTRY_NP(btext)
79218227SmarcelASENTRY_NP(_start)
80250253Sian	STOP_UNWINDING		/* Can't unwind into the bootloader! */
81250253Sian
82236524Simp	mov	r9, r0		/* 0 or boot mode from boot2 */
83236524Simp	mov	r8, r1		/* Save Machine type */
84236524Simp	mov	ip, r2		/* Save meta data */
85236524Simp	mov	fp, r3		/* Future expantion */
86183878Sraj
87193846Smarcel	/* Make sure interrupts are disabled. */
88193846Smarcel	mrs	r7, cpsr
89193846Smarcel	orr	r7, r7, #(I32_bit|F32_bit)
90193846Smarcel	msr	cpsr_c, r7
91193846Smarcel
92166819Scognet#if defined (FLASHADDR) && defined(LOADERRAMADDR)
93166819Scognet	/* Check if we're running from flash. */
94166819Scognet	ldr	r7, =FLASHADDR
95175983Sraj	/*
96166819Scognet	 * If we're running with MMU disabled, test against the
97166819Scognet	 * physical address instead.
98166819Scognet	 */
99166819Scognet	mrc     p15, 0, r2, c1, c0, 0
100166819Scognet	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
101236524Simp	ldreq	r6, =PHYSADDR
102236524Simp	ldrne	r6, =LOADERRAMADDR
103236524Simp	cmp	r7, r6
104166819Scognet	bls 	flash_lower
105166819Scognet	cmp	r7, pc
106166819Scognet	bhi	from_ram
107166819Scognet	b	do_copy
108166819Scognet
109166819Scognetflash_lower:
110236524Simp	cmp	r6, pc
111166819Scognet	bls	from_ram
112166819Scognetdo_copy:
113236524Simp	ldr	r7, =KERNBASE
114175983Sraj	adr	r1, _start
115166819Scognet	ldr	r0, Lreal_start
116166819Scognet	ldr	r2, Lend
117166819Scognet	sub	r2, r2, r0
118236524Simp	sub	r0, r0, r7
119236524Simp	add	r0, r0, r6
120166819Scognet	mov	r4, r0
121166819Scognet	bl	memcpy
122166819Scognet	ldr	r0, Lram_offset
123166819Scognet	add	pc, r4, r0
124166819ScognetLram_offset:	.word from_ram-_C_LABEL(_start)
125166819Scognetfrom_ram:
126166819Scognet	nop
127135640Scognet#endif
128135640Scognet	adr	r7, Lunmapped
129190602Scognet	bic     r7, r7, #0xf0000000
130153616Scognet	orr     r7, r7, #PHYSADDR
131143681Sjmg
132175983Sraj
133166819Scognetdisable_mmu:
134135640Scognet	/* Disable MMU for a while */
135143681Sjmg	mrc     p15, 0, r2, c1, c0, 0
136153550Scognet	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
137153550Scognet	    CPU_CONTROL_WBUF_ENABLE)
138153550Scognet	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
139153550Scognet	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
140135640Scognet	mcr     p15, 0, r2, c1, c0, 0
141129198Scognet
142135640Scognet	nop
143135640Scognet	nop
144135640Scognet	nop
145135640Scognet	mov	pc, r7
146135640ScognetLunmapped:
147261227Sandrew	/*
148261227Sandrew	 * Build page table from scratch.
149261227Sandrew	 */
150261227Sandrew
151261227Sandrew	/* Load the page tables physical address */
152261227Sandrew	ldr	r1, Lstartup_pagetable
153261227Sandrew	ldr	r2, =(KERNVIRTADDR - KERNPHYSADDR)
154261227Sandrew	sub	r0, r1, r2
155261227Sandrew
156129198Scognet	adr	r4, mmu_init_table
157129198Scognet	b	3f
158129198Scognet
159129198Scognet2:
160129198Scognet	str	r3, [r0, r2]
161129198Scognet	add	r2, r2, #4
162129198Scognet	add	r3, r3, #(L1_S_SIZE)
163129198Scognet	adds	r1, r1, #-1
164129198Scognet	bhi	2b
165143681Sjmg3:
166172356Scognet	ldmia	r4!, {r1,r2,r3}   /* # of sections, VA, PA|attr */
167129198Scognet	cmp	r1, #0
168140683Scognet	adrne	r5, 2b
169190602Scognet	bicne	r5, r5, #0xf0000000
170140683Scognet	orrne	r5, r5, #PHYSADDR
171140683Scognet	movne	pc, r5
172129198Scognet
173239268Sgonzo#if defined(SMP)
174239268Sgonzo	orr 	r0, r0, #2		/* Set TTB shared memory flag */
175239268Sgonzo#endif
176129198Scognet	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
177129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
178129198Scognet
179259640Sganbold#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
180239268Sgonzo	mov	r0, #0
181239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
182239268Sgonzo#endif
183239268Sgonzo
184129198Scognet	/* Set the Domain Access register.  Very important! */
185143681Sjmg	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
186129198Scognet	mcr	p15, 0, r0, c3, c0, 0
187248961Sian	/*
188248961Sian	 * Enable MMU.
189248961Sian	 * On armv6 enable extended page tables, and set alignment checking
190248961Sian	 * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
191248961Sian	 * instructions emitted by clang.
192248961Sian	 */
193129198Scognet	mrc	p15, 0, r0, c1, c0, 0
194248961Sian#ifdef _ARM_ARCH_6
195248961Sian	orr	r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
196256628Sian	orr	r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
197250928Sgber	orr	r0, r0, #(CPU_CONTROL_AF_ENABLE)
198239268Sgonzo#endif
199243602Sgonzo	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE)
200129198Scognet	mcr	p15, 0, r0, c1, c0, 0
201153550Scognet	nop
202153550Scognet	nop
203153550Scognet	nop
204129198Scognet	CPWAIT(r0)
205129198Scognet
206129198Scognetmmu_done:
207153550Scognet	nop
208129198Scognet	adr	r1, .Lstart
209129198Scognet	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
210129198Scognet	sub	r2, r2, r1		/* get zero init data */
211129198Scognet	mov	r3, #0
212129198Scognet.L1:
213150863Scognet	str	r3, [r1], #0x0004	/* get zero init data */
214129198Scognet	subs	r2, r2, #4
215129198Scognet	bgt	.L1
216153550Scognet	ldr	pc, .Lvirt_done
217129198Scognet
218142145Scognetvirt_done:
219236524Simp	mov	r1, #20			/* loader info size is 20 bytes also second arg */
220236524Simp	subs	sp, sp, r1		/* allocate arm_boot_params struct on stack */
221247608Sandrew	bic	sp, sp, #7		/* align stack to 8 bytes */
222236524Simp	mov	r0, sp			/* loader info pointer is first arg */
223236524Simp	str	r1, [r0]		/* Store length of loader info */
224236524Simp	str	r9, [r0, #4]		/* Store r0 from boot loader */
225236524Simp	str	r8, [r0, #8]		/* Store r1 from boot loader */
226236524Simp	str	ip, [r0, #12]		/* store r2 from boot loader */
227236524Simp	str	fp, [r0, #16]		/* store r3 from boot loader */
228175983Sraj	mov	fp, #0			/* trace back starts here */
229129198Scognet	bl	_C_LABEL(initarm)	/* Off we go */
230129198Scognet
231129198Scognet	/* init arm will return the new stack pointer. */
232129198Scognet	mov	sp, r0
233129198Scognet
234129198Scognet	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
235129198Scognet
236129198Scognet	adr	r0, .Lmainreturned
237130164Sphk	b	_C_LABEL(panic)
238175983Sraj	/* NOTREACHED */
239129198Scognet#define MMU_INIT(va,pa,n_sec,attr) \
240129198Scognet	.word	n_sec					    ; \
241129198Scognet	.word	4*((va)>>L1_S_SHIFT)			    ; \
242129198Scognet	.word	(pa)|(attr)				    ;
243129198Scognet
244150863ScognetLvirtaddr:
245150863Scognet	.word	KERNVIRTADDR
246150863ScognetLphysaddr:
247150863Scognet	.word	KERNPHYSADDR
248166819ScognetLreal_start:
249166819Scognet	.word	_start
250166819ScognetLend:
251166819Scognet	.word	_edata
252129198ScognetLstartup_pagetable:
253261227Sandrew	.word	pagetable
254239268Sgonzo#ifdef SMP
255239268SgonzoLstartup_pagetable_secondary:
256239268Sgonzo	.word	temp_pagetable
257239268Sgonzo#endif
258248361SandrewEND(btext)
259248361SandrewEND(_start)
260248361Sandrew
261143681Sjmgmmu_init_table:
262129198Scognet	/* fill all table VA==PA */
263129198Scognet	/* map SDRAM VA==PA, WT cacheable */
264239268Sgonzo#if !defined(SMP)
265261039Simp	MMU_INIT(PHYSADDR, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
266135640Scognet	/* map VA 0xc0000000..0xc3ffffff to PA */
267135640Scognet	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
268261336Simp#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
269261039Simp	/* Map in 0x04000000 worth of the SoC's devices for bootstrap debugging */
270261336Simp	MMU_INIT(SOCDEV_VA, SOCDEV_PA, 64, L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
271261039Simp#endif
272239268Sgonzo#else
273239268Sgonzo	MMU_INIT(PHYSADDR, PHYSADDR , 64, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
274239268Sgonzo	/* map VA 0xc0000000..0xc3ffffff to PA */
275239268Sgonzo	MMU_INIT(KERNBASE, PHYSADDR, 64, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
276239268Sgonzo	MMU_INIT(0x48000000, 0x48000000, 1, L1_TYPE_S|L1_SHARED|L1_S_C|L1_S_AP(AP_KRW))
277250293Sgber#endif /* SMP */
278129198Scognet	.word 0	/* end of table */
279129198Scognet.Lstart:
280129198Scognet	.word	_edata
281261227Sandrew	.word	_ebss
282129198Scognet	.word	svcstk + INIT_ARM_STACK_SIZE
283129198Scognet
284153550Scognet.Lvirt_done:
285153550Scognet	.word	virt_done
286239268Sgonzo#if defined(SMP)
287239268Sgonzo.Lmpvirt_done:
288239268Sgonzo	.word	mpvirt_done
289239268Sgonzo#endif
290239268Sgonzo
291129198Scognet.Lmainreturned:
292129198Scognet	.asciz	"main() returned"
293129198Scognet	.align	0
294129198Scognet
295129198Scognet	.bss
296129198Scognetsvcstk:
297129198Scognet	.space	INIT_ARM_STACK_SIZE
298129198Scognet
299261227Sandrew/*
300261227Sandrew * Memory for the initial pagetable. We are unable to place this in
301261227Sandrew * the bss as this will be cleared after the table is loaded.
302261227Sandrew */
303261227Sandrew	.section ".init_pagetable"
304261227Sandrew	.align	14 /* 16KiB aligned */
305261227Sandrewpagetable:
306261227Sandrew	.space	L1_TABLE_SIZE
307261227Sandrew
308129198Scognet	.text
309129198Scognet	.align	0
310129198Scognet
311143681Sjmg.Lcpufuncs:
312129198Scognet	.word	_C_LABEL(cpufuncs)
313129198Scognet
314239268Sgonzo#if defined(SMP)
315239268SgonzoLsramaddr:
316239268Sgonzo	.word	0xffff0080
317239268Sgonzo
318239268Sgonzo#if 0
319239268Sgonzo#define	AP_DEBUG(tmp)			\
320239268Sgonzo	mrc	p15, 0, r1, c0, c0, 5;	\
321239268Sgonzo	ldr	r0, Lsramaddr;		\
322239268Sgonzo	add	r0, r1, lsl #2;		\
323239268Sgonzo	mov	r1, tmp;		\
324239268Sgonzo	str	r1, [r0], #0x0000;
325239268Sgonzo#else
326239268Sgonzo#define AP_DEBUG(tmp)
327239268Sgonzo#endif
328239268Sgonzo
329239268Sgonzo
330239268SgonzoASENTRY_NP(mptramp)
331239268Sgonzo	mov	r0, #0
332239268Sgonzo	mcr	p15, 0, r0, c7, c7, 0
333239268Sgonzo
334239268Sgonzo	AP_DEBUG(#1)
335239268Sgonzo
336261393Sian	mrs	r3, cpsr
337239268Sgonzo	bic	r3, r3, #(PSR_MODE)
338239268Sgonzo	orr	r3, r3, #(PSR_SVC32_MODE)
339261393Sian        msr	cpsr_fsxc, r3
340239268Sgonzo
341239268Sgonzo	mrc	p15, 0, r0, c0, c0, 5
342239268Sgonzo	and	r0, #0x0f		/* Get CPU ID */
343239268Sgonzo
344239268Sgonzo	/* Read boot address for CPU */
345239268Sgonzo	mov	r1, #0x100
346239268Sgonzo	mul	r2, r0, r1
347239268Sgonzo	ldr	r1, Lpmureg
348239268Sgonzo	add	r0, r2, r1
349239268Sgonzo	ldr	r1, [r0], #0x00
350239268Sgonzo
351239268Sgonzo	mov pc, r1
352239268Sgonzo
353239268SgonzoLpmureg:
354239268Sgonzo        .word   0xd0022124
355248361SandrewEND(mptramp)
356239268Sgonzo
357239268SgonzoASENTRY_NP(mpentry)
358239268Sgonzo
359239268Sgonzo	AP_DEBUG(#2)
360239268Sgonzo
361239268Sgonzo	/* Make sure interrupts are disabled. */
362239268Sgonzo	mrs	r7, cpsr
363239268Sgonzo	orr	r7, r7, #(I32_bit|F32_bit)
364239268Sgonzo	msr	cpsr_c, r7
365239268Sgonzo
366239268Sgonzo
367239268Sgonzo	adr     r7, Ltag
368239268Sgonzo	bic     r7, r7, #0xf0000000
369239268Sgonzo	orr     r7, r7, #PHYSADDR
370239268Sgonzo
371239268Sgonzo	/* Disable MMU for a while */
372239268Sgonzo	mrc	p15, 0, r2, c1, c0, 0
373239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
374239268Sgonzo	    CPU_CONTROL_WBUF_ENABLE)
375239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
376239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
377239268Sgonzo	mcr	p15, 0, r2, c1, c0, 0
378239268Sgonzo
379239268Sgonzo	nop
380239268Sgonzo	nop
381239268Sgonzo	nop
382239268Sgonzo
383239268Sgonzo	AP_DEBUG(#3)
384239268Sgonzo
385239268SgonzoLtag:
386239268Sgonzo	ldr	r0, Lstartup_pagetable_secondary
387239268Sgonzo	bic	r0, r0, #0xf0000000
388239268Sgonzo	orr	r0, r0, #PHYSADDR
389239268Sgonzo	ldr	r0, [r0]
390239268Sgonzo#if defined(SMP)
391239268Sgonzo	orr 	r0, r0, #0		/* Set TTB shared memory flag */
392239268Sgonzo#endif
393239268Sgonzo	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
394239268Sgonzo	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
395239268Sgonzo
396259640Sganbold#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
397239268Sgonzo	mov	r0, #0
398239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
399239268Sgonzo#endif
400239268Sgonzo
401239268Sgonzo	AP_DEBUG(#4)
402239268Sgonzo
403239268Sgonzo	/* Set the Domain Access register.  Very important! */
404239268Sgonzo	mov	r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
405239268Sgonzo	mcr	p15, 0, r0, c3, c0, 0
406239268Sgonzo	/* Enable MMU */
407239268Sgonzo	mrc	p15, 0, r0, c1, c0, 0
408259640Sganbold#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_MV_PJ4B) || defined(CPU_CORTEXA) || defined(CPU_KRAIT)
409239268Sgonzo	orr	r0, r0, #CPU_CONTROL_V6_EXTPAGE
410258845Szbb	orr	r0, r0, #CPU_CONTROL_AF_ENABLE
411239268Sgonzo#endif
412239268Sgonzo	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE)
413239268Sgonzo	mcr	p15, 0, r0, c1, c0, 0
414239268Sgonzo	nop
415239268Sgonzo	nop
416239268Sgonzo	nop
417239268Sgonzo	CPWAIT(r0)
418239268Sgonzo
419239268Sgonzo	adr	r1, .Lstart
420239268Sgonzo	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
421239268Sgonzo	mrc	p15, 0, r0, c0, c0, 5
422239268Sgonzo	and	r0, r0, #15
423239268Sgonzo	mov	r1, #2048
424239268Sgonzo	mul	r2, r1, r0
425239268Sgonzo	sub	sp, sp, r2
426239268Sgonzo	str	r1, [sp]
427239268Sgonzo	ldr	pc, .Lmpvirt_done
428239268Sgonzo
429239268Sgonzompvirt_done:
430239268Sgonzo
431239268Sgonzo	mov	fp, #0			/* trace back starts here */
432239268Sgonzo	bl	_C_LABEL(init_secondary)	/* Off we go */
433239268Sgonzo
434239268Sgonzo	adr	r0, .Lmpreturned
435239268Sgonzo	b	_C_LABEL(panic)
436239268Sgonzo	/* NOTREACHED */
437239268Sgonzo
438239268Sgonzo.Lmpreturned:
439239268Sgonzo	.asciz	"main() returned"
440239268Sgonzo	.align	0
441248361SandrewEND(mpentry)
442239268Sgonzo#endif
443239268Sgonzo
444135640ScognetENTRY_NP(cpu_halt)
445129198Scognet	mrs     r2, cpsr
446129198Scognet	bic	r2, r2, #(PSR_MODE)
447129198Scognet	orr     r2, r2, #(PSR_SVC32_MODE)
448129198Scognet	orr	r2, r2, #(I32_bit | F32_bit)
449261393Sian	msr     cpsr_fsxc, r2
450129198Scognet
451129198Scognet	ldr	r4, .Lcpu_reset_address
452129198Scognet	ldr	r4, [r4]
453129198Scognet
454129198Scognet	ldr	r0, .Lcpufuncs
455129198Scognet	mov	lr, pc
456129198Scognet	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
457183839Sraj	mov	lr, pc
458183839Sraj	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
459129198Scognet
460129198Scognet	/*
461129198Scognet	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
462129198Scognet	 * necessary.
463129198Scognet	 */
464129198Scognet
465129198Scognet	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
466129198Scognet	ldr	r1, [r1]
467129198Scognet	cmp	r1, #0
468129198Scognet	mov	r2, #0
469129198Scognet
470129198Scognet	/*
471175983Sraj	 * MMU & IDC off, 32 bit program & data space
472129198Scognet	 * Hurl ourselves into the ROM
473129198Scognet	 */
474129198Scognet	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
475129198Scognet	mcr     15, 0, r0, c1, c0, 0
476129198Scognet	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
477129198Scognet	mov     pc, r4
478129198Scognet
479129198Scognet	/*
480129198Scognet	 * _cpu_reset_address contains the address to branch to, to complete
481129198Scognet	 * the cpu reset after turning the MMU off
482129198Scognet	 * This variable is provided by the hardware specific code
483129198Scognet	 */
484129198Scognet.Lcpu_reset_address:
485129198Scognet	.word	_C_LABEL(cpu_reset_address)
486129198Scognet
487129198Scognet	/*
488129198Scognet	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
489129198Scognet	 * v4 MMU disable instruction needs executing... it is an illegal instruction
490129198Scognet	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
491129198Scognet	 * instruction / data-abort / reset loop.
492129198Scognet	 */
493129198Scognet.Lcpu_reset_needs_v4_MMU_disable:
494129198Scognet	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
495248361SandrewEND(cpu_halt)
496129198Scognet
497129198Scognet
498129198Scognet/*
499129198Scognet * setjump + longjmp
500129198Scognet */
501129198ScognetENTRY(setjmp)
502129198Scognet	stmia	r0, {r4-r14}
503129198Scognet	mov	r0, #0x00000000
504137463Scognet	RET
505248361SandrewEND(setjmp)
506129198Scognet
507129198ScognetENTRY(longjmp)
508129198Scognet	ldmia	r0, {r4-r14}
509129198Scognet	mov	r0, #0x00000001
510137463Scognet	RET
511248361SandrewEND(longjmp)
512129198Scognet
513129198Scognet	.data
514129198Scognet	.global _C_LABEL(esym)
515129198Scognet_C_LABEL(esym):	.word	_C_LABEL(end)
516129198Scognet
517129198ScognetENTRY_NP(abort)
518129198Scognet	b	_C_LABEL(abort)
519248361SandrewEND(abort)
520129198Scognet
521135640ScognetENTRY_NP(sigcode)
522135640Scognet	mov	r0, sp
523245414Sandrew
524245414Sandrew	/*
525245414Sandrew	 * Call the sigreturn system call.
526245414Sandrew	 *
527245414Sandrew	 * We have to load r7 manually rather than using
528245414Sandrew	 * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
529245414Sandrew	 * correct. Using the alternative places esigcode at the address
530245414Sandrew	 * of the data rather than the address one past the data.
531245414Sandrew	 */
532245414Sandrew
533245414Sandrew	ldr	r7, [pc, #12]	/* Load SYS_sigreturn */
534135640Scognet	swi	SYS_sigreturn
535135640Scognet
536135640Scognet	/* Well if that failed we better exit quick ! */
537135640Scognet
538245414Sandrew	ldr	r7, [pc, #8]	/* Load SYS_exit */
539135640Scognet	swi	SYS_exit
540135640Scognet
541245414Sandrew	/* Branch back to retry SYS_sigreturn */
542245414Sandrew	b	. - 16
543245414Sandrew
544245414Sandrew	.word	SYS_sigreturn
545245414Sandrew	.word	SYS_exit
546245414Sandrew
547135640Scognet	.align	0
548135640Scognet	.global _C_LABEL(esigcode)
549135640Scognet		_C_LABEL(esigcode):
550143681Sjmg
551135640Scognet	.data
552135640Scognet	.global szsigcode
553135640Scognetszsigcode:
554135640Scognet	.long esigcode-sigcode
555248361SandrewEND(sigcode)
556129198Scognet/* End of locore.S */
557