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