xref: /openbmc/linux/arch/arm/kernel/entry-armv.S (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds/*
2*1da177e4SLinus Torvalds *  linux/arch/arm/kernel/entry-armv.S
3*1da177e4SLinus Torvalds *
4*1da177e4SLinus Torvalds *  Copyright (C) 1996,1997,1998 Russell King.
5*1da177e4SLinus Torvalds *  ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk)
6*1da177e4SLinus Torvalds *
7*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify
8*1da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as
9*1da177e4SLinus Torvalds * published by the Free Software Foundation.
10*1da177e4SLinus Torvalds *
11*1da177e4SLinus Torvalds *  Low-level vector interface routines
12*1da177e4SLinus Torvalds *
13*1da177e4SLinus Torvalds *  Note:  there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes
14*1da177e4SLinus Torvalds *  it to save wrong values...  Be aware!
15*1da177e4SLinus Torvalds */
16*1da177e4SLinus Torvalds#include <linux/config.h>
17*1da177e4SLinus Torvalds#include <linux/init.h>
18*1da177e4SLinus Torvalds
19*1da177e4SLinus Torvalds#include <asm/thread_info.h>
20*1da177e4SLinus Torvalds#include <asm/glue.h>
21*1da177e4SLinus Torvalds#include <asm/ptrace.h>
22*1da177e4SLinus Torvalds#include <asm/vfpmacros.h>
23*1da177e4SLinus Torvalds
24*1da177e4SLinus Torvalds#include "entry-header.S"
25*1da177e4SLinus Torvalds
26*1da177e4SLinus Torvalds/*
27*1da177e4SLinus Torvalds * Invalid mode handlers
28*1da177e4SLinus Torvalds */
29*1da177e4SLinus Torvalds	.macro	inv_entry, sym, reason
30*1da177e4SLinus Torvalds	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
31*1da177e4SLinus Torvalds	stmia	sp, {r0 - lr}			@ Save XXX r0 - lr
32*1da177e4SLinus Torvalds	ldr	r4, .LC\sym
33*1da177e4SLinus Torvalds	mov	r1, #\reason
34*1da177e4SLinus Torvalds	.endm
35*1da177e4SLinus Torvalds
36*1da177e4SLinus Torvalds__pabt_invalid:
37*1da177e4SLinus Torvalds	inv_entry abt, BAD_PREFETCH
38*1da177e4SLinus Torvalds	b	1f
39*1da177e4SLinus Torvalds
40*1da177e4SLinus Torvalds__dabt_invalid:
41*1da177e4SLinus Torvalds	inv_entry abt, BAD_DATA
42*1da177e4SLinus Torvalds	b	1f
43*1da177e4SLinus Torvalds
44*1da177e4SLinus Torvalds__irq_invalid:
45*1da177e4SLinus Torvalds	inv_entry irq, BAD_IRQ
46*1da177e4SLinus Torvalds	b	1f
47*1da177e4SLinus Torvalds
48*1da177e4SLinus Torvalds__und_invalid:
49*1da177e4SLinus Torvalds	inv_entry und, BAD_UNDEFINSTR
50*1da177e4SLinus Torvalds
51*1da177e4SLinus Torvalds1:	zero_fp
52*1da177e4SLinus Torvalds	ldmia	r4, {r5 - r7}			@ Get XXX pc, cpsr, old_r0
53*1da177e4SLinus Torvalds	add	r4, sp, #S_PC
54*1da177e4SLinus Torvalds	stmia	r4, {r5 - r7}			@ Save XXX pc, cpsr, old_r0
55*1da177e4SLinus Torvalds	mov	r0, sp
56*1da177e4SLinus Torvalds	and	r2, r6, #31			@ int mode
57*1da177e4SLinus Torvalds	b	bad_mode
58*1da177e4SLinus Torvalds
59*1da177e4SLinus Torvalds/*
60*1da177e4SLinus Torvalds * SVC mode handlers
61*1da177e4SLinus Torvalds */
62*1da177e4SLinus Torvalds	.macro	svc_entry, sym
63*1da177e4SLinus Torvalds	sub	sp, sp, #S_FRAME_SIZE
64*1da177e4SLinus Torvalds	stmia	sp, {r0 - r12}			@ save r0 - r12
65*1da177e4SLinus Torvalds	ldr	r2, .LC\sym
66*1da177e4SLinus Torvalds	add	r0, sp, #S_FRAME_SIZE
67*1da177e4SLinus Torvalds	ldmia	r2, {r2 - r4}			@ get pc, cpsr
68*1da177e4SLinus Torvalds	add	r5, sp, #S_SP
69*1da177e4SLinus Torvalds	mov	r1, lr
70*1da177e4SLinus Torvalds
71*1da177e4SLinus Torvalds	@
72*1da177e4SLinus Torvalds	@ We are now ready to fill in the remaining blanks on the stack:
73*1da177e4SLinus Torvalds	@
74*1da177e4SLinus Torvalds	@  r0 - sp_svc
75*1da177e4SLinus Torvalds	@  r1 - lr_svc
76*1da177e4SLinus Torvalds	@  r2 - lr_<exception>, already fixed up for correct return/restart
77*1da177e4SLinus Torvalds	@  r3 - spsr_<exception>
78*1da177e4SLinus Torvalds	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
79*1da177e4SLinus Torvalds	@
80*1da177e4SLinus Torvalds	stmia	r5, {r0 - r4}
81*1da177e4SLinus Torvalds	.endm
82*1da177e4SLinus Torvalds
83*1da177e4SLinus Torvalds	.align	5
84*1da177e4SLinus Torvalds__dabt_svc:
85*1da177e4SLinus Torvalds	svc_entry abt
86*1da177e4SLinus Torvalds
87*1da177e4SLinus Torvalds	@
88*1da177e4SLinus Torvalds	@ get ready to re-enable interrupts if appropriate
89*1da177e4SLinus Torvalds	@
90*1da177e4SLinus Torvalds	mrs	r9, cpsr
91*1da177e4SLinus Torvalds	tst	r3, #PSR_I_BIT
92*1da177e4SLinus Torvalds	biceq	r9, r9, #PSR_I_BIT
93*1da177e4SLinus Torvalds
94*1da177e4SLinus Torvalds	@
95*1da177e4SLinus Torvalds	@ Call the processor-specific abort handler:
96*1da177e4SLinus Torvalds	@
97*1da177e4SLinus Torvalds	@  r2 - aborted context pc
98*1da177e4SLinus Torvalds	@  r3 - aborted context cpsr
99*1da177e4SLinus Torvalds	@
100*1da177e4SLinus Torvalds	@ The abort handler must return the aborted address in r0, and
101*1da177e4SLinus Torvalds	@ the fault status register in r1.  r9 must be preserved.
102*1da177e4SLinus Torvalds	@
103*1da177e4SLinus Torvalds#ifdef MULTI_ABORT
104*1da177e4SLinus Torvalds	ldr	r4, .LCprocfns
105*1da177e4SLinus Torvalds	mov	lr, pc
106*1da177e4SLinus Torvalds	ldr	pc, [r4]
107*1da177e4SLinus Torvalds#else
108*1da177e4SLinus Torvalds	bl	CPU_ABORT_HANDLER
109*1da177e4SLinus Torvalds#endif
110*1da177e4SLinus Torvalds
111*1da177e4SLinus Torvalds	@
112*1da177e4SLinus Torvalds	@ set desired IRQ state, then call main handler
113*1da177e4SLinus Torvalds	@
114*1da177e4SLinus Torvalds	msr	cpsr_c, r9
115*1da177e4SLinus Torvalds	mov	r2, sp
116*1da177e4SLinus Torvalds	bl	do_DataAbort
117*1da177e4SLinus Torvalds
118*1da177e4SLinus Torvalds	@
119*1da177e4SLinus Torvalds	@ IRQs off again before pulling preserved data off the stack
120*1da177e4SLinus Torvalds	@
121*1da177e4SLinus Torvalds	disable_irq r0
122*1da177e4SLinus Torvalds
123*1da177e4SLinus Torvalds	@
124*1da177e4SLinus Torvalds	@ restore SPSR and restart the instruction
125*1da177e4SLinus Torvalds	@
126*1da177e4SLinus Torvalds	ldr	r0, [sp, #S_PSR]
127*1da177e4SLinus Torvalds	msr	spsr_cxsf, r0
128*1da177e4SLinus Torvalds	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
129*1da177e4SLinus Torvalds
130*1da177e4SLinus Torvalds	.align	5
131*1da177e4SLinus Torvalds__irq_svc:
132*1da177e4SLinus Torvalds	svc_entry irq
133*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
134*1da177e4SLinus Torvalds	get_thread_info r8
135*1da177e4SLinus Torvalds	ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
136*1da177e4SLinus Torvalds	add	r7, r9, #1			@ increment it
137*1da177e4SLinus Torvalds	str	r7, [r8, #TI_PREEMPT]
138*1da177e4SLinus Torvalds#endif
139*1da177e4SLinus Torvalds1:	get_irqnr_and_base r0, r6, r5, lr
140*1da177e4SLinus Torvalds	movne	r1, sp
141*1da177e4SLinus Torvalds	@
142*1da177e4SLinus Torvalds	@ routine called with r0 = irq number, r1 = struct pt_regs *
143*1da177e4SLinus Torvalds	@
144*1da177e4SLinus Torvalds	adrne	lr, 1b
145*1da177e4SLinus Torvalds	bne	asm_do_IRQ
146*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
147*1da177e4SLinus Torvalds	ldr	r0, [r8, #TI_FLAGS]		@ get flags
148*1da177e4SLinus Torvalds	tst	r0, #_TIF_NEED_RESCHED
149*1da177e4SLinus Torvalds	blne	svc_preempt
150*1da177e4SLinus Torvaldspreempt_return:
151*1da177e4SLinus Torvalds	ldr	r0, [r8, #TI_PREEMPT]		@ read preempt value
152*1da177e4SLinus Torvalds	teq	r0, r7
153*1da177e4SLinus Torvalds	str	r9, [r8, #TI_PREEMPT]		@ restore preempt count
154*1da177e4SLinus Torvalds	strne	r0, [r0, -r0]			@ bug()
155*1da177e4SLinus Torvalds#endif
156*1da177e4SLinus Torvalds	ldr	r0, [sp, #S_PSR]		@ irqs are already disabled
157*1da177e4SLinus Torvalds	msr	spsr_cxsf, r0
158*1da177e4SLinus Torvalds	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
159*1da177e4SLinus Torvalds
160*1da177e4SLinus Torvalds	.ltorg
161*1da177e4SLinus Torvalds
162*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
163*1da177e4SLinus Torvaldssvc_preempt:
164*1da177e4SLinus Torvalds	teq	r9, #0				@ was preempt count = 0
165*1da177e4SLinus Torvalds	ldreq	r6, .LCirq_stat
166*1da177e4SLinus Torvalds	movne	pc, lr				@ no
167*1da177e4SLinus Torvalds	ldr	r0, [r6, #4]			@ local_irq_count
168*1da177e4SLinus Torvalds	ldr	r1, [r6, #8]			@ local_bh_count
169*1da177e4SLinus Torvalds	adds	r0, r0, r1
170*1da177e4SLinus Torvalds	movne	pc, lr
171*1da177e4SLinus Torvalds	mov	r7, #0				@ preempt_schedule_irq
172*1da177e4SLinus Torvalds	str	r7, [r8, #TI_PREEMPT]		@ expects preempt_count == 0
173*1da177e4SLinus Torvalds1:	bl	preempt_schedule_irq		@ irq en/disable is done inside
174*1da177e4SLinus Torvalds	ldr	r0, [r8, #TI_FLAGS]		@ get new tasks TI_FLAGS
175*1da177e4SLinus Torvalds	tst	r0, #_TIF_NEED_RESCHED
176*1da177e4SLinus Torvalds	beq	preempt_return			@ go again
177*1da177e4SLinus Torvalds	b	1b
178*1da177e4SLinus Torvalds#endif
179*1da177e4SLinus Torvalds
180*1da177e4SLinus Torvalds	.align	5
181*1da177e4SLinus Torvalds__und_svc:
182*1da177e4SLinus Torvalds	svc_entry und
183*1da177e4SLinus Torvalds
184*1da177e4SLinus Torvalds	@
185*1da177e4SLinus Torvalds	@ call emulation code, which returns using r9 if it has emulated
186*1da177e4SLinus Torvalds	@ the instruction, or the more conventional lr if we are to treat
187*1da177e4SLinus Torvalds	@ this as a real undefined instruction
188*1da177e4SLinus Torvalds	@
189*1da177e4SLinus Torvalds	@  r0 - instruction
190*1da177e4SLinus Torvalds	@
191*1da177e4SLinus Torvalds	ldr	r0, [r2, #-4]
192*1da177e4SLinus Torvalds	adr	r9, 1f
193*1da177e4SLinus Torvalds	bl	call_fpe
194*1da177e4SLinus Torvalds
195*1da177e4SLinus Torvalds	mov	r0, sp				@ struct pt_regs *regs
196*1da177e4SLinus Torvalds	bl	do_undefinstr
197*1da177e4SLinus Torvalds
198*1da177e4SLinus Torvalds	@
199*1da177e4SLinus Torvalds	@ IRQs off again before pulling preserved data off the stack
200*1da177e4SLinus Torvalds	@
201*1da177e4SLinus Torvalds1:	disable_irq r0
202*1da177e4SLinus Torvalds
203*1da177e4SLinus Torvalds	@
204*1da177e4SLinus Torvalds	@ restore SPSR and restart the instruction
205*1da177e4SLinus Torvalds	@
206*1da177e4SLinus Torvalds	ldr	lr, [sp, #S_PSR]		@ Get SVC cpsr
207*1da177e4SLinus Torvalds	msr	spsr_cxsf, lr
208*1da177e4SLinus Torvalds	ldmia	sp, {r0 - pc}^			@ Restore SVC registers
209*1da177e4SLinus Torvalds
210*1da177e4SLinus Torvalds	.align	5
211*1da177e4SLinus Torvalds__pabt_svc:
212*1da177e4SLinus Torvalds	svc_entry abt
213*1da177e4SLinus Torvalds
214*1da177e4SLinus Torvalds	@
215*1da177e4SLinus Torvalds	@ re-enable interrupts if appropriate
216*1da177e4SLinus Torvalds	@
217*1da177e4SLinus Torvalds	mrs	r9, cpsr
218*1da177e4SLinus Torvalds	tst	r3, #PSR_I_BIT
219*1da177e4SLinus Torvalds	biceq	r9, r9, #PSR_I_BIT
220*1da177e4SLinus Torvalds	msr	cpsr_c, r9
221*1da177e4SLinus Torvalds
222*1da177e4SLinus Torvalds	@
223*1da177e4SLinus Torvalds	@ set args, then call main handler
224*1da177e4SLinus Torvalds	@
225*1da177e4SLinus Torvalds	@  r0 - address of faulting instruction
226*1da177e4SLinus Torvalds	@  r1 - pointer to registers on stack
227*1da177e4SLinus Torvalds	@
228*1da177e4SLinus Torvalds	mov	r0, r2				@ address (pc)
229*1da177e4SLinus Torvalds	mov	r1, sp				@ regs
230*1da177e4SLinus Torvalds	bl	do_PrefetchAbort		@ call abort handler
231*1da177e4SLinus Torvalds
232*1da177e4SLinus Torvalds	@
233*1da177e4SLinus Torvalds	@ IRQs off again before pulling preserved data off the stack
234*1da177e4SLinus Torvalds	@
235*1da177e4SLinus Torvalds	disable_irq r0
236*1da177e4SLinus Torvalds
237*1da177e4SLinus Torvalds	@
238*1da177e4SLinus Torvalds	@ restore SPSR and restart the instruction
239*1da177e4SLinus Torvalds	@
240*1da177e4SLinus Torvalds	ldr	r0, [sp, #S_PSR]
241*1da177e4SLinus Torvalds	msr	spsr_cxsf, r0
242*1da177e4SLinus Torvalds	ldmia	sp, {r0 - pc}^			@ load r0 - pc, cpsr
243*1da177e4SLinus Torvalds
244*1da177e4SLinus Torvalds	.align	5
245*1da177e4SLinus Torvalds.LCirq:
246*1da177e4SLinus Torvalds	.word	__temp_irq
247*1da177e4SLinus Torvalds.LCund:
248*1da177e4SLinus Torvalds	.word	__temp_und
249*1da177e4SLinus Torvalds.LCabt:
250*1da177e4SLinus Torvalds	.word	__temp_abt
251*1da177e4SLinus Torvalds#ifdef MULTI_ABORT
252*1da177e4SLinus Torvalds.LCprocfns:
253*1da177e4SLinus Torvalds	.word	processor
254*1da177e4SLinus Torvalds#endif
255*1da177e4SLinus Torvalds.LCfp:
256*1da177e4SLinus Torvalds	.word	fp_enter
257*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
258*1da177e4SLinus Torvalds.LCirq_stat:
259*1da177e4SLinus Torvalds	.word	irq_stat
260*1da177e4SLinus Torvalds#endif
261*1da177e4SLinus Torvalds
262*1da177e4SLinus Torvalds/*
263*1da177e4SLinus Torvalds * User mode handlers
264*1da177e4SLinus Torvalds */
265*1da177e4SLinus Torvalds	.macro	usr_entry, sym
266*1da177e4SLinus Torvalds	sub	sp, sp, #S_FRAME_SIZE		@ Allocate frame size in one go
267*1da177e4SLinus Torvalds	stmia	sp, {r0 - r12}			@ save r0 - r12
268*1da177e4SLinus Torvalds	ldr	r7, .LC\sym
269*1da177e4SLinus Torvalds	add	r5, sp, #S_PC
270*1da177e4SLinus Torvalds	ldmia	r7, {r2 - r4}			@ Get USR pc, cpsr
271*1da177e4SLinus Torvalds
272*1da177e4SLinus Torvalds	@
273*1da177e4SLinus Torvalds	@ We are now ready to fill in the remaining blanks on the stack:
274*1da177e4SLinus Torvalds	@
275*1da177e4SLinus Torvalds	@  r2 - lr_<exception>, already fixed up for correct return/restart
276*1da177e4SLinus Torvalds	@  r3 - spsr_<exception>
277*1da177e4SLinus Torvalds	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
278*1da177e4SLinus Torvalds	@
279*1da177e4SLinus Torvalds	@ Also, separately save sp_usr and lr_usr
280*1da177e4SLinus Torvalds	@
281*1da177e4SLinus Torvalds	stmia	r5, {r2 - r4}
282*1da177e4SLinus Torvalds	stmdb	r5, {sp, lr}^
283*1da177e4SLinus Torvalds
284*1da177e4SLinus Torvalds	@
285*1da177e4SLinus Torvalds	@ Enable the alignment trap while in kernel mode
286*1da177e4SLinus Torvalds	@
287*1da177e4SLinus Torvalds	alignment_trap r7, r0, __temp_\sym
288*1da177e4SLinus Torvalds
289*1da177e4SLinus Torvalds	@
290*1da177e4SLinus Torvalds	@ Clear FP to mark the first stack frame
291*1da177e4SLinus Torvalds	@
292*1da177e4SLinus Torvalds	zero_fp
293*1da177e4SLinus Torvalds	.endm
294*1da177e4SLinus Torvalds
295*1da177e4SLinus Torvalds	.align	5
296*1da177e4SLinus Torvalds__dabt_usr:
297*1da177e4SLinus Torvalds	usr_entry abt
298*1da177e4SLinus Torvalds
299*1da177e4SLinus Torvalds	@
300*1da177e4SLinus Torvalds	@ Call the processor-specific abort handler:
301*1da177e4SLinus Torvalds	@
302*1da177e4SLinus Torvalds	@  r2 - aborted context pc
303*1da177e4SLinus Torvalds	@  r3 - aborted context cpsr
304*1da177e4SLinus Torvalds	@
305*1da177e4SLinus Torvalds	@ The abort handler must return the aborted address in r0, and
306*1da177e4SLinus Torvalds	@ the fault status register in r1.
307*1da177e4SLinus Torvalds	@
308*1da177e4SLinus Torvalds#ifdef MULTI_ABORT
309*1da177e4SLinus Torvalds	ldr	r4, .LCprocfns
310*1da177e4SLinus Torvalds	mov	lr, pc
311*1da177e4SLinus Torvalds	ldr	pc, [r4]
312*1da177e4SLinus Torvalds#else
313*1da177e4SLinus Torvalds	bl	CPU_ABORT_HANDLER
314*1da177e4SLinus Torvalds#endif
315*1da177e4SLinus Torvalds
316*1da177e4SLinus Torvalds	@
317*1da177e4SLinus Torvalds	@ IRQs on, then call the main handler
318*1da177e4SLinus Torvalds	@
319*1da177e4SLinus Torvalds	enable_irq r2
320*1da177e4SLinus Torvalds	mov	r2, sp
321*1da177e4SLinus Torvalds	adr	lr, ret_from_exception
322*1da177e4SLinus Torvalds	b	do_DataAbort
323*1da177e4SLinus Torvalds
324*1da177e4SLinus Torvalds	.align	5
325*1da177e4SLinus Torvalds__irq_usr:
326*1da177e4SLinus Torvalds	usr_entry irq
327*1da177e4SLinus Torvalds
328*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
329*1da177e4SLinus Torvalds	get_thread_info r8
330*1da177e4SLinus Torvalds	ldr	r9, [r8, #TI_PREEMPT]		@ get preempt count
331*1da177e4SLinus Torvalds	add	r7, r9, #1			@ increment it
332*1da177e4SLinus Torvalds	str	r7, [r8, #TI_PREEMPT]
333*1da177e4SLinus Torvalds#endif
334*1da177e4SLinus Torvalds1:	get_irqnr_and_base r0, r6, r5, lr
335*1da177e4SLinus Torvalds	movne	r1, sp
336*1da177e4SLinus Torvalds	adrne	lr, 1b
337*1da177e4SLinus Torvalds	@
338*1da177e4SLinus Torvalds	@ routine called with r0 = irq number, r1 = struct pt_regs *
339*1da177e4SLinus Torvalds	@
340*1da177e4SLinus Torvalds	bne	asm_do_IRQ
341*1da177e4SLinus Torvalds#ifdef CONFIG_PREEMPT
342*1da177e4SLinus Torvalds	ldr	r0, [r8, #TI_PREEMPT]
343*1da177e4SLinus Torvalds	teq	r0, r7
344*1da177e4SLinus Torvalds	str	r9, [r8, #TI_PREEMPT]
345*1da177e4SLinus Torvalds	strne	r0, [r0, -r0]
346*1da177e4SLinus Torvalds	mov	tsk, r8
347*1da177e4SLinus Torvalds#else
348*1da177e4SLinus Torvalds	get_thread_info tsk
349*1da177e4SLinus Torvalds#endif
350*1da177e4SLinus Torvalds	mov	why, #0
351*1da177e4SLinus Torvalds	b	ret_to_user
352*1da177e4SLinus Torvalds
353*1da177e4SLinus Torvalds	.ltorg
354*1da177e4SLinus Torvalds
355*1da177e4SLinus Torvalds	.align	5
356*1da177e4SLinus Torvalds__und_usr:
357*1da177e4SLinus Torvalds	usr_entry und
358*1da177e4SLinus Torvalds
359*1da177e4SLinus Torvalds	tst	r3, #PSR_T_BIT			@ Thumb mode?
360*1da177e4SLinus Torvalds	bne	fpundefinstr			@ ignore FP
361*1da177e4SLinus Torvalds	sub	r4, r2, #4
362*1da177e4SLinus Torvalds
363*1da177e4SLinus Torvalds	@
364*1da177e4SLinus Torvalds	@ fall through to the emulation code, which returns using r9 if
365*1da177e4SLinus Torvalds	@ it has emulated the instruction, or the more conventional lr
366*1da177e4SLinus Torvalds	@ if we are to treat this as a real undefined instruction
367*1da177e4SLinus Torvalds	@
368*1da177e4SLinus Torvalds	@  r0 - instruction
369*1da177e4SLinus Torvalds	@
370*1da177e4SLinus Torvalds1:	ldrt	r0, [r4]
371*1da177e4SLinus Torvalds	adr	r9, ret_from_exception
372*1da177e4SLinus Torvalds	adr	lr, fpundefinstr
373*1da177e4SLinus Torvalds	@
374*1da177e4SLinus Torvalds	@ fallthrough to call_fpe
375*1da177e4SLinus Torvalds	@
376*1da177e4SLinus Torvalds
377*1da177e4SLinus Torvalds/*
378*1da177e4SLinus Torvalds * The out of line fixup for the ldrt above.
379*1da177e4SLinus Torvalds */
380*1da177e4SLinus Torvalds	.section .fixup, "ax"
381*1da177e4SLinus Torvalds2:	mov	pc, r9
382*1da177e4SLinus Torvalds	.previous
383*1da177e4SLinus Torvalds	.section __ex_table,"a"
384*1da177e4SLinus Torvalds	.long	1b, 2b
385*1da177e4SLinus Torvalds	.previous
386*1da177e4SLinus Torvalds
387*1da177e4SLinus Torvalds/*
388*1da177e4SLinus Torvalds * Check whether the instruction is a co-processor instruction.
389*1da177e4SLinus Torvalds * If yes, we need to call the relevant co-processor handler.
390*1da177e4SLinus Torvalds *
391*1da177e4SLinus Torvalds * Note that we don't do a full check here for the co-processor
392*1da177e4SLinus Torvalds * instructions; all instructions with bit 27 set are well
393*1da177e4SLinus Torvalds * defined.  The only instructions that should fault are the
394*1da177e4SLinus Torvalds * co-processor instructions.  However, we have to watch out
395*1da177e4SLinus Torvalds * for the ARM6/ARM7 SWI bug.
396*1da177e4SLinus Torvalds *
397*1da177e4SLinus Torvalds * Emulators may wish to make use of the following registers:
398*1da177e4SLinus Torvalds *  r0  = instruction opcode.
399*1da177e4SLinus Torvalds *  r2  = PC+4
400*1da177e4SLinus Torvalds *  r10 = this threads thread_info structure.
401*1da177e4SLinus Torvalds */
402*1da177e4SLinus Torvaldscall_fpe:
403*1da177e4SLinus Torvalds	tst	r0, #0x08000000			@ only CDP/CPRT/LDC/STC have bit 27
404*1da177e4SLinus Torvalds#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
405*1da177e4SLinus Torvalds	and	r8, r0, #0x0f000000		@ mask out op-code bits
406*1da177e4SLinus Torvalds	teqne	r8, #0x0f000000			@ SWI (ARM6/7 bug)?
407*1da177e4SLinus Torvalds#endif
408*1da177e4SLinus Torvalds	moveq	pc, lr
409*1da177e4SLinus Torvalds	get_thread_info r10			@ get current thread
410*1da177e4SLinus Torvalds	and	r8, r0, #0x00000f00		@ mask out CP number
411*1da177e4SLinus Torvalds	mov	r7, #1
412*1da177e4SLinus Torvalds	add	r6, r10, #TI_USED_CP
413*1da177e4SLinus Torvalds	strb	r7, [r6, r8, lsr #8]		@ set appropriate used_cp[]
414*1da177e4SLinus Torvalds#ifdef CONFIG_IWMMXT
415*1da177e4SLinus Torvalds	@ Test if we need to give access to iWMMXt coprocessors
416*1da177e4SLinus Torvalds	ldr	r5, [r10, #TI_FLAGS]
417*1da177e4SLinus Torvalds	rsbs	r7, r8, #(1 << 8)		@ CP 0 or 1 only
418*1da177e4SLinus Torvalds	movcss	r7, r5, lsr #(TIF_USING_IWMMXT + 1)
419*1da177e4SLinus Torvalds	bcs	iwmmxt_task_enable
420*1da177e4SLinus Torvalds#endif
421*1da177e4SLinus Torvalds	enable_irq r7
422*1da177e4SLinus Torvalds	add	pc, pc, r8, lsr #6
423*1da177e4SLinus Torvalds	mov	r0, r0
424*1da177e4SLinus Torvalds
425*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#0
426*1da177e4SLinus Torvalds	b	do_fpe				@ CP#1 (FPE)
427*1da177e4SLinus Torvalds	b	do_fpe				@ CP#2 (FPE)
428*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#3
429*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#4
430*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#5
431*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#6
432*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#7
433*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#8
434*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#9
435*1da177e4SLinus Torvalds#ifdef CONFIG_VFP
436*1da177e4SLinus Torvalds	b	do_vfp				@ CP#10 (VFP)
437*1da177e4SLinus Torvalds	b	do_vfp				@ CP#11 (VFP)
438*1da177e4SLinus Torvalds#else
439*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#10 (VFP)
440*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#11 (VFP)
441*1da177e4SLinus Torvalds#endif
442*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#12
443*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#13
444*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#14 (Debug)
445*1da177e4SLinus Torvalds	mov	pc, lr				@ CP#15 (Control)
446*1da177e4SLinus Torvalds
447*1da177e4SLinus Torvaldsdo_fpe:
448*1da177e4SLinus Torvalds	ldr	r4, .LCfp
449*1da177e4SLinus Torvalds	add	r10, r10, #TI_FPSTATE		@ r10 = workspace
450*1da177e4SLinus Torvalds	ldr	pc, [r4]			@ Call FP module USR entry point
451*1da177e4SLinus Torvalds
452*1da177e4SLinus Torvalds/*
453*1da177e4SLinus Torvalds * The FP module is called with these registers set:
454*1da177e4SLinus Torvalds *  r0  = instruction
455*1da177e4SLinus Torvalds *  r2  = PC+4
456*1da177e4SLinus Torvalds *  r9  = normal "successful" return address
457*1da177e4SLinus Torvalds *  r10 = FP workspace
458*1da177e4SLinus Torvalds *  lr  = unrecognised FP instruction return address
459*1da177e4SLinus Torvalds */
460*1da177e4SLinus Torvalds
461*1da177e4SLinus Torvalds	.data
462*1da177e4SLinus TorvaldsENTRY(fp_enter)
463*1da177e4SLinus Torvalds	.word	fpundefinstr
464*1da177e4SLinus Torvalds	.text
465*1da177e4SLinus Torvalds
466*1da177e4SLinus Torvaldsfpundefinstr:
467*1da177e4SLinus Torvalds	mov	r0, sp
468*1da177e4SLinus Torvalds	adr	lr, ret_from_exception
469*1da177e4SLinus Torvalds	b	do_undefinstr
470*1da177e4SLinus Torvalds
471*1da177e4SLinus Torvalds	.align	5
472*1da177e4SLinus Torvalds__pabt_usr:
473*1da177e4SLinus Torvalds	usr_entry abt
474*1da177e4SLinus Torvalds
475*1da177e4SLinus Torvalds	enable_irq r0				@ Enable interrupts
476*1da177e4SLinus Torvalds	mov	r0, r2				@ address (pc)
477*1da177e4SLinus Torvalds	mov	r1, sp				@ regs
478*1da177e4SLinus Torvalds	bl	do_PrefetchAbort		@ call abort handler
479*1da177e4SLinus Torvalds	/* fall through */
480*1da177e4SLinus Torvalds/*
481*1da177e4SLinus Torvalds * This is the return code to user mode for abort handlers
482*1da177e4SLinus Torvalds */
483*1da177e4SLinus TorvaldsENTRY(ret_from_exception)
484*1da177e4SLinus Torvalds	get_thread_info tsk
485*1da177e4SLinus Torvalds	mov	why, #0
486*1da177e4SLinus Torvalds	b	ret_to_user
487*1da177e4SLinus Torvalds
488*1da177e4SLinus Torvalds/*
489*1da177e4SLinus Torvalds * Register switch for ARMv3 and ARMv4 processors
490*1da177e4SLinus Torvalds * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
491*1da177e4SLinus Torvalds * previous and next are guaranteed not to be the same.
492*1da177e4SLinus Torvalds */
493*1da177e4SLinus TorvaldsENTRY(__switch_to)
494*1da177e4SLinus Torvalds	add	ip, r1, #TI_CPU_SAVE
495*1da177e4SLinus Torvalds	ldr	r3, [r2, #TI_TP_VALUE]
496*1da177e4SLinus Torvalds	stmia	ip!, {r4 - sl, fp, sp, lr}	@ Store most regs on stack
497*1da177e4SLinus Torvalds	ldr	r6, [r2, #TI_CPU_DOMAIN]!
498*1da177e4SLinus Torvalds#if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT)
499*1da177e4SLinus Torvalds	mra	r4, r5, acc0
500*1da177e4SLinus Torvalds	stmia   ip, {r4, r5}
501*1da177e4SLinus Torvalds#endif
502*1da177e4SLinus Torvalds	mov	r4, #0xffff0fff
503*1da177e4SLinus Torvalds	str	r3, [r4, #-3]			@ Set TLS ptr
504*1da177e4SLinus Torvalds	mcr	p15, 0, r6, c3, c0, 0		@ Set domain register
505*1da177e4SLinus Torvalds#ifdef CONFIG_VFP
506*1da177e4SLinus Torvalds	@ Always disable VFP so we can lazily save/restore the old
507*1da177e4SLinus Torvalds	@ state. This occurs in the context of the previous thread.
508*1da177e4SLinus Torvalds	VFPFMRX	r4, FPEXC
509*1da177e4SLinus Torvalds	bic	r4, r4, #FPEXC_ENABLE
510*1da177e4SLinus Torvalds	VFPFMXR	FPEXC, r4
511*1da177e4SLinus Torvalds#endif
512*1da177e4SLinus Torvalds#if defined(CONFIG_IWMMXT)
513*1da177e4SLinus Torvalds	bl	iwmmxt_task_switch
514*1da177e4SLinus Torvalds#elif defined(CONFIG_CPU_XSCALE)
515*1da177e4SLinus Torvalds	add	r4, r2, #40			@ cpu_context_save->extra
516*1da177e4SLinus Torvalds	ldmib	r4, {r4, r5}
517*1da177e4SLinus Torvalds	mar	acc0, r4, r5
518*1da177e4SLinus Torvalds#endif
519*1da177e4SLinus Torvalds	ldmib	r2, {r4 - sl, fp, sp, pc}	@ Load all regs saved previously
520*1da177e4SLinus Torvalds
521*1da177e4SLinus Torvalds	__INIT
522*1da177e4SLinus Torvalds/*
523*1da177e4SLinus Torvalds * Vector stubs.
524*1da177e4SLinus Torvalds *
525*1da177e4SLinus Torvalds * This code is copied to 0x200 or 0xffff0200 so we can use branches in the
526*1da177e4SLinus Torvalds * vectors, rather than ldr's.
527*1da177e4SLinus Torvalds *
528*1da177e4SLinus Torvalds * Common stub entry macro:
529*1da177e4SLinus Torvalds *   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
530*1da177e4SLinus Torvalds */
531*1da177e4SLinus Torvalds	.macro	vector_stub, name, sym, correction=0
532*1da177e4SLinus Torvalds	.align	5
533*1da177e4SLinus Torvalds
534*1da177e4SLinus Torvaldsvector_\name:
535*1da177e4SLinus Torvalds	ldr	r13, .LCs\sym
536*1da177e4SLinus Torvalds	.if \correction
537*1da177e4SLinus Torvalds	sub	lr, lr, #\correction
538*1da177e4SLinus Torvalds	.endif
539*1da177e4SLinus Torvalds	str	lr, [r13]			@ save lr_IRQ
540*1da177e4SLinus Torvalds	mrs	lr, spsr
541*1da177e4SLinus Torvalds	str	lr, [r13, #4]			@ save spsr_IRQ
542*1da177e4SLinus Torvalds	@
543*1da177e4SLinus Torvalds	@ now branch to the relevant MODE handling routine
544*1da177e4SLinus Torvalds	@
545*1da177e4SLinus Torvalds	mrs	r13, cpsr
546*1da177e4SLinus Torvalds	bic	r13, r13, #MODE_MASK
547*1da177e4SLinus Torvalds	orr	r13, r13, #MODE_SVC
548*1da177e4SLinus Torvalds	msr	spsr_cxsf, r13			@ switch to SVC_32 mode
549*1da177e4SLinus Torvalds
550*1da177e4SLinus Torvalds	and	lr, lr, #15
551*1da177e4SLinus Torvalds	ldr	lr, [pc, lr, lsl #2]
552*1da177e4SLinus Torvalds	movs	pc, lr				@ Changes mode and branches
553*1da177e4SLinus Torvalds	.endm
554*1da177e4SLinus Torvalds
555*1da177e4SLinus Torvalds__stubs_start:
556*1da177e4SLinus Torvalds/*
557*1da177e4SLinus Torvalds * Interrupt dispatcher
558*1da177e4SLinus Torvalds */
559*1da177e4SLinus Torvalds	vector_stub	irq, irq, 4
560*1da177e4SLinus Torvalds
561*1da177e4SLinus Torvalds	.long	__irq_usr			@  0  (USR_26 / USR_32)
562*1da177e4SLinus Torvalds	.long	__irq_invalid			@  1  (FIQ_26 / FIQ_32)
563*1da177e4SLinus Torvalds	.long	__irq_invalid			@  2  (IRQ_26 / IRQ_32)
564*1da177e4SLinus Torvalds	.long	__irq_svc			@  3  (SVC_26 / SVC_32)
565*1da177e4SLinus Torvalds	.long	__irq_invalid			@  4
566*1da177e4SLinus Torvalds	.long	__irq_invalid			@  5
567*1da177e4SLinus Torvalds	.long	__irq_invalid			@  6
568*1da177e4SLinus Torvalds	.long	__irq_invalid			@  7
569*1da177e4SLinus Torvalds	.long	__irq_invalid			@  8
570*1da177e4SLinus Torvalds	.long	__irq_invalid			@  9
571*1da177e4SLinus Torvalds	.long	__irq_invalid			@  a
572*1da177e4SLinus Torvalds	.long	__irq_invalid			@  b
573*1da177e4SLinus Torvalds	.long	__irq_invalid			@  c
574*1da177e4SLinus Torvalds	.long	__irq_invalid			@  d
575*1da177e4SLinus Torvalds	.long	__irq_invalid			@  e
576*1da177e4SLinus Torvalds	.long	__irq_invalid			@  f
577*1da177e4SLinus Torvalds
578*1da177e4SLinus Torvalds/*
579*1da177e4SLinus Torvalds * Data abort dispatcher
580*1da177e4SLinus Torvalds * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
581*1da177e4SLinus Torvalds */
582*1da177e4SLinus Torvalds	vector_stub	dabt, abt, 8
583*1da177e4SLinus Torvalds
584*1da177e4SLinus Torvalds	.long	__dabt_usr			@  0  (USR_26 / USR_32)
585*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  1  (FIQ_26 / FIQ_32)
586*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  2  (IRQ_26 / IRQ_32)
587*1da177e4SLinus Torvalds	.long	__dabt_svc			@  3  (SVC_26 / SVC_32)
588*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  4
589*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  5
590*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  6
591*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  7
592*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  8
593*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  9
594*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  a
595*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  b
596*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  c
597*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  d
598*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  e
599*1da177e4SLinus Torvalds	.long	__dabt_invalid			@  f
600*1da177e4SLinus Torvalds
601*1da177e4SLinus Torvalds/*
602*1da177e4SLinus Torvalds * Prefetch abort dispatcher
603*1da177e4SLinus Torvalds * Enter in ABT mode, spsr = USR CPSR, lr = USR PC
604*1da177e4SLinus Torvalds */
605*1da177e4SLinus Torvalds	vector_stub	pabt, abt, 4
606*1da177e4SLinus Torvalds
607*1da177e4SLinus Torvalds	.long	__pabt_usr			@  0 (USR_26 / USR_32)
608*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  1 (FIQ_26 / FIQ_32)
609*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  2 (IRQ_26 / IRQ_32)
610*1da177e4SLinus Torvalds	.long	__pabt_svc			@  3 (SVC_26 / SVC_32)
611*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  4
612*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  5
613*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  6
614*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  7
615*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  8
616*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  9
617*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  a
618*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  b
619*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  c
620*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  d
621*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  e
622*1da177e4SLinus Torvalds	.long	__pabt_invalid			@  f
623*1da177e4SLinus Torvalds
624*1da177e4SLinus Torvalds/*
625*1da177e4SLinus Torvalds * Undef instr entry dispatcher
626*1da177e4SLinus Torvalds * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
627*1da177e4SLinus Torvalds */
628*1da177e4SLinus Torvalds	vector_stub	und, und
629*1da177e4SLinus Torvalds
630*1da177e4SLinus Torvalds	.long	__und_usr			@  0 (USR_26 / USR_32)
631*1da177e4SLinus Torvalds	.long	__und_invalid			@  1 (FIQ_26 / FIQ_32)
632*1da177e4SLinus Torvalds	.long	__und_invalid			@  2 (IRQ_26 / IRQ_32)
633*1da177e4SLinus Torvalds	.long	__und_svc			@  3 (SVC_26 / SVC_32)
634*1da177e4SLinus Torvalds	.long	__und_invalid			@  4
635*1da177e4SLinus Torvalds	.long	__und_invalid			@  5
636*1da177e4SLinus Torvalds	.long	__und_invalid			@  6
637*1da177e4SLinus Torvalds	.long	__und_invalid			@  7
638*1da177e4SLinus Torvalds	.long	__und_invalid			@  8
639*1da177e4SLinus Torvalds	.long	__und_invalid			@  9
640*1da177e4SLinus Torvalds	.long	__und_invalid			@  a
641*1da177e4SLinus Torvalds	.long	__und_invalid			@  b
642*1da177e4SLinus Torvalds	.long	__und_invalid			@  c
643*1da177e4SLinus Torvalds	.long	__und_invalid			@  d
644*1da177e4SLinus Torvalds	.long	__und_invalid			@  e
645*1da177e4SLinus Torvalds	.long	__und_invalid			@  f
646*1da177e4SLinus Torvalds
647*1da177e4SLinus Torvalds	.align	5
648*1da177e4SLinus Torvalds
649*1da177e4SLinus Torvalds/*=============================================================================
650*1da177e4SLinus Torvalds * Undefined FIQs
651*1da177e4SLinus Torvalds *-----------------------------------------------------------------------------
652*1da177e4SLinus Torvalds * Enter in FIQ mode, spsr = ANY CPSR, lr = ANY PC
653*1da177e4SLinus Torvalds * MUST PRESERVE SVC SPSR, but need to switch to SVC mode to show our msg.
654*1da177e4SLinus Torvalds * Basically to switch modes, we *HAVE* to clobber one register...  brain
655*1da177e4SLinus Torvalds * damage alert!  I don't think that we can execute any code in here in any
656*1da177e4SLinus Torvalds * other mode than FIQ...  Ok you can switch to another mode, but you can't
657*1da177e4SLinus Torvalds * get out of that mode without clobbering one register.
658*1da177e4SLinus Torvalds */
659*1da177e4SLinus Torvaldsvector_fiq:
660*1da177e4SLinus Torvalds	disable_fiq
661*1da177e4SLinus Torvalds	subs	pc, lr, #4
662*1da177e4SLinus Torvalds
663*1da177e4SLinus Torvalds/*=============================================================================
664*1da177e4SLinus Torvalds * Address exception handler
665*1da177e4SLinus Torvalds *-----------------------------------------------------------------------------
666*1da177e4SLinus Torvalds * These aren't too critical.
667*1da177e4SLinus Torvalds * (they're not supposed to happen, and won't happen in 32-bit data mode).
668*1da177e4SLinus Torvalds */
669*1da177e4SLinus Torvalds
670*1da177e4SLinus Torvaldsvector_addrexcptn:
671*1da177e4SLinus Torvalds	b	vector_addrexcptn
672*1da177e4SLinus Torvalds
673*1da177e4SLinus Torvalds/*
674*1da177e4SLinus Torvalds * We group all the following data together to optimise
675*1da177e4SLinus Torvalds * for CPUs with separate I & D caches.
676*1da177e4SLinus Torvalds */
677*1da177e4SLinus Torvalds	.align	5
678*1da177e4SLinus Torvalds
679*1da177e4SLinus Torvalds.LCvswi:
680*1da177e4SLinus Torvalds	.word	vector_swi
681*1da177e4SLinus Torvalds
682*1da177e4SLinus Torvalds.LCsirq:
683*1da177e4SLinus Torvalds	.word	__temp_irq
684*1da177e4SLinus Torvalds.LCsund:
685*1da177e4SLinus Torvalds	.word	__temp_und
686*1da177e4SLinus Torvalds.LCsabt:
687*1da177e4SLinus Torvalds	.word	__temp_abt
688*1da177e4SLinus Torvalds
689*1da177e4SLinus Torvalds__stubs_end:
690*1da177e4SLinus Torvalds
691*1da177e4SLinus Torvalds	.equ	__real_stubs_start, .LCvectors + 0x200
692*1da177e4SLinus Torvalds
693*1da177e4SLinus Torvalds.LCvectors:
694*1da177e4SLinus Torvalds	swi	SYS_ERROR0
695*1da177e4SLinus Torvalds	b	__real_stubs_start + (vector_und - __stubs_start)
696*1da177e4SLinus Torvalds	ldr	pc, __real_stubs_start + (.LCvswi - __stubs_start)
697*1da177e4SLinus Torvalds	b	__real_stubs_start + (vector_pabt - __stubs_start)
698*1da177e4SLinus Torvalds	b	__real_stubs_start + (vector_dabt - __stubs_start)
699*1da177e4SLinus Torvalds	b	__real_stubs_start + (vector_addrexcptn - __stubs_start)
700*1da177e4SLinus Torvalds	b	__real_stubs_start + (vector_irq - __stubs_start)
701*1da177e4SLinus Torvalds	b	__real_stubs_start + (vector_fiq - __stubs_start)
702*1da177e4SLinus Torvalds
703*1da177e4SLinus TorvaldsENTRY(__trap_init)
704*1da177e4SLinus Torvalds	stmfd	sp!, {r4 - r6, lr}
705*1da177e4SLinus Torvalds
706*1da177e4SLinus Torvalds	mov	r0, #0xff000000
707*1da177e4SLinus Torvalds	orr	r0, r0, #0x00ff0000		@ high vectors position
708*1da177e4SLinus Torvalds	adr	r1, .LCvectors			@ set up the vectors
709*1da177e4SLinus Torvalds	ldmia	r1, {r1, r2, r3, r4, r5, r6, ip, lr}
710*1da177e4SLinus Torvalds	stmia	r0, {r1, r2, r3, r4, r5, r6, ip, lr}
711*1da177e4SLinus Torvalds
712*1da177e4SLinus Torvalds	add	r2, r0, #0x200
713*1da177e4SLinus Torvalds	adr	r0, __stubs_start		@ copy stubs to 0x200
714*1da177e4SLinus Torvalds	adr	r1, __stubs_end
715*1da177e4SLinus Torvalds1:	ldr	r3, [r0], #4
716*1da177e4SLinus Torvalds	str	r3, [r2], #4
717*1da177e4SLinus Torvalds	cmp	r0, r1
718*1da177e4SLinus Torvalds	blt	1b
719*1da177e4SLinus Torvalds	LOADREGS(fd, sp!, {r4 - r6, pc})
720*1da177e4SLinus Torvalds
721*1da177e4SLinus Torvalds	.data
722*1da177e4SLinus Torvalds
723*1da177e4SLinus Torvalds/*
724*1da177e4SLinus Torvalds * Do not reorder these, and do not insert extra data between...
725*1da177e4SLinus Torvalds */
726*1da177e4SLinus Torvalds
727*1da177e4SLinus Torvalds__temp_irq:
728*1da177e4SLinus Torvalds	.word	0				@ saved lr_irq
729*1da177e4SLinus Torvalds	.word	0				@ saved spsr_irq
730*1da177e4SLinus Torvalds	.word	-1				@ old_r0
731*1da177e4SLinus Torvalds__temp_und:
732*1da177e4SLinus Torvalds	.word	0				@ Saved lr_und
733*1da177e4SLinus Torvalds	.word	0				@ Saved spsr_und
734*1da177e4SLinus Torvalds	.word	-1				@ old_r0
735*1da177e4SLinus Torvalds__temp_abt:
736*1da177e4SLinus Torvalds	.word	0				@ Saved lr_abt
737*1da177e4SLinus Torvalds	.word	0				@ Saved spsr_abt
738*1da177e4SLinus Torvalds	.word	-1				@ old_r0
739*1da177e4SLinus Torvalds
740*1da177e4SLinus Torvalds	.globl	cr_alignment
741*1da177e4SLinus Torvalds	.globl	cr_no_alignment
742*1da177e4SLinus Torvaldscr_alignment:
743*1da177e4SLinus Torvalds	.space	4
744*1da177e4SLinus Torvaldscr_no_alignment:
745*1da177e4SLinus Torvalds	.space	4
746