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