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