locore-v4.S revision 266849
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 266849 2014-05-29 16:54:15Z cognet $");
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 */
85266271Sgavin	mov	fp, r3		/* Future expansion */
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
151261855Sandrew	/* Find the delta between VA and PA */
152261855Sandrew	adr	r0, Lpagetable
153261855Sandrew	ldr	r1, [r0]
154261855Sandrew	sub	r2, r1, r0
155261855Sandrew	/* At this point: r2 = VA - PA */
156261855Sandrew
157261855Sandrew	/*
158261855Sandrew	 * Find the physical address of the table. After these two
159261855Sandrew	 * instructions:
160261855Sandrew	 * r1 = va(pagetable)
161261855Sandrew	 *
162261855Sandrew	 * r0 = va(pagetable) - (VA - PA)
163261855Sandrew	 *    = va(pagetable) - VA + PA
164261855Sandrew	 *    = pa(pagetable)
165261855Sandrew	 */
166261855Sandrew	ldr	r1, [r0, #4]
167261227Sandrew	sub	r0, r1, r2
168261227Sandrew
169266849Scognet#ifndef _ARM_ARCH_6
170261606Sandrew	/*
171266849Scognet	 * Some of the older ports (the various XScale, mostly) assume
172266849Scognet	 * that the memory before the kernel is mapped, and use it for
173266849Scognet	 * the various stacks, page tables, etc. For those CPUs, map the
174266849Scognet	 * 64 first MB of RAM, as it used to be.
175266849Scognet	 */
176266849Scognet	/*
177261606Sandrew	 * Map PA == VA
178266849Scognet	 */
179266849Scognet	ldr     r5, =PHYSADDR
180266849Scognet	mov     r1, r5
181266849Scognet	mov     r2, r5
182266849Scognet	/* Map 64MiB, preserved over calls to build_pagetables */
183266849Scognet	mov     r3, #64
184266849Scognet	bl      build_pagetables
185266849Scognet
186266849Scognet	/* Create the kernel map to jump to */
187266849Scognet	mov     r1, r5
188266849Scognet	ldr     r2, =(KERNBASE)
189266849Scognet	bl      build_pagetables
190266849Scognet	ldr	r5, =(KERNPHYSADDR)
191266849Scognet#else
192266849Scognet	/*
193266849Scognet	 * Map PA == VA
194266849Scognet	 */
195261855Sandrew	/* Find the start kernels load address */
196261855Sandrew	adr	r5, _start
197261855Sandrew	ldr	r2, =(L1_S_OFFSET)
198261855Sandrew	bic	r5, r2
199261606Sandrew	mov	r1, r5
200261606Sandrew	mov	r2, r5
201261606Sandrew	/* Map 64MiB, preserved over calls to build_pagetables */
202261606Sandrew	mov	r3, #64
203261606Sandrew	bl	build_pagetables
204129198Scognet
205261606Sandrew	/* Create the kernel map to jump to */
206261606Sandrew	mov	r1, r5
207261855Sandrew	ldr	r2, =(KERNVIRTADDR)
208261606Sandrew	bl	build_pagetables
209266849Scognet#endif
210261606Sandrew
211261606Sandrew#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
212261606Sandrew	/* Create the custom map */
213261783Simp	ldr	r1, =SOCDEV_PA
214261783Simp	ldr	r2, =SOCDEV_VA
215261606Sandrew	bl	build_pagetables
216261606Sandrew#endif
217129198Scognet
218239268Sgonzo#if defined(SMP)
219239268Sgonzo	orr 	r0, r0, #2		/* Set TTB shared memory flag */
220239268Sgonzo#endif
221129198Scognet	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
222129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
223129198Scognet
224259640Sganbold#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
225239268Sgonzo	mov	r0, #0
226239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
227239268Sgonzo#endif
228239268Sgonzo
229129198Scognet	/* Set the Domain Access register.  Very important! */
230143681Sjmg	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
231129198Scognet	mcr	p15, 0, r0, c3, c0, 0
232248961Sian	/*
233248961Sian	 * Enable MMU.
234248961Sian	 * On armv6 enable extended page tables, and set alignment checking
235248961Sian	 * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
236248961Sian	 * instructions emitted by clang.
237248961Sian	 */
238129198Scognet	mrc	p15, 0, r0, c1, c0, 0
239248961Sian#ifdef _ARM_ARCH_6
240248961Sian	orr	r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
241256628Sian	orr	r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
242250928Sgber	orr	r0, r0, #(CPU_CONTROL_AF_ENABLE)
243239268Sgonzo#endif
244243602Sgonzo	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE)
245129198Scognet	mcr	p15, 0, r0, c1, c0, 0
246153550Scognet	nop
247153550Scognet	nop
248153550Scognet	nop
249129198Scognet	CPWAIT(r0)
250129198Scognet
251129198Scognetmmu_done:
252153550Scognet	nop
253129198Scognet	adr	r1, .Lstart
254129198Scognet	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
255129198Scognet	sub	r2, r2, r1		/* get zero init data */
256129198Scognet	mov	r3, #0
257129198Scognet.L1:
258150863Scognet	str	r3, [r1], #0x0004	/* get zero init data */
259129198Scognet	subs	r2, r2, #4
260129198Scognet	bgt	.L1
261153550Scognet	ldr	pc, .Lvirt_done
262129198Scognet
263142145Scognetvirt_done:
264261663Sandrew	mov	r1, #28			/* loader info size is 28 bytes also second arg */
265236524Simp	subs	sp, sp, r1		/* allocate arm_boot_params struct on stack */
266261855Sandrew	mov	r0, sp			/* loader info pointer is first arg */
267247608Sandrew	bic	sp, sp, #7		/* align stack to 8 bytes */
268236524Simp	str	r1, [r0]		/* Store length of loader info */
269236524Simp	str	r9, [r0, #4]		/* Store r0 from boot loader */
270236524Simp	str	r8, [r0, #8]		/* Store r1 from boot loader */
271236524Simp	str	ip, [r0, #12]		/* store r2 from boot loader */
272236524Simp	str	fp, [r0, #16]		/* store r3 from boot loader */
273261562Sandrew	str	r5, [r0, #20]		/* store the physical address */
274261855Sandrew	adr	r4, Lpagetable		/* load the pagetable address */
275261855Sandrew	ldr	r5, [r4, #4]
276261663Sandrew	str	r5, [r0, #24]		/* store the pagetable address */
277175983Sraj	mov	fp, #0			/* trace back starts here */
278129198Scognet	bl	_C_LABEL(initarm)	/* Off we go */
279129198Scognet
280129198Scognet	/* init arm will return the new stack pointer. */
281129198Scognet	mov	sp, r0
282129198Scognet
283129198Scognet	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
284129198Scognet
285129198Scognet	adr	r0, .Lmainreturned
286130164Sphk	b	_C_LABEL(panic)
287175983Sraj	/* NOTREACHED */
288261606SandrewEND(btext)
289261606SandrewEND(_start)
290261606Sandrew
291261606Sandrew/*
292261606Sandrew * Builds the page table
293261606Sandrew * r0 - The table base address
294261606Sandrew * r1 - The physical address (trashed)
295261606Sandrew * r2 - The virtual address (trashed)
296261606Sandrew * r3 - The number of 1MiB sections
297261606Sandrew * r4 - Trashed
298261606Sandrew *
299261606Sandrew * Addresses must be 1MiB aligned
300261606Sandrew */
301261606Sandrewbuild_pagetables:
302261606Sandrew	/* Set the required page attributed */
303261606Sandrew	ldr	r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
304261606Sandrew#if defined(SMP)
305261606Sandrew	orr	r4, #(L1_SHARED)
306261606Sandrew#endif
307261606Sandrew	orr	r1, r4
308261606Sandrew
309261606Sandrew	/* Move the virtual address to the correct bit location */
310261606Sandrew	lsr	r2, #(L1_S_SHIFT - 2)
311261606Sandrew
312261606Sandrew	mov	r4, r3
313261606Sandrew1:
314261606Sandrew	str	r1, [r0, r2]
315261606Sandrew	add	r2, r2, #4
316261606Sandrew	add	r1, r1, #(L1_S_SIZE)
317261606Sandrew	adds	r4, r4, #-1
318261606Sandrew	bhi	1b
319261606Sandrew
320261606Sandrew	RET
321261606Sandrew
322261855SandrewLpagetable:
323261855Sandrew	.word	.
324261855Sandrew	.word	pagetable
325261855Sandrew
326150863ScognetLvirtaddr:
327150863Scognet	.word	KERNVIRTADDR
328150863ScognetLphysaddr:
329150863Scognet	.word	KERNPHYSADDR
330166819ScognetLreal_start:
331166819Scognet	.word	_start
332261855SandrewLend:
333166819Scognet	.word	_edata
334261855Sandrew
335129198Scognet.Lstart:
336129198Scognet	.word	_edata
337261227Sandrew	.word	_ebss
338129198Scognet	.word	svcstk + INIT_ARM_STACK_SIZE
339129198Scognet
340153550Scognet.Lvirt_done:
341153550Scognet	.word	virt_done
342239268Sgonzo
343129198Scognet.Lmainreturned:
344129198Scognet	.asciz	"main() returned"
345129198Scognet	.align	0
346129198Scognet
347129198Scognet	.bss
348129198Scognetsvcstk:
349129198Scognet	.space	INIT_ARM_STACK_SIZE
350129198Scognet
351261227Sandrew/*
352261227Sandrew * Memory for the initial pagetable. We are unable to place this in
353261227Sandrew * the bss as this will be cleared after the table is loaded.
354261227Sandrew */
355261227Sandrew	.section ".init_pagetable"
356261227Sandrew	.align	14 /* 16KiB aligned */
357261227Sandrewpagetable:
358261227Sandrew	.space	L1_TABLE_SIZE
359261227Sandrew
360129198Scognet	.text
361129198Scognet	.align	0
362129198Scognet
363143681Sjmg.Lcpufuncs:
364129198Scognet	.word	_C_LABEL(cpufuncs)
365129198Scognet
366239268Sgonzo#if defined(SMP)
367239268Sgonzo
368265705Sian.Lmpvirt_done:
369265705Sian	.word	mpvirt_done
370265705SianLstartup_pagetable_secondary:
371265705Sian	.word	temp_pagetable
372265705Sian
373239268SgonzoASENTRY_NP(mpentry)
374239268Sgonzo
375239268Sgonzo	/* Make sure interrupts are disabled. */
376239268Sgonzo	mrs	r7, cpsr
377239268Sgonzo	orr	r7, r7, #(I32_bit|F32_bit)
378239268Sgonzo	msr	cpsr_c, r7
379239268Sgonzo
380265784Sian	/* Disable MMU.  It should be disabled already, but make sure. */
381239268Sgonzo	mrc	p15, 0, r2, c1, c0, 0
382239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
383239268Sgonzo	    CPU_CONTROL_WBUF_ENABLE)
384239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
385239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
386239268Sgonzo	mcr	p15, 0, r2, c1, c0, 0
387239268Sgonzo	nop
388239268Sgonzo	nop
389239268Sgonzo	nop
390265784Sian	CPWAIT(r0)
391239268Sgonzo
392265784Sian#if defined(ARM_MMU_V6)
393265784Sian	bl	armv6_idcache_inv_all	/* Modifies r0 only */
394265784Sian#elif defined(ARM_MMU_V7)
395265784Sian	bl	armv7_idcache_inv_all	/* Modifies r0-r3, ip */
396265784Sian#endif
397265784Sian
398239268Sgonzo	ldr	r0, Lstartup_pagetable_secondary
399239268Sgonzo	bic	r0, r0, #0xf0000000
400239268Sgonzo	orr	r0, r0, #PHYSADDR
401239268Sgonzo	ldr	r0, [r0]
402262413Sian	orr 	r0, r0, #2		/* Set TTB shared memory flag */
403239268Sgonzo	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
404239268Sgonzo	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
405239268Sgonzo
406239268Sgonzo	mov	r0, #0
407239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
408239268Sgonzo
409239268Sgonzo	/* Set the Domain Access register.  Very important! */
410239268Sgonzo	mov	r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
411239268Sgonzo	mcr	p15, 0, r0, c3, c0, 0
412239268Sgonzo	/* Enable MMU */
413239268Sgonzo	mrc	p15, 0, r0, c1, c0, 0
414239268Sgonzo	orr	r0, r0, #CPU_CONTROL_V6_EXTPAGE
415258845Szbb	orr	r0, r0, #CPU_CONTROL_AF_ENABLE
416265784Sian	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
417265784Sian	    CPU_CONTROL_WBUF_ENABLE)
418265784Sian	orr	r0, r0, #(CPU_CONTROL_IC_ENABLE)
419265784Sian	orr	r0, r0, #(CPU_CONTROL_BPRD_ENABLE)
420239268Sgonzo	mcr	p15, 0, r0, c1, c0, 0
421239268Sgonzo	nop
422239268Sgonzo	nop
423239268Sgonzo	nop
424239268Sgonzo	CPWAIT(r0)
425239268Sgonzo
426239268Sgonzo	adr	r1, .Lstart
427239268Sgonzo	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
428239268Sgonzo	mrc	p15, 0, r0, c0, c0, 5
429239268Sgonzo	and	r0, r0, #15
430239268Sgonzo	mov	r1, #2048
431239268Sgonzo	mul	r2, r1, r0
432239268Sgonzo	sub	sp, sp, r2
433239268Sgonzo	str	r1, [sp]
434239268Sgonzo	ldr	pc, .Lmpvirt_done
435239268Sgonzo
436239268Sgonzompvirt_done:
437239268Sgonzo
438239268Sgonzo	mov	fp, #0			/* trace back starts here */
439239268Sgonzo	bl	_C_LABEL(init_secondary)	/* Off we go */
440239268Sgonzo
441239268Sgonzo	adr	r0, .Lmpreturned
442239268Sgonzo	b	_C_LABEL(panic)
443239268Sgonzo	/* NOTREACHED */
444239268Sgonzo
445239268Sgonzo.Lmpreturned:
446265705Sian	.asciz	"init_secondary() returned"
447239268Sgonzo	.align	0
448248361SandrewEND(mpentry)
449239268Sgonzo#endif
450239268Sgonzo
451135640ScognetENTRY_NP(cpu_halt)
452129198Scognet	mrs     r2, cpsr
453129198Scognet	bic	r2, r2, #(PSR_MODE)
454129198Scognet	orr     r2, r2, #(PSR_SVC32_MODE)
455129198Scognet	orr	r2, r2, #(I32_bit | F32_bit)
456261393Sian	msr     cpsr_fsxc, r2
457129198Scognet
458129198Scognet	ldr	r4, .Lcpu_reset_address
459129198Scognet	ldr	r4, [r4]
460129198Scognet
461129198Scognet	ldr	r0, .Lcpufuncs
462129198Scognet	mov	lr, pc
463129198Scognet	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
464183839Sraj	mov	lr, pc
465183839Sraj	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
466129198Scognet
467129198Scognet	/*
468129198Scognet	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
469129198Scognet	 * necessary.
470129198Scognet	 */
471129198Scognet
472129198Scognet	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
473129198Scognet	ldr	r1, [r1]
474129198Scognet	cmp	r1, #0
475129198Scognet	mov	r2, #0
476129198Scognet
477129198Scognet	/*
478175983Sraj	 * MMU & IDC off, 32 bit program & data space
479129198Scognet	 * Hurl ourselves into the ROM
480129198Scognet	 */
481129198Scognet	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
482129198Scognet	mcr     15, 0, r0, c1, c0, 0
483129198Scognet	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
484129198Scognet	mov     pc, r4
485129198Scognet
486129198Scognet	/*
487129198Scognet	 * _cpu_reset_address contains the address to branch to, to complete
488129198Scognet	 * the cpu reset after turning the MMU off
489129198Scognet	 * This variable is provided by the hardware specific code
490129198Scognet	 */
491129198Scognet.Lcpu_reset_address:
492129198Scognet	.word	_C_LABEL(cpu_reset_address)
493129198Scognet
494129198Scognet	/*
495129198Scognet	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
496129198Scognet	 * v4 MMU disable instruction needs executing... it is an illegal instruction
497129198Scognet	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
498129198Scognet	 * instruction / data-abort / reset loop.
499129198Scognet	 */
500129198Scognet.Lcpu_reset_needs_v4_MMU_disable:
501129198Scognet	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
502248361SandrewEND(cpu_halt)
503129198Scognet
504129198Scognet
505129198Scognet/*
506129198Scognet * setjump + longjmp
507129198Scognet */
508129198ScognetENTRY(setjmp)
509129198Scognet	stmia	r0, {r4-r14}
510129198Scognet	mov	r0, #0x00000000
511137463Scognet	RET
512248361SandrewEND(setjmp)
513129198Scognet
514129198ScognetENTRY(longjmp)
515129198Scognet	ldmia	r0, {r4-r14}
516129198Scognet	mov	r0, #0x00000001
517137463Scognet	RET
518248361SandrewEND(longjmp)
519129198Scognet
520129198Scognet	.data
521129198Scognet	.global _C_LABEL(esym)
522129198Scognet_C_LABEL(esym):	.word	_C_LABEL(end)
523129198Scognet
524129198ScognetENTRY_NP(abort)
525129198Scognet	b	_C_LABEL(abort)
526248361SandrewEND(abort)
527129198Scognet
528135640ScognetENTRY_NP(sigcode)
529135640Scognet	mov	r0, sp
530262903Sian	add	r0, r0, #SIGF_UC
531245414Sandrew
532245414Sandrew	/*
533245414Sandrew	 * Call the sigreturn system call.
534245414Sandrew	 *
535245414Sandrew	 * We have to load r7 manually rather than using
536245414Sandrew	 * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
537245414Sandrew	 * correct. Using the alternative places esigcode at the address
538245414Sandrew	 * of the data rather than the address one past the data.
539245414Sandrew	 */
540245414Sandrew
541245414Sandrew	ldr	r7, [pc, #12]	/* Load SYS_sigreturn */
542135640Scognet	swi	SYS_sigreturn
543135640Scognet
544135640Scognet	/* Well if that failed we better exit quick ! */
545135640Scognet
546245414Sandrew	ldr	r7, [pc, #8]	/* Load SYS_exit */
547135640Scognet	swi	SYS_exit
548135640Scognet
549245414Sandrew	/* Branch back to retry SYS_sigreturn */
550245414Sandrew	b	. - 16
551245414Sandrew
552245414Sandrew	.word	SYS_sigreturn
553245414Sandrew	.word	SYS_exit
554245414Sandrew
555135640Scognet	.align	0
556135640Scognet	.global _C_LABEL(esigcode)
557135640Scognet		_C_LABEL(esigcode):
558143681Sjmg
559135640Scognet	.data
560135640Scognet	.global szsigcode
561135640Scognetszsigcode:
562135640Scognet	.long esigcode-sigcode
563248361SandrewEND(sigcode)
564129198Scognet/* End of locore.S */
565