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