exception.S revision 1.10 1 /* $NetBSD: exception.S,v 1.10 2003/10/25 21:51:31 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 "opt_compat_netbsd.h"
50 #include "opt_execfmt.h"
51 #include "opt_multiprocessor.h"
52 #include <machine/asm.h>
53 #include <machine/cpu.h>
54 #include <machine/frame.h>
55 #include "assym.h"
56
57 .text
58 .align 0
59
60 .Lastpending:
61 .word _C_LABEL(astpending)
62 #if defined(COMPAT_15) && defined(EXEC_AOUT)
63 .Lcpufuncs:
64 .word _C_LABEL(cpufuncs)
65 #ifndef MULTIPROCESSOR
66 .Lcurpcb:
67 .word _C_LABEL(curpcb)
68 .Lcpu_info_store:
69 .word _C_LABEL(cpu_info_store)
70 #define GET_CURPCB \
71 ldr r1, .Lcurpcb ;\
72 ldr r1, [r1]
73 #define GET_CPUINFO \
74 ldr r0, .Lcpu_info_store
75 #else
76 .Lcpu_info:
77 .word _C_LABEL(cpu_info)
78 #define GET_CURPCB \
79 ldr r4, .Lcpu_info ;\
80 bl _C_LABEL(cpu_number) ;\
81 ldr r0, [r4, r0, lsl #2] ;\
82 ldr r1, [r0, #CI_CURPCB]
83 #define GET_CPUINFO /* nothing to do */
84 #endif
85 #define ENABLE_ALIGNMENT_FAULTS \
86 GET_CURPCB ;\
87 ldr r1, [r1, #PCB_FLAGS] /* Fetch curpcb->pcb_flags */ ;\
88 tst r1, #PCB_NOALIGNFLT ;\
89 beq 1f /* Alignment faults already enabled */ ;\
90 GET_CPUINFO ;\
91 ldr r2, .Lcpufuncs ;\
92 ldr r1, [r0, #CI_CTRL] /* Fetch control register */ ;\
93 mov r0, #-1 ;\
94 mov lr, pc ;\
95 ldr pc, [r2, #CF_CONTROL] /* Enable alignment faults */ ;\
96 1:
97 #endif /* COMPAT_15 && EXEC_AOUT */
98
99
100 /*
101 * General exception exit handler
102 *
103 * It exits straight away if not returning to USR mode.
104 * This loops around delivering any pending ASTs.
105 * Interrupts are disabled at suitable points to avoid ASTs
106 * being posted between testing and exit to user mode.
107 *
108 * This function uses PULLFRAMEFROMSVCANDEXIT thus should
109 * only be called if the exception handler used PUSHFRAMEINSVC
110 */
111
112 exception_exit:
113 mrs r4, cpsr /* Get CPSR */
114
115 ldr r0, [sp] /* Get the SPSR from stack */
116 and r0, r0, #(PSR_MODE) /* Test for USR32 mode before the AST */
117 teq r0, #(PSR_USR32_MODE)
118 bne .Ldo_exit /* Not USR mode so no AST delivery */
119
120 ldr r5, .Lastpending /* Get address of astpending */
121 #if defined(COMPAT_15) && defined(EXEC_AOUT) && !defined(MULTIPROCESSOR)
122 ldr r6, .Lcurpcb
123 ldr r7, .Lcpu_info_store
124 #endif
125
126 Lexception_exit_loop:
127 orr r0, r4, #(I32_bit) /* Block IRQs */
128 msr cpsr_all, r0
129
130 ldr r1, [r5] /* Do we have an AST pending */
131 teq r1, #0x00000000
132 bne .Ldo_ast
133
134 #if defined(COMPAT_15) && defined(EXEC_AOUT)
135 /* Disable alignment faults for the process, if necessary. */
136 #ifdef MULTIPROCESSOR
137 ldr r7, .Lcpu_info
138 bl _C_LABEL(cpu_number)
139 ldr r7, [r7, r0, lsl #2]
140 ldr r1, [r7, #CI_CURPCB]
141 #else
142 ldr r1, [r6]
143 #endif
144 ldr r1, [r1, #PCB_FLAGS] /* Fetch curpcb->pcb_flags */
145 tst r1, #PCB_NOALIGNFLT
146 beq 1f /* Keep alignment faults enabled */
147 ldr r1, [r7, #CI_CTRL] /* Fetch control register */
148 ldr r2, .Lcpufuncs
149 mov r0, #-1
150 bic r1, r1, #CPU_CONTROL_AFLT_ENABLE /* Disable alignment faults */
151 mov lr, pc
152 ldr pc, [r2, #CF_CONTROL] /* Set the new control register value */
153 1:
154 #endif
155
156 PULLFRAMEFROMSVCANDEXIT /* No AST so exit */
157
158 .Ldo_ast:
159 mov r1, #0x00000000 /* Clear ast pending */
160 str r1, [r5]
161
162 msr cpsr_all, r4 /* Restore interrupts */
163
164 mov r0, sp /* arg 0 = trap frame */
165 bl _C_LABEL(ast) /* call the AST handler */
166 b Lexception_exit_loop /* Try and exit again */
167
168 .Ldo_exit:
169 orr r0, r4, #(I32_bit) /* Disable interrupts */
170 msr cpsr_all, r0
171
172 PULLFRAMEFROMSVCANDEXIT /* Restore the trap frame and exit */
173
174 /*
175 * reset_entry:
176 *
177 * Handler for Reset exception.
178 */
179 ASENTRY_NP(reset_entry)
180 adr r0, Lreset_panicmsg
181 mov r1, lr
182 bl _C_LABEL(panic)
183 /* NOTREACHED */
184 Lreset_panicmsg:
185 .asciz "Reset vector called, LR = 0x%08x"
186 .balign 4
187
188 /*
189 * swi_entry
190 *
191 * Handler for the Software Interrupt exception.
192 */
193 ASENTRY_NP(swi_entry)
194 PUSHFRAME
195
196 #if defined(COMPAT_15) && defined(EXEC_AOUT)
197 ENABLE_ALIGNMENT_FAULTS
198 #endif
199
200 mov r0, sp /* Pass the frame to any function */
201
202 bl _C_LABEL(swi_handler) /* It's a SWI ! */
203
204 ldr r5, .Lastpending /* Get address of astpending */
205 mrs r4, cpsr /* Get CPSR */
206 #if defined(COMPAT_15) && defined(EXEC_AOUT) && !defined(MULTIPROCESSOR)
207 ldr r6, .Lcurpcb
208 ldr r7, .Lcpu_info_store
209 #endif
210
211 .Lswi_exit_loop:
212 orr r0, r4, #(I32_bit) /* Disable IRQs */
213 msr cpsr_all, r0
214
215 ldr r1, [r5] /* Do we have an AST pending */
216 teq r1, #0x00000000
217 bne .Ldo_swi_ast
218
219 #if defined(COMPAT_15) && defined(EXEC_AOUT)
220 /* Disable alignment faults for the process, if necessary. */
221 #ifdef MULTIPROCESSOR
222 ldr r7, .Lcpu_info
223 bl _C_LABEL(cpu_number)
224 ldr r7, [r7, r0, lsl #2]
225 ldr r1, [r7, #CI_CURPCB]
226 #else
227 ldr r1, [r6]
228 #endif
229 ldr r1, [r1, #PCB_FLAGS] /* Fetch curpcb->pcb_flags */
230 tst r1, #PCB_NOALIGNFLT
231 beq 1f /* Keep alignment faults enabled */
232 ldr r1, [r7, #CI_CTRL] /* Fetch control register */
233 ldr r2, .Lcpufuncs
234 mov r0, #-1
235 bic r1, r1, #CPU_CONTROL_AFLT_ENABLE /* Disable alignment faults */
236 mov lr, pc
237 ldr pc, [r2, #CF_CONTROL] /* Set the new control register value */
238 1:
239 #endif
240 PULLFRAME
241 movs pc, lr /* Exit */
242
243 .Ldo_swi_ast:
244 mov r1, #0x00000000 /* Clear ast pending */
245 str r1, [r5]
246
247 msr cpsr_all, r4 /* Restore interrupts */
248
249 mov r0, sp /* arg 0 = trap frame */
250 bl _C_LABEL(ast) /* call the AST handler */
251 b .Lswi_exit_loop /* Try and exit again */
252
253 /*
254 * prefetch_abort_entry:
255 *
256 * Handler for the Prefetch Abort exception.
257 */
258 ASENTRY_NP(prefetch_abort_entry)
259 sub lr, lr, #0x00000004 /* Adjust the lr */
260
261 PUSHFRAMEINSVC
262
263 #if defined(COMPAT_15) && defined(EXEC_AOUT)
264 ENABLE_ALIGNMENT_FAULTS
265 #endif
266
267 mov r0, sp /* pass the stack pointer as r0 */
268
269 adr lr, exception_exit
270 ldr r1, Lprefetch_abort_handler_address
271 ldr pc, [r1]
272
273 Lprefetch_abort_handler_address:
274 .word _C_LABEL(prefetch_abort_handler_address)
275
276 .data
277 .global _C_LABEL(prefetch_abort_handler_address)
278
279 _C_LABEL(prefetch_abort_handler_address):
280 .word abortprefetch
281
282 .text
283 abortprefetch:
284 adr r0, abortprefetchmsg
285 b _C_LABEL(panic)
286
287 abortprefetchmsg:
288 .asciz "abortprefetch"
289 .align 0
290
291 /*
292 * data_abort_entry:
293 *
294 * Handler for the Data Abort exception.
295 */
296 ASENTRY_NP(data_abort_entry)
297 sub lr, lr, #0x00000008 /* Adjust the lr */
298
299 PUSHFRAMEINSVC /* Push trap frame and switch */
300 /* to SVC32 mode */
301
302 #if defined(COMPAT_15) && defined(EXEC_AOUT)
303 and r0, r0, #(PSR_MODE) /* Test for USR32 mode (r0 = spsr_all)*/
304 teq r0, #(PSR_USR32_MODE)
305 bne 99f /* Not USR mode so skip AFLT check */
306 ENABLE_ALIGNMENT_FAULTS
307 99:
308 #endif
309
310 mov r0, sp /* pass the stack pointer as r0 */
311
312 adr lr, exception_exit
313 ldr r1, Ldata_abort_handler_address
314 ldr pc, [r1]
315
316 Ldata_abort_handler_address:
317 .word _C_LABEL(data_abort_handler_address)
318
319 .data
320 .global _C_LABEL(data_abort_handler_address)
321 _C_LABEL(data_abort_handler_address):
322 .word abortdata
323
324 .text
325 abortdata:
326 adr r0, abortdatamsg
327 b _C_LABEL(panic)
328
329 abortdatamsg:
330 .asciz "abortdata"
331 .align 0
332
333 /*
334 * address_exception_entry:
335 *
336 * Handler for the Address Exception exception.
337 *
338 * NOTE: This exception isn't really used on arm32. We
339 * print a warning message to the console and then treat
340 * it like a Data Abort.
341 */
342 ASENTRY_NP(address_exception_entry)
343 mrs r1, cpsr_all
344 mrs r2, spsr_all
345 mov r3, lr
346 adr r0, Laddress_exception_msg
347 bl _C_LABEL(printf) /* XXX CLOBBERS LR!! */
348 b data_abort_entry
349 Laddress_exception_msg:
350 .asciz "Address Exception CPSR=0x%08x SPSR=0x%08x LR=0x%08x\n"
351 .balign 4
352
353 /*
354 * undefined_entry:
355 *
356 * Handler for the Undefined Instruction exception.
357 *
358 * We indirect the undefined vector via the handler address
359 * in the data area. Entry to the undefined handler must
360 * look like direct entry from the vector.
361 */
362 ASENTRY_NP(undefined_entry)
363 #ifdef IPKDB
364 /*
365 * IPKDB must be hooked in at the earliest possible entry point.
366 *
367 */
368 /*
369 * Make room for all registers saving real r0-r7 and r15.
370 * The remaining registers are updated later.
371 */
372 stmfd sp!, {r0,r1} /* psr & spsr */
373 stmfd sp!, {lr} /* pc */
374 stmfd sp!, {r0-r14} /* r0-r7, r8-r14 */
375 /*
376 * Get previous psr.
377 */
378 mrs r7, cpsr_all
379 mrs r0, spsr_all
380 str r0, [sp, #(16*4)]
381 /*
382 * Test for user mode.
383 */
384 tst r0, #0xf
385 bne .Lprenotuser_push
386 add r1, sp, #(8*4)
387 stmia r1,{r8-r14}^ /* store user mode r8-r14*/
388 b .Lgoipkdb
389 /*
390 * Switch to previous mode to get r8-r13.
391 */
392 .Lprenotuser_push:
393 orr r0, r0, #(I32_bit) /* disable interrupts */
394 msr cpsr_all, r0
395 mov r1, r8
396 mov r2, r9
397 mov r3, r10
398 mov r4, r11
399 mov r5, r12
400 mov r6, r13
401 msr cpsr_all, r7 /* back to undefined mode */
402 add r8, sp, #(8*4)
403 stmia r8, {r1-r6} /* r8-r13 */
404 /*
405 * Now back to previous mode to get r14 and spsr.
406 */
407 msr cpsr_all, r0
408 mov r1, r14
409 mrs r2, spsr
410 msr cpsr_all, r7 /* back to undefined mode */
411 str r1, [sp, #(14*4)] /* r14 */
412 str r2, [sp, #(17*4)] /* spsr */
413 /*
414 * Now to IPKDB.
415 */
416 .Lgoipkdb:
417 #if defined(COMPAT_15) && defined(EXEC_AOUT)
418 ENABLE_ALIGNMENT_FAULTS
419 #endif
420 mov r0, sp
421 bl _C_LABEL(ipkdb_trap_glue)
422 ldr r1, .Lipkdb_trap_return
423 str r0,[r1]
424
425 #if defined(COMPAT_15) && defined(EXEC_AOUT)
426 #ifdef MULTIPROCESSOR
427 ldr r7, .Lcpu_info
428 bl _C_LABEL(cpu_number)
429 ldr r7, [r7, r0, lsl #2]
430 ldr r1, [r7, #CI_CURPCB]
431 #else
432 ldr r6, .Lcurpcb
433 ldr r7, .Lcpu_info_store
434 ldr r1, [r6]
435 #endif
436 ldr r1, [r1, #PCB_FLAGS] /* Fetch curpcb->pcb_flags */
437 tst r1, #PCB_NOALIGNFLT
438 beq 1f /* Keep alignment faults enabled */
439 ldr r1, [r7, #CI_CTRL] /* Fetch control register */
440 ldr r2, .Lcpufuncs
441 mov r0, #-1
442 bic r1, r1, #CPU_CONTROL_AFLT_ENABLE /* Disable alignment faults */
443 mov lr, pc
444 ldr pc, [r2, #CF_CONTROL] /* Set the new control register value */
445 1:
446 #endif
447
448 /*
449 * Have to load all registers from the stack.
450 *
451 * Start with spsr and pc.
452 */
453 ldr r0, [sp, #(16*4)] /* spsr */
454 ldr r1, [sp, #(15*4)] /* r15 */
455 msr spsr_all, r0
456 mov r14, r1
457 /*
458 * Test for user mode.
459 */
460 tst r0, #0xf
461 bne .Lprenotuser_pull
462 add r1, sp, #(8*4)
463 ldmia r1, {r8-r14}^ /* load user mode r8-r14 */
464 b .Lpull_r0r7
465 .Lprenotuser_pull:
466 /*
467 * Now previous mode spsr and r14.
468 */
469 ldr r1, [sp, #(17*4)] /* spsr */
470 ldr r2, [sp, #(14*4)] /* r14 */
471 orr r0, r0, #(I32_bit)
472 msr cpsr_all, r0 /* switch to previous mode */
473 msr spsr_all, r1
474 mov r14, r2
475 msr cpsr_all, r7 /* back to undefined mode */
476 /*
477 * Now r8-r13.
478 */
479 add r8, sp, #(8*4)
480 ldmia r8, {r1-r6} /* r8-r13 */
481 msr cpsr_all, r0
482 mov r8, r1
483 mov r9, r2
484 mov r10, r3
485 mov r11, r4
486 mov r12, r5
487 mov r13, r6
488 msr cpsr_all, r7
489 .Lpull_r0r7:
490 /*
491 * Now the rest of the registers.
492 */
493 ldr r1,Lipkdb_trap_return
494 ldr r0,[r1]
495 tst r0,r0
496 ldmfd sp!, {r0-r7} /* r0-r7 */
497 add sp, sp, #(10*4) /* adjust sp */
498
499 /*
500 * Did IPKDB handle it?
501 */
502 movnes pc, lr /* return */
503
504 #endif
505 stmfd sp!, {r0, r1}
506 ldr r0, Lundefined_handler_indirection
507 ldr r1, [sp], #0x0004
508 str r1, [r0, #0x0000]
509 ldr r1, [sp], #0x0004
510 str r1, [r0, #0x0004]
511 ldmia r0, {r0, r1, pc}
512
513 #ifdef IPKDB
514 Lipkdb_trap_return:
515 .word Lipkdb_trap_return_data
516 #endif
517
518 Lundefined_handler_indirection:
519 .word Lundefined_handler_indirection_data
520
521 /*
522 * assembly bounce code for calling the kernel
523 * undefined instruction handler. This uses
524 * a standard trap frame and is called in SVC mode.
525 */
526
527 ENTRY_NP(undefinedinstruction_bounce)
528 PUSHFRAMEINSVC
529 #if defined(COMPAT_15) && defined(EXEC_AOUT)
530 and r0, r0, #(PSR_MODE) /* Test for USR32 mode (r0 = spsr_all)*/
531 teq r0, #(PSR_USR32_MODE)
532 bne 99f /* Not USR mode so skip AFLT check */
533 ENABLE_ALIGNMENT_FAULTS
534 99:
535 #endif
536 mov r0, sp
537 bl _C_LABEL(undefinedinstruction)
538
539 b exception_exit
540
541 .data
542 .align 0
543
544 #ifdef IPKDB
545 Lipkdb_trap_return_data:
546 .word 0
547 #endif
548
549 /*
550 * Indirection data
551 * 2 words use for preserving r0 and r1
552 * 3rd word contains the undefined handler address.
553 */
554
555 Lundefined_handler_indirection_data:
556 .word 0
557 .word 0
558
559 .global _C_LABEL(undefined_handler_address)
560 _C_LABEL(undefined_handler_address):
561 .word _C_LABEL(undefinedinstruction_bounce)
562