locore-v4.S revision 271240
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 271240 2014-09-07 21:46:54Z andrew $");
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
130143681Sjmg
131166819Scognetdisable_mmu:
132135640Scognet	/* Disable MMU for a while */
133143681Sjmg	mrc     p15, 0, r2, c1, c0, 0
134153550Scognet	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
135153550Scognet	    CPU_CONTROL_WBUF_ENABLE)
136153550Scognet	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
137153550Scognet	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
138135640Scognet	mcr     p15, 0, r2, c1, c0, 0
139129198Scognet
140135640Scognet	nop
141135640Scognet	nop
142135640Scognet	nop
143271240Sandrew	CPWAIT(r0)
144271240Sandrew
145135640ScognetLunmapped:
146261227Sandrew	/*
147261227Sandrew	 * Build page table from scratch.
148261227Sandrew	 */
149261227Sandrew
150261855Sandrew	/* Find the delta between VA and PA */
151261855Sandrew	adr	r0, Lpagetable
152271232Sandrew	bl	translate_va_to_pa
153261855Sandrew
154266849Scognet#ifndef _ARM_ARCH_6
155261606Sandrew	/*
156266849Scognet	 * Some of the older ports (the various XScale, mostly) assume
157266849Scognet	 * that the memory before the kernel is mapped, and use it for
158266849Scognet	 * the various stacks, page tables, etc. For those CPUs, map the
159266849Scognet	 * 64 first MB of RAM, as it used to be.
160266849Scognet	 */
161266849Scognet	/*
162261606Sandrew	 * Map PA == VA
163266849Scognet	 */
164266849Scognet	ldr     r5, =PHYSADDR
165266849Scognet	mov     r1, r5
166266849Scognet	mov     r2, r5
167266849Scognet	/* Map 64MiB, preserved over calls to build_pagetables */
168266849Scognet	mov     r3, #64
169266849Scognet	bl      build_pagetables
170266849Scognet
171266849Scognet	/* Create the kernel map to jump to */
172266849Scognet	mov     r1, r5
173266849Scognet	ldr     r2, =(KERNBASE)
174266849Scognet	bl      build_pagetables
175266849Scognet	ldr	r5, =(KERNPHYSADDR)
176266849Scognet#else
177266849Scognet	/*
178266849Scognet	 * Map PA == VA
179266849Scognet	 */
180261855Sandrew	/* Find the start kernels load address */
181261855Sandrew	adr	r5, _start
182261855Sandrew	ldr	r2, =(L1_S_OFFSET)
183261855Sandrew	bic	r5, r2
184261606Sandrew	mov	r1, r5
185261606Sandrew	mov	r2, r5
186261606Sandrew	/* Map 64MiB, preserved over calls to build_pagetables */
187261606Sandrew	mov	r3, #64
188261606Sandrew	bl	build_pagetables
189129198Scognet
190261606Sandrew	/* Create the kernel map to jump to */
191261606Sandrew	mov	r1, r5
192261855Sandrew	ldr	r2, =(KERNVIRTADDR)
193261606Sandrew	bl	build_pagetables
194266849Scognet#endif
195261606Sandrew
196261606Sandrew#if defined(SOCDEV_PA) && defined(SOCDEV_VA)
197261606Sandrew	/* Create the custom map */
198261783Simp	ldr	r1, =SOCDEV_PA
199261783Simp	ldr	r2, =SOCDEV_VA
200261606Sandrew	bl	build_pagetables
201261606Sandrew#endif
202129198Scognet
203239268Sgonzo#if defined(SMP)
204239268Sgonzo	orr 	r0, r0, #2		/* Set TTB shared memory flag */
205239268Sgonzo#endif
206129198Scognet	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
207129198Scognet	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
208129198Scognet
209259640Sganbold#if defined(CPU_ARM1136) || defined(CPU_ARM1176) || defined(CPU_CORTEXA) || defined(CPU_MV_PJ4B) || defined(CPU_KRAIT)
210239268Sgonzo	mov	r0, #0
211239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
212239268Sgonzo#endif
213239268Sgonzo
214129198Scognet	/* Set the Domain Access register.  Very important! */
215143681Sjmg	mov     r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
216129198Scognet	mcr	p15, 0, r0, c3, c0, 0
217248961Sian	/*
218248961Sian	 * Enable MMU.
219248961Sian	 * On armv6 enable extended page tables, and set alignment checking
220248961Sian	 * to modulo-4 (CPU_CONTROL_UNAL_ENABLE) for the ldrd/strd
221248961Sian	 * instructions emitted by clang.
222248961Sian	 */
223129198Scognet	mrc	p15, 0, r0, c1, c0, 0
224248961Sian#ifdef _ARM_ARCH_6
225248961Sian	orr	r0, r0, #(CPU_CONTROL_V6_EXTPAGE | CPU_CONTROL_UNAL_ENABLE)
226256628Sian	orr	r0, r0, #(CPU_CONTROL_AFLT_ENABLE)
227250928Sgber	orr	r0, r0, #(CPU_CONTROL_AF_ENABLE)
228239268Sgonzo#endif
229243602Sgonzo	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE)
230129198Scognet	mcr	p15, 0, r0, c1, c0, 0
231153550Scognet	nop
232153550Scognet	nop
233153550Scognet	nop
234129198Scognet	CPWAIT(r0)
235129198Scognet
236129198Scognetmmu_done:
237153550Scognet	nop
238129198Scognet	adr	r1, .Lstart
239129198Scognet	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
240129198Scognet	sub	r2, r2, r1		/* get zero init data */
241129198Scognet	mov	r3, #0
242129198Scognet.L1:
243150863Scognet	str	r3, [r1], #0x0004	/* get zero init data */
244129198Scognet	subs	r2, r2, #4
245129198Scognet	bgt	.L1
246153550Scognet	ldr	pc, .Lvirt_done
247129198Scognet
248142145Scognetvirt_done:
249261663Sandrew	mov	r1, #28			/* loader info size is 28 bytes also second arg */
250236524Simp	subs	sp, sp, r1		/* allocate arm_boot_params struct on stack */
251261855Sandrew	mov	r0, sp			/* loader info pointer is first arg */
252247608Sandrew	bic	sp, sp, #7		/* align stack to 8 bytes */
253236524Simp	str	r1, [r0]		/* Store length of loader info */
254236524Simp	str	r9, [r0, #4]		/* Store r0 from boot loader */
255236524Simp	str	r8, [r0, #8]		/* Store r1 from boot loader */
256236524Simp	str	ip, [r0, #12]		/* store r2 from boot loader */
257236524Simp	str	fp, [r0, #16]		/* store r3 from boot loader */
258261562Sandrew	str	r5, [r0, #20]		/* store the physical address */
259261855Sandrew	adr	r4, Lpagetable		/* load the pagetable address */
260261855Sandrew	ldr	r5, [r4, #4]
261261663Sandrew	str	r5, [r0, #24]		/* store the pagetable address */
262175983Sraj	mov	fp, #0			/* trace back starts here */
263129198Scognet	bl	_C_LABEL(initarm)	/* Off we go */
264129198Scognet
265129198Scognet	/* init arm will return the new stack pointer. */
266129198Scognet	mov	sp, r0
267129198Scognet
268129198Scognet	bl	_C_LABEL(mi_startup)		/* call mi_startup()! */
269129198Scognet
270129198Scognet	adr	r0, .Lmainreturned
271130164Sphk	b	_C_LABEL(panic)
272175983Sraj	/* NOTREACHED */
273261606SandrewEND(_start)
274261606Sandrew
275271232Sandrew#define VA_TO_PA_POINTER(name, table)	 \
276271232Sandrewname:					;\
277271232Sandrew	.word	.			;\
278271232Sandrew	.word	table
279271232Sandrew
280261606Sandrew/*
281271232Sandrew * Returns the physical address of a magic va to pa pointer.
282271232Sandrew * r0     - The pagetable data pointer. This must be built using the
283271232Sandrew *          VA_TO_PA_POINTER macro.
284271232Sandrew *          e.g.
285271232Sandrew *            VA_TO_PA_POINTER(Lpagetable, pagetable)
286271232Sandrew *            ...
287271232Sandrew *            adr  r0, Lpagetable
288271232Sandrew *            bl   translate_va_to_pa
289271232Sandrew *            r0 will now contain the physical address of pagetable
290271232Sandrew * r1, r2 - Trashed
291271232Sandrew */
292271232Sandrewtranslate_va_to_pa:
293271232Sandrew	ldr	r1, [r0]
294271232Sandrew	sub	r2, r1, r0
295271232Sandrew	/* At this point: r2 = VA - PA */
296271232Sandrew
297271232Sandrew	/*
298271232Sandrew	 * Find the physical address of the table. After these two
299271232Sandrew	 * instructions:
300271232Sandrew	 * r1 = va(pagetable)
301271232Sandrew	 *
302271232Sandrew	 * r0 = va(pagetable) - (VA - PA)
303271232Sandrew	 *    = va(pagetable) - VA + PA
304271232Sandrew	 *    = pa(pagetable)
305271232Sandrew	 */
306271232Sandrew	ldr	r1, [r0, #4]
307271232Sandrew	sub	r0, r1, r2
308271232Sandrew	RET
309271232Sandrew
310271232Sandrew/*
311261606Sandrew * Builds the page table
312261606Sandrew * r0 - The table base address
313261606Sandrew * r1 - The physical address (trashed)
314261606Sandrew * r2 - The virtual address (trashed)
315261606Sandrew * r3 - The number of 1MiB sections
316261606Sandrew * r4 - Trashed
317261606Sandrew *
318261606Sandrew * Addresses must be 1MiB aligned
319261606Sandrew */
320261606Sandrewbuild_pagetables:
321261606Sandrew	/* Set the required page attributed */
322261606Sandrew	ldr	r4, =(L1_TYPE_S|L1_S_C|L1_S_AP(AP_KRW))
323261606Sandrew#if defined(SMP)
324261606Sandrew	orr	r4, #(L1_SHARED)
325261606Sandrew#endif
326261606Sandrew	orr	r1, r4
327261606Sandrew
328261606Sandrew	/* Move the virtual address to the correct bit location */
329261606Sandrew	lsr	r2, #(L1_S_SHIFT - 2)
330261606Sandrew
331261606Sandrew	mov	r4, r3
332261606Sandrew1:
333261606Sandrew	str	r1, [r0, r2]
334261606Sandrew	add	r2, r2, #4
335261606Sandrew	add	r1, r1, #(L1_S_SIZE)
336261606Sandrew	adds	r4, r4, #-1
337261606Sandrew	bhi	1b
338261606Sandrew
339261606Sandrew	RET
340261606Sandrew
341271232SandrewVA_TO_PA_POINTER(Lpagetable, pagetable)
342261855Sandrew
343166819ScognetLreal_start:
344166819Scognet	.word	_start
345261855SandrewLend:
346166819Scognet	.word	_edata
347261855Sandrew
348129198Scognet.Lstart:
349129198Scognet	.word	_edata
350261227Sandrew	.word	_ebss
351129198Scognet	.word	svcstk + INIT_ARM_STACK_SIZE
352129198Scognet
353153550Scognet.Lvirt_done:
354153550Scognet	.word	virt_done
355239268Sgonzo
356129198Scognet.Lmainreturned:
357129198Scognet	.asciz	"main() returned"
358129198Scognet	.align	0
359129198Scognet
360129198Scognet	.bss
361129198Scognetsvcstk:
362129198Scognet	.space	INIT_ARM_STACK_SIZE
363129198Scognet
364261227Sandrew/*
365261227Sandrew * Memory for the initial pagetable. We are unable to place this in
366261227Sandrew * the bss as this will be cleared after the table is loaded.
367261227Sandrew */
368261227Sandrew	.section ".init_pagetable"
369261227Sandrew	.align	14 /* 16KiB aligned */
370261227Sandrewpagetable:
371261227Sandrew	.space	L1_TABLE_SIZE
372261227Sandrew
373129198Scognet	.text
374129198Scognet	.align	0
375129198Scognet
376143681Sjmg.Lcpufuncs:
377129198Scognet	.word	_C_LABEL(cpufuncs)
378129198Scognet
379239268Sgonzo#if defined(SMP)
380239268Sgonzo
381265705Sian.Lmpvirt_done:
382265705Sian	.word	mpvirt_done
383271232SandrewVA_TO_PA_POINTER(Lstartup_pagetable_secondary, temp_pagetable)
384265705Sian
385239268SgonzoASENTRY_NP(mpentry)
386239268Sgonzo
387239268Sgonzo	/* Make sure interrupts are disabled. */
388239268Sgonzo	mrs	r7, cpsr
389239268Sgonzo	orr	r7, r7, #(I32_bit|F32_bit)
390239268Sgonzo	msr	cpsr_c, r7
391239268Sgonzo
392265784Sian	/* Disable MMU.  It should be disabled already, but make sure. */
393239268Sgonzo	mrc	p15, 0, r2, c1, c0, 0
394239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
395239268Sgonzo	    CPU_CONTROL_WBUF_ENABLE)
396239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_IC_ENABLE)
397239268Sgonzo	bic	r2, r2, #(CPU_CONTROL_BPRD_ENABLE)
398239268Sgonzo	mcr	p15, 0, r2, c1, c0, 0
399239268Sgonzo	nop
400239268Sgonzo	nop
401239268Sgonzo	nop
402265784Sian	CPWAIT(r0)
403239268Sgonzo
404270862Sian#if ARM_MMU_V6
405265784Sian	bl	armv6_idcache_inv_all	/* Modifies r0 only */
406270862Sian#elif ARM_MMU_V7
407265784Sian	bl	armv7_idcache_inv_all	/* Modifies r0-r3, ip */
408265784Sian#endif
409265784Sian
410271232Sandrew	/* Load the page table physical address */
411271232Sandrew	adr	r0, Lstartup_pagetable_secondary
412271232Sandrew	bl	translate_va_to_pa
413271232Sandrew	/* Load the address the secondary page table */
414239268Sgonzo	ldr	r0, [r0]
415271232Sandrew
416262413Sian	orr 	r0, r0, #2		/* Set TTB shared memory flag */
417239268Sgonzo	mcr	p15, 0, r0, c2, c0, 0	/* Set TTB */
418239268Sgonzo	mcr	p15, 0, r0, c8, c7, 0	/* Flush TLB */
419239268Sgonzo
420239268Sgonzo	mov	r0, #0
421239268Sgonzo	mcr	p15, 0, r0, c13, c0, 1	/* Set ASID to 0 */
422239268Sgonzo
423239268Sgonzo	/* Set the Domain Access register.  Very important! */
424239268Sgonzo	mov	r0, #((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT)
425239268Sgonzo	mcr	p15, 0, r0, c3, c0, 0
426239268Sgonzo	/* Enable MMU */
427239268Sgonzo	mrc	p15, 0, r0, c1, c0, 0
428239268Sgonzo	orr	r0, r0, #CPU_CONTROL_V6_EXTPAGE
429258845Szbb	orr	r0, r0, #CPU_CONTROL_AF_ENABLE
430265784Sian	orr	r0, r0, #(CPU_CONTROL_MMU_ENABLE | CPU_CONTROL_DC_ENABLE |\
431265784Sian	    CPU_CONTROL_WBUF_ENABLE)
432265784Sian	orr	r0, r0, #(CPU_CONTROL_IC_ENABLE)
433265784Sian	orr	r0, r0, #(CPU_CONTROL_BPRD_ENABLE)
434239268Sgonzo	mcr	p15, 0, r0, c1, c0, 0
435239268Sgonzo	nop
436239268Sgonzo	nop
437239268Sgonzo	nop
438239268Sgonzo	CPWAIT(r0)
439239268Sgonzo
440239268Sgonzo	adr	r1, .Lstart
441239268Sgonzo	ldmia	r1, {r1, r2, sp}	/* Set initial stack and */
442239268Sgonzo	mrc	p15, 0, r0, c0, c0, 5
443239268Sgonzo	and	r0, r0, #15
444239268Sgonzo	mov	r1, #2048
445239268Sgonzo	mul	r2, r1, r0
446239268Sgonzo	sub	sp, sp, r2
447239268Sgonzo	str	r1, [sp]
448239268Sgonzo	ldr	pc, .Lmpvirt_done
449239268Sgonzo
450239268Sgonzompvirt_done:
451239268Sgonzo
452239268Sgonzo	mov	fp, #0			/* trace back starts here */
453239268Sgonzo	bl	_C_LABEL(init_secondary)	/* Off we go */
454239268Sgonzo
455239268Sgonzo	adr	r0, .Lmpreturned
456239268Sgonzo	b	_C_LABEL(panic)
457239268Sgonzo	/* NOTREACHED */
458239268Sgonzo
459239268Sgonzo.Lmpreturned:
460265705Sian	.asciz	"init_secondary() returned"
461239268Sgonzo	.align	0
462248361SandrewEND(mpentry)
463239268Sgonzo#endif
464239268Sgonzo
465135640ScognetENTRY_NP(cpu_halt)
466129198Scognet	mrs     r2, cpsr
467129198Scognet	bic	r2, r2, #(PSR_MODE)
468129198Scognet	orr     r2, r2, #(PSR_SVC32_MODE)
469129198Scognet	orr	r2, r2, #(I32_bit | F32_bit)
470261393Sian	msr     cpsr_fsxc, r2
471129198Scognet
472129198Scognet	ldr	r4, .Lcpu_reset_address
473129198Scognet	ldr	r4, [r4]
474129198Scognet
475129198Scognet	ldr	r0, .Lcpufuncs
476129198Scognet	mov	lr, pc
477129198Scognet	ldr	pc, [r0, #CF_IDCACHE_WBINV_ALL]
478183839Sraj	mov	lr, pc
479183839Sraj	ldr	pc, [r0, #CF_L2CACHE_WBINV_ALL]
480129198Scognet
481129198Scognet	/*
482129198Scognet	 * Load the cpu_reset_needs_v4_MMU_disable flag to determine if it's
483129198Scognet	 * necessary.
484129198Scognet	 */
485129198Scognet
486129198Scognet	ldr	r1, .Lcpu_reset_needs_v4_MMU_disable
487129198Scognet	ldr	r1, [r1]
488129198Scognet	cmp	r1, #0
489129198Scognet	mov	r2, #0
490129198Scognet
491129198Scognet	/*
492175983Sraj	 * MMU & IDC off, 32 bit program & data space
493129198Scognet	 * Hurl ourselves into the ROM
494129198Scognet	 */
495129198Scognet	mov	r0, #(CPU_CONTROL_32BP_ENABLE | CPU_CONTROL_32BD_ENABLE)
496129198Scognet	mcr     15, 0, r0, c1, c0, 0
497129198Scognet	mcrne   15, 0, r2, c8, c7, 0 	/* nail I+D TLB on ARMv4 and greater */
498129198Scognet	mov     pc, r4
499129198Scognet
500129198Scognet	/*
501129198Scognet	 * _cpu_reset_address contains the address to branch to, to complete
502129198Scognet	 * the cpu reset after turning the MMU off
503129198Scognet	 * This variable is provided by the hardware specific code
504129198Scognet	 */
505129198Scognet.Lcpu_reset_address:
506129198Scognet	.word	_C_LABEL(cpu_reset_address)
507129198Scognet
508129198Scognet	/*
509129198Scognet	 * cpu_reset_needs_v4_MMU_disable contains a flag that signals if the
510129198Scognet	 * v4 MMU disable instruction needs executing... it is an illegal instruction
511129198Scognet	 * on f.e. ARM6/7 that locks up the computer in an endless illegal
512129198Scognet	 * instruction / data-abort / reset loop.
513129198Scognet	 */
514129198Scognet.Lcpu_reset_needs_v4_MMU_disable:
515129198Scognet	.word	_C_LABEL(cpu_reset_needs_v4_MMU_disable)
516248361SandrewEND(cpu_halt)
517129198Scognet
518129198Scognet
519129198Scognet/*
520129198Scognet * setjump + longjmp
521129198Scognet */
522129198ScognetENTRY(setjmp)
523129198Scognet	stmia	r0, {r4-r14}
524129198Scognet	mov	r0, #0x00000000
525137463Scognet	RET
526248361SandrewEND(setjmp)
527129198Scognet
528129198ScognetENTRY(longjmp)
529129198Scognet	ldmia	r0, {r4-r14}
530129198Scognet	mov	r0, #0x00000001
531137463Scognet	RET
532248361SandrewEND(longjmp)
533129198Scognet
534129198Scognet	.data
535129198Scognet	.global _C_LABEL(esym)
536129198Scognet_C_LABEL(esym):	.word	_C_LABEL(end)
537129198Scognet
538129198ScognetENTRY_NP(abort)
539129198Scognet	b	_C_LABEL(abort)
540248361SandrewEND(abort)
541129198Scognet
542135640ScognetENTRY_NP(sigcode)
543135640Scognet	mov	r0, sp
544262903Sian	add	r0, r0, #SIGF_UC
545245414Sandrew
546245414Sandrew	/*
547245414Sandrew	 * Call the sigreturn system call.
548245414Sandrew	 *
549245414Sandrew	 * We have to load r7 manually rather than using
550245414Sandrew	 * "ldr r7, =SYS_sigreturn" to ensure the value of szsigcode is
551245414Sandrew	 * correct. Using the alternative places esigcode at the address
552245414Sandrew	 * of the data rather than the address one past the data.
553245414Sandrew	 */
554245414Sandrew
555245414Sandrew	ldr	r7, [pc, #12]	/* Load SYS_sigreturn */
556135640Scognet	swi	SYS_sigreturn
557135640Scognet
558135640Scognet	/* Well if that failed we better exit quick ! */
559135640Scognet
560245414Sandrew	ldr	r7, [pc, #8]	/* Load SYS_exit */
561135640Scognet	swi	SYS_exit
562135640Scognet
563245414Sandrew	/* Branch back to retry SYS_sigreturn */
564245414Sandrew	b	. - 16
565269390SianEND(sigcode)
566245414Sandrew	.word	SYS_sigreturn
567245414Sandrew	.word	SYS_exit
568245414Sandrew
569135640Scognet	.align	0
570135640Scognet	.global _C_LABEL(esigcode)
571135640Scognet		_C_LABEL(esigcode):
572143681Sjmg
573135640Scognet	.data
574135640Scognet	.global szsigcode
575135640Scognetszsigcode:
576135640Scognet	.long esigcode-sigcode
577269390Sian
578129198Scognet/* End of locore.S */
579