xref: /netbsd-src/sys/arch/arm/arm32/exception.S (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1/*	$NetBSD: exception.S,v 1.14 2005/12/11 12:16:41 christos Exp $	*/
2
3/*
4 * Copyright (c) 1994-1997 Mark Brinicombe.
5 * Copyright (c) 1994 Brini.
6 * All rights reserved.
7 *
8 * This code is derived from software written for Brini by Mark Brinicombe
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 *    must display the following acknowledgement:
20 *	This product includes software developed by Brini.
21 * 4. The name of the company nor the name of the author may be used to
22 *    endorse or promote products derived from this software without specific
23 *    prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * RiscBSD kernel project
38 *
39 * exception.S
40 *
41 * Low level handlers for exception vectors
42 *
43 * Created      : 24/09/94
44 *
45 * Based on kate/display/abort.s
46 */
47
48#include "opt_ipkdb.h"
49#include <machine/asm.h>
50#include <machine/cpu.h>
51#include <machine/frame.h>
52#include "assym.h"
53
54	.text
55	.align	0
56
57AST_ALIGNMENT_FAULT_LOCALS
58
59/*
60 * reset_entry:
61 *
62 *	Handler for Reset exception.
63 */
64ASENTRY_NP(reset_entry)
65	adr	r0, Lreset_panicmsg
66	mov	r1, lr
67	bl	_C_LABEL(panic)
68	/* NOTREACHED */
69Lreset_panicmsg:
70	.asciz	"Reset vector called, LR = 0x%08x"
71	.balign	4
72
73/*
74 * swi_entry
75 *
76 *	Handler for the Software Interrupt exception.
77 */
78ASENTRY_NP(swi_entry)
79	PUSHFRAME
80	ENABLE_ALIGNMENT_FAULTS
81
82	mov	r0, sp			/* Pass the frame to any function */
83	bl	_C_LABEL(swi_handler)	/* It's a SWI ! */
84
85	DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
86	PULLFRAME
87	movs	pc, lr			/* Exit */
88
89/*
90 * prefetch_abort_entry:
91 *
92 *	Handler for the Prefetch Abort exception.
93 */
94ASENTRY_NP(prefetch_abort_entry)
95#ifdef __XSCALE__
96	nop				/* Make absolutely sure any pending */
97	nop				/* imprecise aborts have occurred. */
98#endif
99        sub     lr, lr, #0x00000004     /* Adjust the lr */
100
101	PUSHFRAMEINSVC
102	ENABLE_ALIGNMENT_FAULTS
103
104	ldr	r1, Lprefetch_abort_handler_address
105	adr	lr, exception_exit
106 	mov	r0, sp			/* pass the stack pointer as r0 */
107	ldr	pc, [r1]
108
109Lprefetch_abort_handler_address:
110	.word	_C_LABEL(prefetch_abort_handler_address)
111
112	.data
113	.global	_C_LABEL(prefetch_abort_handler_address)
114
115_C_LABEL(prefetch_abort_handler_address):
116	.word	abortprefetch
117
118	.text
119abortprefetch:
120        adr     r0, abortprefetchmsg
121	b	_C_LABEL(panic)
122
123abortprefetchmsg:
124        .asciz  "abortprefetch"
125        .align  0
126
127/*
128 * data_abort_entry:
129 *
130 *	Handler for the Data Abort exception.
131 */
132ASENTRY_NP(data_abort_entry)
133#ifdef __XSCALE__
134	nop				/* Make absolutely sure any pending */
135	nop				/* imprecise aborts have occurred. */
136#endif
137        sub     lr, lr, #0x00000008     /* Adjust the lr */
138
139	PUSHFRAMEINSVC			/* Push trap frame and switch */
140					/* to SVC32 mode */
141	ENABLE_ALIGNMENT_FAULTS
142
143	ldr	r1, Ldata_abort_handler_address
144	adr	lr, exception_exit
145	mov	r0, sp			/* pass the stack pointer as r0 */
146	ldr	pc, [r1]
147
148Ldata_abort_handler_address:
149	.word	_C_LABEL(data_abort_handler_address)
150
151	.data
152	.global	_C_LABEL(data_abort_handler_address)
153_C_LABEL(data_abort_handler_address):
154	.word	abortdata
155
156	.text
157abortdata:
158        adr     r0, abortdatamsg
159	b	_C_LABEL(panic)
160
161abortdatamsg:
162        .asciz  "abortdata"
163        .align  0
164
165/*
166 * address_exception_entry:
167 *
168 *	Handler for the Address Exception exception.
169 *
170 *	NOTE: This exception isn't really used on arm32.  We
171 *	print a warning message to the console and then treat
172 *	it like a Data Abort.
173 */
174ASENTRY_NP(address_exception_entry)
175	mrs	r1, cpsr_all
176	mrs	r2, spsr_all
177	mov	r3, lr
178	adr	r0, Laddress_exception_msg
179	bl	_C_LABEL(printf)	/* XXX CLOBBERS LR!! */
180	b	data_abort_entry
181Laddress_exception_msg:
182	.asciz	"Address Exception CPSR=0x%08x SPSR=0x%08x LR=0x%08x\n"
183	.balign	4
184
185/*
186 * General exception exit handler
187 * (Placed here to be within range of all the references to it)
188 *
189 * It exits straight away if not returning to USR mode.
190 * This loops around delivering any pending ASTs.
191 * Interrupts are disabled at suitable points to avoid ASTs
192 * being posted between testing and exit to user mode.
193 *
194 * This function uses PULLFRAMEFROMSVCANDEXIT and
195 * DO_AST_AND_RESTORE_ALIGNMENT_FAULTS thus should
196 * only be called if the exception handler used PUSHFRAMEINSVC
197 * followed by ENABLE_ALIGNMENT_FAULTS.
198 */
199
200exception_exit:
201	DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
202	PULLFRAMEFROMSVCANDEXIT
203
204/*
205 * undefined_entry:
206 *
207 *	Handler for the Undefined Instruction exception.
208 *
209 *	We indirect the undefined vector via the handler address
210 *	in the data area.  Entry to the undefined handler must
211 *	look like direct entry from the vector.
212 */
213ASENTRY_NP(undefined_entry)
214#ifdef IPKDB
215/*
216 * IPKDB must be hooked in at the earliest possible entry point.
217 *
218 */
219/*
220 * Make room for all registers saving real r0-r7 and r15.
221 * The remaining registers are updated later.
222 */
223	stmfd	sp!, {r0,r1}		/* psr & spsr */
224	stmfd	sp!, {lr}		/* pc */
225	stmfd	sp!, {r0-r14}		/* r0-r7, r8-r14 */
226/*
227 * Get previous psr.
228 */
229	mrs	r7, cpsr_all
230	mrs	r0, spsr_all
231	str	r0, [sp, #(16*4)]
232/*
233 * Test for user mode.
234 */
235	tst	r0, #0xf
236	bne	.Lprenotuser_push
237	add	r1, sp, #(8*4)
238	stmia	r1,{r8-r14}^		/* store user mode r8-r14*/
239	b	.Lgoipkdb
240/*
241 * Switch to previous mode to get r8-r13.
242 */
243.Lprenotuser_push:
244	orr	r0, r0, #(I32_bit) /* disable interrupts */
245	msr	cpsr_all, r0
246	mov	r1, r8
247	mov	r2, r9
248	mov	r3, r10
249	mov	r4, r11
250	mov	r5, r12
251	mov	r6, r13
252	msr	cpsr_all, r7		/* back to undefined mode */
253	add	r8, sp, #(8*4)
254	stmia	r8, {r1-r6}		/* r8-r13 */
255/*
256 * Now back to previous mode to get r14 and spsr.
257 */
258	msr	cpsr_all, r0
259	mov	r1, r14
260	mrs	r2, spsr
261	msr	cpsr_all, r7		/* back to undefined mode */
262	str	r1, [sp, #(14*4)]	/* r14 */
263	str	r2, [sp, #(17*4)]	/* spsr */
264/*
265 * Now to IPKDB.
266 */
267.Lgoipkdb:
268	mov	r0, sp
269	bl	_C_LABEL(ipkdb_trap_glue)
270	ldr	r1, .Lipkdb_trap_return
271	str	r0,[r1]
272
273/*
274 * Have to load all registers from the stack.
275 *
276 * Start with spsr and pc.
277 */
278	ldr	r0, [sp, #(16*4)]	/* spsr */
279	ldr	r1, [sp, #(15*4)]	/* r15 */
280	msr	spsr_all, r0
281	mov	r14, r1
282/*
283 * Test for user mode.
284 */
285	tst	r0, #0xf
286	bne	.Lprenotuser_pull
287	add	r1, sp, #(8*4)
288	ldmia	r1, {r8-r14}^		/* load user mode r8-r14 */
289	b	.Lpull_r0r7
290.Lprenotuser_pull:
291/*
292 * Now previous mode spsr and r14.
293 */
294	ldr	r1, [sp, #(17*4)]		/* spsr */
295	ldr	r2, [sp, #(14*4)]		/* r14 */
296	orr	r0, r0, #(I32_bit)
297	msr	cpsr_all, r0			/* switch to previous mode */
298	msr	spsr_all, r1
299	mov	r14, r2
300	msr	cpsr_all, r7			/* back to undefined mode */
301/*
302 * Now r8-r13.
303 */
304	add	r8, sp, #(8*4)
305	ldmia	r8, {r1-r6}		/* r8-r13 */
306	msr	cpsr_all, r0
307	mov	r8, r1
308	mov	r9, r2
309	mov	r10, r3
310	mov	r11, r4
311	mov	r12, r5
312	mov	r13, r6
313	msr	cpsr_all, r7
314.Lpull_r0r7:
315/*
316 * Now the rest of the registers.
317 */
318	ldr	r1,Lipkdb_trap_return
319	ldr	r0,[r1]
320	tst	r0,r0
321	ldmfd	sp!, {r0-r7}		/* r0-r7 */
322	add	sp, sp, #(10*4)		/* adjust sp */
323
324/*
325 * Did IPKDB handle it?
326 */
327	movnes	pc, lr			/* return */
328
329#endif
330	stmfd	sp!, {r0, r1}
331	ldr	r0, Lundefined_handler_indirection
332	ldr	r1, [sp], #0x0004
333	str	r1, [r0, #0x0000]
334	ldr	r1, [sp], #0x0004
335	str	r1, [r0, #0x0004]
336	ldmia	r0, {r0, r1, pc}
337
338#ifdef IPKDB
339Lipkdb_trap_return:
340	.word	Lipkdb_trap_return_data
341#endif
342
343Lundefined_handler_indirection:
344	.word	Lundefined_handler_indirection_data
345
346/*
347 * assembly bounce code for calling the kernel
348 * undefined instruction handler. This uses
349 * a standard trap frame and is called in SVC mode.
350 */
351
352ENTRY_NP(undefinedinstruction_bounce)
353	PUSHFRAMEINSVC
354	ENABLE_ALIGNMENT_FAULTS
355
356	mov	r0, sp
357	adr	lr, exception_exit
358	b	_C_LABEL(undefinedinstruction)
359
360	.data
361	.align	0
362
363#ifdef IPKDB
364Lipkdb_trap_return_data:
365	.word	0
366#endif
367
368/*
369 * Indirection data
370 * 2 words use for preserving r0 and r1
371 * 3rd word contains the undefined handler address.
372 */
373
374Lundefined_handler_indirection_data:
375	.word	0
376	.word	0
377
378	.global	_C_LABEL(undefined_handler_address)
379_C_LABEL(undefined_handler_address):
380	.word	_C_LABEL(undefinedinstruction_bounce)
381