locore-v4.S revision 270862
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>
40270862Sian#include <machine/cpuconf.h>
41129198Scognet#include <machine/pte.h>
42236524Simp
43129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/locore.S 270862 2014-08-30 22:21:57Z ian $");
44129198Scognet
45159849Simp/* What size should this really be ? It is only used by initarm() */
46239268Sgonzo#define INIT_ARM_STACK_SIZE	(2048 * 4)
47129198Scognet
48129198Scognet#define	CPWAIT_BRANCH							 \
49129198Scognet	sub	pc, pc, #4
50129198Scognet
51129198Scognet#define	CPWAIT(tmp)							 \
52129198Scognet	mrc	p15, 0, tmp, c2, c0, 0	/* arbitrary read of CP15 */	;\
53129198Scognet	mov	tmp, tmp		/* wait for it to complete */	;\
54129198Scognet	CPWAIT_BRANCH			/* branch to next insn */
55129198Scognet
56235277Simp/*
57235277Simp * This is for kvm_mkdb, and should be the address of the beginning
58235277Simp * of the kernel text segment (not necessarily the same as kernbase).
59235277Simp */
60129198Scognet	.text
61129198Scognet	.align	0
62129198Scognet.globl kernbase
63129198Scognet.set kernbase,KERNBASE
64150863Scognet.globl physaddr
65150863Scognet.set physaddr,PHYSADDR
66129198Scognet
67183878Sraj/*
68236524Simp * On entry for FreeBSD boot ABI:
69236524Simp *	r0 - metadata pointer or 0 (boothowto on AT91's boot2)
70218227Smarcel *	r1 - if (r0 == 0) then metadata pointer
71236524Simp * On entry for Linux boot ABI:
72236524Simp *	r0 - 0
73236524Simp *	r1 - machine type (passed as arg2 to initarm)
74236524Simp *	r2 - Pointer to a tagged list or dtb image (phys addr) (passed as arg1 initarm)
75236524Simp *
76236524Simp * For both types of boot we gather up the args, put them in a struct arm_boot_params
77236524Simp * structure and pass that to initarm.
78183878Sraj */
79269390Sian	.globl	btext
80269390Sianbtext:
81218227SmarcelASENTRY_NP(_start)
82250253Sian	STOP_UNWINDING		/* Can't unwind into the bootloader! */
83250253Sian
84236524Simp	mov	r9, r0		/* 0 or boot mode from boot2 */
85236524Simp	mov	r8, r1		/* Save Machine type */
86236524Simp	mov	ip, r2		/* Save meta data */
87266271Sgavin	mov	fp, r3		/* Future expansion */
88183878Sraj
89193846Smarcel	/* Make sure interrupts are disabled. */
90193846Smarcel	mrs	r7, cpsr
91193846Smarcel	orr	r7, r7, #(I32_bit|F32_bit)
92193846Smarcel	msr	cpsr_c, r7
93193846Smarcel
94166819Scognet#if defined (FLASHADDR) && defined(LOADERRAMADDR)
95166819Scognet	/* Check if we're running from flash. */
96166819Scognet	ldr	r7, =FLASHADDR
97175983Sraj	/*
98166819Scognet	 * If we're running with MMU disabled, test against the
99166819Scognet	 * physical address instead.
100166819Scognet	 */
101166819Scognet	mrc     p15, 0, r2, c1, c0, 0
102166819Scognet	ands	r2, r2, #CPU_CONTROL_MMU_ENABLE
103236524Simp	ldreq	r6, =PHYSADDR
104236524Simp	ldrne	r6, =LOADERRAMADDR
105236524Simp	cmp	r7, r6
106166819Scognet	bls 	flash_lower
107166819Scognet	cmp	r7, pc
108166819Scognet	bhi	from_ram
109166819Scognet	b	do_copy
110166819Scognet
111166819Scognetflash_lower:
112236524Simp	cmp	r6, pc
113166819Scognet	bls	from_ram
114166819Scognetdo_copy:
115236524Simp	ldr	r7, =KERNBASE
116175983Sraj	adr	r1, _start
117166819Scognet	ldr	r0, Lreal_start
118166819Scognet	ldr	r2, Lend
119166819Scognet	sub	r2, r2, r0
120236524Simp	sub	r0, r0, r7
121236524Simp	add	r0, r0, r6
122166819Scognet	mov	r4, r0
123166819Scognet	bl	memcpy
124166819Scognet	ldr	r0, Lram_offset
125166819Scognet	add	pc, r4, r0
126166819ScognetLram_offset:	.word from_ram-_C_LABEL(_start)
127166819Scognetfrom_ram:
128166819Scognet	nop
129135640Scognet#endif
130135640Scognet	adr	r7, Lunmapped
131190602Scognet	bic     r7, r7, #0xf0000000
132153616Scognet	orr     r7, r7, #PHYSADDR
133143681Sjmg
134175983Sraj
135166819Scognetdisable_mmu:
136135640Scognet	/* Disable MMU for a while */
137143681Sjmg	mrc     p15, 0, r2, c1, c0, 0
138153550Scognet	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
139153550Scognet	    CPU_CONTROL_WBUF_ENABLE)
140153550Scognet	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
141153550Scognet	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
142135640Scognet	mcr     p15, 0, r2, c1, c0, 0
143129198Scognet
144135640Scognet	nop
145135640Scognet	nop
146135640Scognet	nop
147135640Scognet	mov	pc, r7
148135640ScognetLunmapped:
149261227Sandrew	/*
150261227Sandrew	 * Build page table from scratch.
151261227Sandrew	 */
152261227Sandrew
153261855Sandrew	/* Find the delta between VA and PA */
154261855Sandrew	adr	r0, Lpagetable
155261855Sandrew	ldr	r1, [r0]
156261855Sandrew	sub	r2, r1, r0
157261855Sandrew	/* At this point: r2 = VA - PA */
158261855Sandrew
159261855Sandrew	/*
160261855Sandrew	 * Find the physical address of the table. After these two
161261855Sandrew	 * instructions:
162261855Sandrew	 * r1 = va(pagetable)
163261855Sandrew	 *
164261855Sandrew	 * r0 = va(pagetable) - (VA - PA)
165261855Sandrew	 *    = va(pagetable) - VA + PA
166261855Sandrew	 *    = pa(pagetable)
167261855Sandrew	 */
168261855Sandrew	ldr	r1, [r0, #4]
169261227Sandrew	sub	r0, r1, r2
170261227Sandrew
171266849Scognet#ifndef _ARM_ARCH_6
172261606Sandrew	/*
173266849Scognet	 * Some of the older ports (the various XScale, mostly) assume
174266849Scognet	 * that the memory before the kernel is mapped, and use it for
175266849Scognet	 * the various stacks, page tables, etc. For those CPUs, map the
176266849Scognet	 * 64 first MB of RAM, as it used to be.
177266849Scognet	 */
178266849Scognet	/*
179261606Sandrew	 * Map PA == VA
180266849Scognet	 */
181266849Scognet	ldr     r5, =PHYSADDR
182266849Scognet	mov     r1, r5
183266849Scognet	mov     r2, r5
184266849Scognet	/* Map 64MiB, preserved over calls to build_pagetables */
185266849Scognet	mov     r3, #64
186266849Scognet	bl      build_pagetables
187266849Scognet
188266849Scognet	/* Create the kernel map to jump to */
189266849Scognet	mov     r1, r5
190266849Scognet	ldr     r2, =(KERNBASE)
191266849Scognet	bl      build_pagetables
192266849Scognet	ldr	r5, =(KERNPHYSADDR)
193266849Scognet#else
194266849Scognet	/*
195266849Scognet	 * Map PA == VA
196266849Scognet	 */
197261855Sandrew	/* Find the start kernels load address */
198261855Sandrew	adr	r5, _start
199261855Sandrew	ldr	r2, =(L1_S_OFFSET)
200261855Sandrew	bic	r5, r2
201261606Sandrew	mov	r1, r5
202261606Sandrew	mov	r2, r5
203261606Sandrew	/* Map 64MiB, preserved over calls to build_pagetables */
204261606Sandrew	mov	r3, #64
205261606Sandrew	bl	build_pagetables
206129198Scognet
207261606Sandrew	/* Create the kernel map to jump to */
208261606Sandrew	mov	r1, r5
209261855Sandrew	ldr	r2, =(KERNVIRTADDR)
210261606Sandrew	bl	build_pagetables
211266849Scognet#endif
212261606Sandrew
213261606Sandrew#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
214261606Sandrew	/* Create the custom map */
215261783Simp	ldr	r1, =SOCDEV_PA
216261783Simp	ldr	r2, =SOCDEV_VA
217261606Sandrew	bl	build_pagetables
218261606Sandrew#endif
219129198Scognet
220239268Sgonzo#if defined(SMP)
221239268Sgonzo	orr 	r0, r0, #2		/* Set TTB shared memory flag */
222239268Sgonzo#endif
223129198Scognet	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
224129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
225129198Scognet
226259640Sganbold#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
227239268Sgonzo	mov	r0, #0
228239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
229239268Sgonzo#endif
230239268Sgonzo
231129198Scognet	/* Set the Domain Access register.  Very important! */
232143681Sjmg	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
233129198Scognet	mcr	p15, 0, r0, c3, c0, 0
234248961Sian	/*
235248961Sian	 * Enable MMU.
236248961Sian	 * On armv6 enable extended page tables, and set alignment checking
237248961Sian	 * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
238248961Sian	 * instructions emitted by clang.
239248961Sian	 */
240129198Scognet	mrc	p15, 0, r0, c1, c0, 0
241248961Sian#ifdef _ARM_ARCH_6
242248961Sian	orr	r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
243256628Sian	orr	r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
244250928Sgber	orr	r0, r0, #(CPU_CONTROL_AF_ENABLE)
245239268Sgonzo#endif
246243602Sgonzo	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE)
247129198Scognet	mcr	p15, 0, r0, c1, c0, 0
248153550Scognet	nop
249153550Scognet	nop
250153550Scognet	nop
251129198Scognet	CPWAIT(r0)
252129198Scognet
253129198Scognetmmu_done:
254153550Scognet	nop
255129198Scognet	adr	r1, .Lstart
256129198Scognet	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
257129198Scognet	sub	r2, r2, r1		/* get zero init data */
258129198Scognet	mov	r3, #0
259129198Scognet.L1:
260150863Scognet	str	r3, [r1], #0x0004	/* get zero init data */
261129198Scognet	subs	r2, r2, #4
262129198Scognet	bgt	.L1
263153550Scognet	ldr	pc, .Lvirt_done
264129198Scognet
265142145Scognetvirt_done:
266261663Sandrew	mov	r1, #28			/* loader info size is 28 bytes also second arg */
267236524Simp	subs	sp, sp, r1		/* allocate arm_boot_params struct on stack */
268261855Sandrew	mov	r0, sp			/* loader info pointer is first arg */
269247608Sandrew	bic	sp, sp, #7		/* align stack to 8 bytes */
270236524Simp	str	r1, [r0]		/* Store length of loader info */
271236524Simp	str	r9, [r0, #4]		/* Store r0 from boot loader */
272236524Simp	str	r8, [r0, #8]		/* Store r1 from boot loader */
273236524Simp	str	ip, [r0, #12]		/* store r2 from boot loader */
274236524Simp	str	fp, [r0, #16]		/* store r3 from boot loader */
275261562Sandrew	str	r5, [r0, #20]		/* store the physical address */
276261855Sandrew	adr	r4, Lpagetable		/* load the pagetable address */
277261855Sandrew	ldr	r5, [r4, #4]
278261663Sandrew	str	r5, [r0, #24]		/* store the pagetable address */
279175983Sraj	mov	fp, #0			/* trace back starts here */
280129198Scognet	bl	_C_LABEL(initarm)	/* Off we go */
281129198Scognet
282129198Scognet	/* init arm will return the new stack pointer. */
283129198Scognet	mov	sp, r0
284129198Scognet
285129198Scognet	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
286129198Scognet
287129198Scognet	adr	r0, .Lmainreturned
288130164Sphk	b	_C_LABEL(panic)
289175983Sraj	/* NOTREACHED */
290261606SandrewEND(_start)
291261606Sandrew
292261606Sandrew/*
293261606Sandrew * Builds the page table
294261606Sandrew * r0 - The table base address
295261606Sandrew * r1 - The physical address (trashed)
296261606Sandrew * r2 - The virtual address (trashed)
297261606Sandrew * r3 - The number of 1MiB sections
298261606Sandrew * r4 - Trashed
299261606Sandrew *
300261606Sandrew * Addresses must be 1MiB aligned
301261606Sandrew */
302261606Sandrewbuild_pagetables:
303261606Sandrew	/* Set the required page attributed */
304261606Sandrew	ldr	r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
305261606Sandrew#if defined(SMP)
306261606Sandrew	orr	r4, #(L1_SHARED)
307261606Sandrew#endif
308261606Sandrew	orr	r1, r4
309261606Sandrew
310261606Sandrew	/* Move the virtual address to the correct bit location */
311261606Sandrew	lsr	r2, #(L1_S_SHIFT - 2)
312261606Sandrew
313261606Sandrew	mov	r4, r3
314261606Sandrew1:
315261606Sandrew	str	r1, [r0, r2]
316261606Sandrew	add	r2, r2, #4
317261606Sandrew	add	r1, r1, #(L1_S_SIZE)
318261606Sandrew	adds	r4, r4, #-1
319261606Sandrew	bhi	1b
320261606Sandrew
321261606Sandrew	RET
322261606Sandrew
323261855SandrewLpagetable:
324261855Sandrew	.word	.
325261855Sandrew	.word	pagetable
326261855Sandrew
327150863ScognetLvirtaddr:
328150863Scognet	.word	KERNVIRTADDR
329150863ScognetLphysaddr:
330150863Scognet	.word	KERNPHYSADDR
331166819ScognetLreal_start:
332166819Scognet	.word	_start
333261855SandrewLend:
334166819Scognet	.word	_edata
335261855Sandrew
336129198Scognet.Lstart:
337129198Scognet	.word	_edata
338261227Sandrew	.word	_ebss
339129198Scognet	.word	svcstk + INIT_ARM_STACK_SIZE
340129198Scognet
341153550Scognet.Lvirt_done:
342153550Scognet	.word	virt_done
343239268Sgonzo
344129198Scognet.Lmainreturned:
345129198Scognet	.asciz	"main() returned"
346129198Scognet	.align	0
347129198Scognet
348129198Scognet	.bss
349129198Scognetsvcstk:
350129198Scognet	.space	INIT_ARM_STACK_SIZE
351129198Scognet
352261227Sandrew/*
353261227Sandrew * Memory for the initial pagetable. We are unable to place this in
354261227Sandrew * the bss as this will be cleared after the table is loaded.
355261227Sandrew */
356261227Sandrew	.section ".init_pagetable"
357261227Sandrew	.align	14 /* 16KiB aligned */
358261227Sandrewpagetable:
359261227Sandrew	.space	L1_TABLE_SIZE
360261227Sandrew
361129198Scognet	.text
362129198Scognet	.align	0
363129198Scognet
364143681Sjmg.Lcpufuncs:
365129198Scognet	.word	_C_LABEL(cpufuncs)
366129198Scognet
367239268Sgonzo#if defined(SMP)
368239268Sgonzo
369265705Sian.Lmpvirt_done:
370265705Sian	.word	mpvirt_done
371265705SianLstartup_pagetable_secondary:
372265705Sian	.word	temp_pagetable
373265705Sian
374239268SgonzoASENTRY_NP(mpentry)
375239268Sgonzo
376239268Sgonzo	/* Make sure interrupts are disabled. */
377239268Sgonzo	mrs	r7, cpsr
378239268Sgonzo	orr	r7, r7, #(I32_bit|F32_bit)
379239268Sgonzo	msr	cpsr_c, r7
380239268Sgonzo
381265784Sian	/* Disable MMU.  It should be disabled already, but make sure. */
382239268Sgonzo	mrc	p15, 0, r2, c1, c0, 0
383239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
384239268Sgonzo	    CPU_CONTROL_WBUF_ENABLE)
385239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
386239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
387239268Sgonzo	mcr	p15, 0, r2, c1, c0, 0
388239268Sgonzo	nop
389239268Sgonzo	nop
390239268Sgonzo	nop
391265784Sian	CPWAIT(r0)
392239268Sgonzo
393270862Sian#if ARM_MMU_V6
394265784Sian	bl	armv6_idcache_inv_all	/* Modifies r0 only */
395270862Sian#elif ARM_MMU_V7
396265784Sian	bl	armv7_idcache_inv_all	/* Modifies r0-r3, ip */
397265784Sian#endif
398265784Sian
399239268Sgonzo	ldr	r0, Lstartup_pagetable_secondary
400239268Sgonzo	bic	r0, r0, #0xf0000000
401239268Sgonzo	orr	r0, r0, #PHYSADDR
402239268Sgonzo	ldr	r0, [r0]
403262413Sian	orr 	r0, r0, #2		/* Set TTB shared memory flag */
404239268Sgonzo	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
405239268Sgonzo	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
406239268Sgonzo
407239268Sgonzo	mov	r0, #0
408239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
409239268Sgonzo
410239268Sgonzo	/* Set the Domain Access register.  Very important! */
411239268Sgonzo	mov	r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
412239268Sgonzo	mcr	p15, 0, r0, c3, c0, 0
413239268Sgonzo	/* Enable MMU */
414239268Sgonzo	mrc	p15, 0, r0, c1, c0, 0
415239268Sgonzo	orr	r0, r0, #CPU_CONTROL_V6_EXTPAGE
416258845Szbb	orr	r0, r0, #CPU_CONTROL_AF_ENABLE
417265784Sian	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
418265784Sian	    CPU_CONTROL_WBUF_ENABLE)
419265784Sian	orr	r0, r0, #(CPU_CONTROL_IC_ENABLE)
420265784Sian	orr	r0, r0, #(CPU_CONTROL_BPRD_ENABLE)
421239268Sgonzo	mcr	p15, 0, r0, c1, c0, 0
422239268Sgonzo	nop
423239268Sgonzo	nop
424239268Sgonzo	nop
425239268Sgonzo	CPWAIT(r0)
426239268Sgonzo
427239268Sgonzo	adr	r1, .Lstart
428239268Sgonzo	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
429239268Sgonzo	mrc	p15, 0, r0, c0, c0, 5
430239268Sgonzo	and	r0, r0, #15
431239268Sgonzo	mov	r1, #2048
432239268Sgonzo	mul	r2, r1, r0
433239268Sgonzo	sub	sp, sp, r2
434239268Sgonzo	str	r1, [sp]
435239268Sgonzo	ldr	pc, .Lmpvirt_done
436239268Sgonzo
437239268Sgonzompvirt_done:
438239268Sgonzo
439239268Sgonzo	mov	fp, #0			/* trace back starts here */
440239268Sgonzo	bl	_C_LABEL(init_secondary)	/* Off we go */
441239268Sgonzo
442239268Sgonzo	adr	r0, .Lmpreturned
443239268Sgonzo	b	_C_LABEL(panic)
444239268Sgonzo	/* NOTREACHED */
445239268Sgonzo
446239268Sgonzo.Lmpreturned:
447265705Sian	.asciz	"init_secondary() returned"
448239268Sgonzo	.align	0
449248361SandrewEND(mpentry)
450239268Sgonzo#endif
451239268Sgonzo
452135640ScognetENTRY_NP(cpu_halt)
453129198Scognet	mrs     r2, cpsr
454129198Scognet	bic	r2, r2, #(PSR_MODE)
455129198Scognet	orr     r2, r2, #(PSR_SVC32_MODE)
456129198Scognet	orr	r2, r2, #(I32_bit | F32_bit)
457261393Sian	msr     cpsr_fsxc, r2
458129198Scognet
459129198Scognet	ldr	r4, .Lcpu_reset_address
460129198Scognet	ldr	r4, [r4]
461129198Scognet
462129198Scognet	ldr	r0, .Lcpufuncs
463129198Scognet	mov	lr, pc
464129198Scognet	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
465183839Sraj	mov	lr, pc
466183839Sraj	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
467129198Scognet
468129198Scognet	/*
469129198Scognet	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
470129198Scognet	 * necessary.
471129198Scognet	 */
472129198Scognet
473129198Scognet	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
474129198Scognet	ldr	r1, [r1]
475129198Scognet	cmp	r1, #0
476129198Scognet	mov	r2, #0
477129198Scognet
478129198Scognet	/*
479175983Sraj	 * MMU & IDC off, 32 bit program & data space
480129198Scognet	 * Hurl ourselves into the ROM
481129198Scognet	 */
482129198Scognet	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
483129198Scognet	mcr     15, 0, r0, c1, c0, 0
484129198Scognet	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
485129198Scognet	mov     pc, r4
486129198Scognet
487129198Scognet	/*
488129198Scognet	 * _cpu_reset_address contains the address to branch to, to complete
489129198Scognet	 * the cpu reset after turning the MMU off
490129198Scognet	 * This variable is provided by the hardware specific code
491129198Scognet	 */
492129198Scognet.Lcpu_reset_address:
493129198Scognet	.word	_C_LABEL(cpu_reset_address)
494129198Scognet
495129198Scognet	/*
496129198Scognet	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
497129198Scognet	 * v4 MMU disable instruction needs executing... it is an illegal instruction
498129198Scognet	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
499129198Scognet	 * instruction / data-abort / reset loop.
500129198Scognet	 */
501129198Scognet.Lcpu_reset_needs_v4_MMU_disable:
502129198Scognet	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
503248361SandrewEND(cpu_halt)
504129198Scognet
505129198Scognet
506129198Scognet/*
507129198Scognet * setjump + longjmp
508129198Scognet */
509129198ScognetENTRY(setjmp)
510129198Scognet	stmia	r0, {r4-r14}
511129198Scognet	mov	r0, #0x00000000
512137463Scognet	RET
513248361SandrewEND(setjmp)
514129198Scognet
515129198ScognetENTRY(longjmp)
516129198Scognet	ldmia	r0, {r4-r14}
517129198Scognet	mov	r0, #0x00000001
518137463Scognet	RET
519248361SandrewEND(longjmp)
520129198Scognet
521129198Scognet	.data
522129198Scognet	.global _C_LABEL(esym)
523129198Scognet_C_LABEL(esym):	.word	_C_LABEL(end)
524129198Scognet
525129198ScognetENTRY_NP(abort)
526129198Scognet	b	_C_LABEL(abort)
527248361SandrewEND(abort)
528129198Scognet
529135640ScognetENTRY_NP(sigcode)
530135640Scognet	mov	r0, sp
531262903Sian	add	r0, r0, #SIGF_UC
532245414Sandrew
533245414Sandrew	/*
534245414Sandrew	 * Call the sigreturn system call.
535245414Sandrew	 *
536245414Sandrew	 * We have to load r7 manually rather than using
537245414Sandrew	 * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
538245414Sandrew	 * correct. Using the alternative places esigcode at the address
539245414Sandrew	 * of the data rather than the address one past the data.
540245414Sandrew	 */
541245414Sandrew
542245414Sandrew	ldr	r7, [pc, #12]	/* Load SYS_sigreturn */
543135640Scognet	swi	SYS_sigreturn
544135640Scognet
545135640Scognet	/* Well if that failed we better exit quick ! */
546135640Scognet
547245414Sandrew	ldr	r7, [pc, #8]	/* Load SYS_exit */
548135640Scognet	swi	SYS_exit
549135640Scognet
550245414Sandrew	/* Branch back to retry SYS_sigreturn */
551245414Sandrew	b	. - 16
552269390SianEND(sigcode)
553245414Sandrew	.word	SYS_sigreturn
554245414Sandrew	.word	SYS_exit
555245414Sandrew
556135640Scognet	.align	0
557135640Scognet	.global _C_LABEL(esigcode)
558135640Scognet		_C_LABEL(esigcode):
559143681Sjmg
560135640Scognet	.data
561135640Scognet	.global szsigcode
562135640Scognetszsigcode:
563135640Scognet	.long esigcode-sigcode
564269390Sian
565129198Scognet/* End of locore.S */
566