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