exception.S revision 1.12 1 /* $NetBSD: exception.S,v 1.12 2003/10/30 08:57:24 scw 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
57 AST_ALIGNMENT_FAULT_LOCALS
58
59 /*
60 * General exception exit handler
61 *
62 * It exits straight away if not returning to USR mode.
63 * This loops around delivering any pending ASTs.
64 * Interrupts are disabled at suitable points to avoid ASTs
65 * being posted between testing and exit to user mode.
66 *
67 * This function uses PULLFRAMEFROMSVCANDEXIT and
68 * DO_AST_AND_RESTORE_ALIGNMENT_FAULTS thus should
69 * only be called if the exception handler used PUSHFRAMEINSVC
70 * followed by ENABLE_ALIGNMENT_FAULTS.
71 */
72
73 exception_exit:
74 DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
75 PULLFRAMEFROMSVCANDEXIT
76
77 /*
78 * reset_entry:
79 *
80 * Handler for Reset exception.
81 */
82 ASENTRY_NP(reset_entry)
83 adr r0, Lreset_panicmsg
84 mov r1, lr
85 bl _C_LABEL(panic)
86 /* NOTREACHED */
87 Lreset_panicmsg:
88 .asciz "Reset vector called, LR = 0x%08x"
89 .balign 4
90
91 /*
92 * swi_entry
93 *
94 * Handler for the Software Interrupt exception.
95 */
96 ASENTRY_NP(swi_entry)
97 PUSHFRAME
98 ENABLE_ALIGNMENT_FAULTS
99
100 mov r0, sp /* Pass the frame to any function */
101 bl _C_LABEL(swi_handler) /* It's a SWI ! */
102
103 DO_AST_AND_RESTORE_ALIGNMENT_FAULTS
104 PULLFRAME
105 movs pc, lr /* Exit */
106
107 /*
108 * prefetch_abort_entry:
109 *
110 * Handler for the Prefetch Abort exception.
111 */
112 ASENTRY_NP(prefetch_abort_entry)
113 sub lr, lr, #0x00000004 /* Adjust the lr */
114
115 PUSHFRAMEINSVC
116 ENABLE_ALIGNMENT_FAULTS
117
118 ldr r1, Lprefetch_abort_handler_address
119 adr lr, exception_exit
120 mov r0, sp /* pass the stack pointer as r0 */
121 ldr pc, [r1]
122
123 Lprefetch_abort_handler_address:
124 .word _C_LABEL(prefetch_abort_handler_address)
125
126 .data
127 .global _C_LABEL(prefetch_abort_handler_address)
128
129 _C_LABEL(prefetch_abort_handler_address):
130 .word abortprefetch
131
132 .text
133 abortprefetch:
134 adr r0, abortprefetchmsg
135 b _C_LABEL(panic)
136
137 abortprefetchmsg:
138 .asciz "abortprefetch"
139 .align 0
140
141 /*
142 * data_abort_entry:
143 *
144 * Handler for the Data Abort exception.
145 */
146 ASENTRY_NP(data_abort_entry)
147 sub lr, lr, #0x00000008 /* Adjust the lr */
148
149 PUSHFRAMEINSVC /* Push trap frame and switch */
150 /* to SVC32 mode */
151 ENABLE_ALIGNMENT_FAULTS
152
153 ldr r1, Ldata_abort_handler_address
154 adr lr, exception_exit
155 mov r0, sp /* pass the stack pointer as r0 */
156 ldr pc, [r1]
157
158 Ldata_abort_handler_address:
159 .word _C_LABEL(data_abort_handler_address)
160
161 .data
162 .global _C_LABEL(data_abort_handler_address)
163 _C_LABEL(data_abort_handler_address):
164 .word abortdata
165
166 .text
167 abortdata:
168 adr r0, abortdatamsg
169 b _C_LABEL(panic)
170
171 abortdatamsg:
172 .asciz "abortdata"
173 .align 0
174
175 /*
176 * address_exception_entry:
177 *
178 * Handler for the Address Exception exception.
179 *
180 * NOTE: This exception isn't really used on arm32. We
181 * print a warning message to the console and then treat
182 * it like a Data Abort.
183 */
184 ASENTRY_NP(address_exception_entry)
185 mrs r1, cpsr_all
186 mrs r2, spsr_all
187 mov r3, lr
188 adr r0, Laddress_exception_msg
189 bl _C_LABEL(printf) /* XXX CLOBBERS LR!! */
190 b data_abort_entry
191 Laddress_exception_msg:
192 .asciz "Address Exception CPSR=0x%08x SPSR=0x%08x LR=0x%08x\n"
193 .balign 4
194
195 /*
196 * undefined_entry:
197 *
198 * Handler for the Undefined Instruction exception.
199 *
200 * We indirect the undefined vector via the handler address
201 * in the data area. Entry to the undefined handler must
202 * look like direct entry from the vector.
203 */
204 ASENTRY_NP(undefined_entry)
205 #ifdef IPKDB
206 /*
207 * IPKDB must be hooked in at the earliest possible entry point.
208 *
209 */
210 /*
211 * Make room for all registers saving real r0-r7 and r15.
212 * The remaining registers are updated later.
213 */
214 stmfd sp!, {r0,r1} /* psr & spsr */
215 stmfd sp!, {lr} /* pc */
216 stmfd sp!, {r0-r14} /* r0-r7, r8-r14 */
217 /*
218 * Get previous psr.
219 */
220 mrs r7, cpsr_all
221 mrs r0, spsr_all
222 str r0, [sp, #(16*4)]
223 /*
224 * Test for user mode.
225 */
226 tst r0, #0xf
227 bne .Lprenotuser_push
228 add r1, sp, #(8*4)
229 stmia r1,{r8-r14}^ /* store user mode r8-r14*/
230 b .Lgoipkdb
231 /*
232 * Switch to previous mode to get r8-r13.
233 */
234 .Lprenotuser_push:
235 orr r0, r0, #(I32_bit) /* disable interrupts */
236 msr cpsr_all, r0
237 mov r1, r8
238 mov r2, r9
239 mov r3, r10
240 mov r4, r11
241 mov r5, r12
242 mov r6, r13
243 msr cpsr_all, r7 /* back to undefined mode */
244 add r8, sp, #(8*4)
245 stmia r8, {r1-r6} /* r8-r13 */
246 /*
247 * Now back to previous mode to get r14 and spsr.
248 */
249 msr cpsr_all, r0
250 mov r1, r14
251 mrs r2, spsr
252 msr cpsr_all, r7 /* back to undefined mode */
253 str r1, [sp, #(14*4)] /* r14 */
254 str r2, [sp, #(17*4)] /* spsr */
255 /*
256 * Now to IPKDB.
257 */
258 .Lgoipkdb:
259 mov r0, sp
260 bl _C_LABEL(ipkdb_trap_glue)
261 ldr r1, .Lipkdb_trap_return
262 str r0,[r1]
263
264 /*
265 * Have to load all registers from the stack.
266 *
267 * Start with spsr and pc.
268 */
269 ldr r0, [sp, #(16*4)] /* spsr */
270 ldr r1, [sp, #(15*4)] /* r15 */
271 msr spsr_all, r0
272 mov r14, r1
273 /*
274 * Test for user mode.
275 */
276 tst r0, #0xf
277 bne .Lprenotuser_pull
278 add r1, sp, #(8*4)
279 ldmia r1, {r8-r14}^ /* load user mode r8-r14 */
280 b .Lpull_r0r7
281 .Lprenotuser_pull:
282 /*
283 * Now previous mode spsr and r14.
284 */
285 ldr r1, [sp, #(17*4)] /* spsr */
286 ldr r2, [sp, #(14*4)] /* r14 */
287 orr r0, r0, #(I32_bit)
288 msr cpsr_all, r0 /* switch to previous mode */
289 msr spsr_all, r1
290 mov r14, r2
291 msr cpsr_all, r7 /* back to undefined mode */
292 /*
293 * Now r8-r13.
294 */
295 add r8, sp, #(8*4)
296 ldmia r8, {r1-r6} /* r8-r13 */
297 msr cpsr_all, r0
298 mov r8, r1
299 mov r9, r2
300 mov r10, r3
301 mov r11, r4
302 mov r12, r5
303 mov r13, r6
304 msr cpsr_all, r7
305 .Lpull_r0r7:
306 /*
307 * Now the rest of the registers.
308 */
309 ldr r1,Lipkdb_trap_return
310 ldr r0,[r1]
311 tst r0,r0
312 ldmfd sp!, {r0-r7} /* r0-r7 */
313 add sp, sp, #(10*4) /* adjust sp */
314
315 /*
316 * Did IPKDB handle it?
317 */
318 movnes pc, lr /* return */
319
320 #endif
321 stmfd sp!, {r0, r1}
322 ldr r0, Lundefined_handler_indirection
323 ldr r1, [sp], #0x0004
324 str r1, [r0, #0x0000]
325 ldr r1, [sp], #0x0004
326 str r1, [r0, #0x0004]
327 ldmia r0, {r0, r1, pc}
328
329 #ifdef IPKDB
330 Lipkdb_trap_return:
331 .word Lipkdb_trap_return_data
332 #endif
333
334 Lundefined_handler_indirection:
335 .word Lundefined_handler_indirection_data
336
337 /*
338 * assembly bounce code for calling the kernel
339 * undefined instruction handler. This uses
340 * a standard trap frame and is called in SVC mode.
341 */
342
343 ENTRY_NP(undefinedinstruction_bounce)
344 PUSHFRAMEINSVC
345 ENABLE_ALIGNMENT_FAULTS
346
347 mov r0, sp
348 adr lr, exception_exit
349 b _C_LABEL(undefinedinstruction)
350
351 .data
352 .align 0
353
354 #ifdef IPKDB
355 Lipkdb_trap_return_data:
356 .word 0
357 #endif
358
359 /*
360 * Indirection data
361 * 2 words use for preserving r0 and r1
362 * 3rd word contains the undefined handler address.
363 */
364
365 Lundefined_handler_indirection_data:
366 .word 0
367 .word 0
368
369 .global _C_LABEL(undefined_handler_address)
370 _C_LABEL(undefined_handler_address):
371 .word _C_LABEL(undefinedinstruction_bounce)
372