1129198Scognet/* $NetBSD: exception.S,v 1.13 2003/10/31 16:30:15 scw Exp $ */ 2129198Scognet 3139735Simp/*- 4129198Scognet * Copyright (c) 1994-1997 Mark Brinicombe. 5129198Scognet * Copyright (c) 1994 Brini. 6129198Scognet * All rights reserved. 7129198Scognet * 8129198Scognet * This code is derived from software written for Brini by Mark Brinicombe 9129198Scognet * 10129198Scognet * Redistribution and use in source and binary forms, with or without 11129198Scognet * modification, are permitted provided that the following conditions 12129198Scognet * are met: 13129198Scognet * 1. Redistributions of source code must retain the above copyright 14129198Scognet * notice, this list of conditions and the following disclaimer. 15129198Scognet * 2. Redistributions in binary form must reproduce the above copyright 16129198Scognet * notice, this list of conditions and the following disclaimer in the 17129198Scognet * documentation and/or other materials provided with the distribution. 18129198Scognet * 3. All advertising materials mentioning features or use of this software 19129198Scognet * must display the following acknowledgement: 20129198Scognet * This product includes software developed by Brini. 21129198Scognet * 4. The name of the company nor the name of the author may be used to 22129198Scognet * endorse or promote products derived from this software without specific 23129198Scognet * prior written permission. 24129198Scognet * 25129198Scognet * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED 26129198Scognet * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 27129198Scognet * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 28129198Scognet * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 29129198Scognet * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 30129198Scognet * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31129198Scognet * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32129198Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33129198Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34129198Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35129198Scognet * SUCH DAMAGE. 36129198Scognet * 37129198Scognet * RiscBSD kernel project 38129198Scognet * 39129198Scognet * exception.S 40129198Scognet * 41129198Scognet * Low level handlers for exception vectors 42129198Scognet * 43129198Scognet * Created : 24/09/94 44129198Scognet * 45129198Scognet * Based on kate/display/abort.s 46129198Scognet * 47129198Scognet */ 48129198Scognet 49129198Scognet#include "assym.s" 50129198Scognet 51129198Scognet#include <machine/asm.h> 52129198Scognet#include <machine/armreg.h> 53129198Scognet#include <machine/asmacros.h> 54291852Sandrew#include <machine/trap.h> 55291852Sandrew 56129198Scognet__FBSDID("$FreeBSD$"); 57129198Scognet 58278529Sgnn#ifdef KDTRACE_HOOKS 59278529Sgnn .bss 60278529Sgnn .align 4 61291852Sandrew .global _C_LABEL(dtrace_invop_jump_addr) 62291852Sandrew_C_LABEL(dtrace_invop_jump_addr): 63278529Sgnn .word 0 64278529Sgnn .word 0 65278529Sgnn#endif 66278529Sgnn 67283366Sandrew .text 68276596Sian .align 2 69129198Scognet 70129198Scognet/* 71262997Sian * ASM macros for pushing and pulling trapframes from the stack 72262997Sian * 73262997Sian * These macros are used to handle the irqframe and trapframe structures 74262997Sian * defined above. 75262997Sian */ 76262997Sian 77262997Sian/* 78262997Sian * PUSHFRAME - macro to push a trap frame on the stack in the current mode 79262997Sian * Since the current mode is used, the SVC lr field is not defined. 80262997Sian * 81262997Sian * NOTE: r13 and r14 are stored separately as a work around for the 82262997Sian * SA110 rev 2 STM^ bug 83262997Sian */ 84284115Sandrew#if __ARM_ARCH < 6 85262997Sian#define PUSHFRAME \ 86262997Sian sub sp, sp, #4; /* Align the stack */ \ 87262997Sian str lr, [sp, #-4]!; /* Push the return address */ \ 88262997Sian sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 89262997Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 90262997Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 91262997Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 92263033Sian mov r0, r0; /* NOP for previous instruction */ \ 93262997Sian mrs r0, spsr; /* Put the SPSR on the stack */ \ 94262997Sian str r0, [sp, #-4]!; \ 95262997Sian ldr r0, =ARM_RAS_START; \ 96262997Sian mov r1, #0; \ 97262997Sian str r1, [r0]; \ 98262997Sian mov r1, #0xffffffff; \ 99262997Sian str r1, [r0, #4]; 100262997Sian#else 101262997Sian#define PUSHFRAME \ 102262997Sian sub sp, sp, #4; /* Align the stack */ \ 103262997Sian str lr, [sp, #-4]!; /* Push the return address */ \ 104262997Sian sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 105262997Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 106262997Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 107262997Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 108263033Sian mov r0, r0; /* NOP for previous instruction */ \ 109262997Sian mrs r0, spsr; /* Put the SPSR on the stack */ \ 110262997Sian str r0, [sp, #-4]!; 111262997Sian#endif 112262997Sian 113262997Sian/* 114262997Sian * PULLFRAME - macro to pull a trap frame from the stack in the current mode 115262997Sian * Since the current mode is used, the SVC lr field is ignored. 116262997Sian */ 117262997Sian 118284115Sandrew#if __ARM_ARCH < 6 119262997Sian#define PULLFRAME \ 120263033Sian ldr r0, [sp], #4; /* Get the SPSR from stack */ \ 121263033Sian msr spsr_fsxc, r0; \ 122263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 123263033Sian mov r0, r0; /* NOP for previous instruction */ \ 124262997Sian add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 125263033Sian ldr lr, [sp], #4; /* Pull the return address */ \ 126262997Sian add sp, sp, #4 /* Align the stack */ 127283366Sandrew#else 128262997Sian#define PULLFRAME \ 129263033Sian ldr r0, [sp], #4 ; /* Get the SPSR from stack */ \ 130263033Sian msr spsr_fsxc, r0; \ 131262997Sian clrex; \ 132263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 133263033Sian mov r0, r0; /* NOP for previous instruction */ \ 134262997Sian add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 135263033Sian ldr lr, [sp], #4; /* Pull the return address */ \ 136262997Sian add sp, sp, #4 /* Align the stack */ 137262997Sian#endif 138262997Sian 139262997Sian/* 140262987Sian * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 141262987Sian * This should only be used if the processor is not currently in SVC32 142262987Sian * mode. The processor mode is switched to SVC mode and the trap frame is 143262987Sian * stored. The SVC lr field is used to store the previous value of 144262987Sian * lr in SVC mode. 145262987Sian * 146262987Sian * NOTE: r13 and r14 are stored separately as a work around for the 147262987Sian * SA110 rev 2 STM^ bug 148262987Sian */ 149284115Sandrew#if __ARM_ARCH < 6 150262987Sian#define PUSHFRAMEINSVC \ 151262987Sian stmdb sp, {r0-r3}; /* Save 4 registers */ \ 152262987Sian mov r0, lr; /* Save xxx32 r14 */ \ 153262987Sian mov r1, sp; /* Save xxx32 sp */ \ 154262987Sian mrs r3, spsr; /* Save xxx32 spsr */ \ 155263033Sian mrs r2, cpsr; /* Get the CPSR */ \ 156263033Sian bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 157263033Sian orr r2, r2, #(PSR_SVC32_MODE); \ 158263033Sian msr cpsr_c, r2; /* Punch into SVC mode */ \ 159262987Sian mov r2, sp; /* Save SVC sp */ \ 160262987Sian bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 161279667Sandrew sub sp, sp, #(4 * 17); /* Pad trapframe to keep alignment */ \ 162279667Sandrew /* and for dtrace to emulate push/pop */ \ 163262987Sian str r0, [sp, #-4]!; /* Push return address */ \ 164262987Sian str lr, [sp, #-4]!; /* Push SVC lr */ \ 165262987Sian str r2, [sp, #-4]!; /* Push SVC sp */ \ 166263033Sian msr spsr_fsxc, r3; /* Restore correct spsr */ \ 167262987Sian ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 168262987Sian sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 169262987Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 170262987Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 171262987Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 172263033Sian mov r0, r0; /* NOP for previous instruction */ \ 173262987Sian ldr r5, =ARM_RAS_START; /* Check if there's any RAS */ \ 174263033Sian ldr r4, [r5, #4]; /* reset it to point at the */ \ 175263033Sian cmp r4, #0xffffffff; /* end of memory if necessary; */ \ 176263033Sian movne r1, #0xffffffff; /* leave value in r4 for later */ \ 177299069Spfg strne r1, [r5, #4]; /* comparison against PC. */ \ 178263033Sian ldr r3, [r5]; /* Retrieve global RAS_START */ \ 179263033Sian cmp r3, #0; /* and reset it if non-zero. */ \ 180263033Sian movne r1, #0; /* If non-zero RAS_START and */ \ 181263033Sian strne r1, [r5]; /* PC was lower than RAS_END, */ \ 182263033Sian ldrne r1, [r0, #16]; /* adjust the saved PC so that */ \ 183263033Sian cmpne r4, r1; /* execution later resumes at */ \ 184263033Sian strhi r3, [r0, #16]; /* the RAS_START location. */ \ 185263033Sian mrs r0, spsr; \ 186263033Sian str r0, [sp, #-4]! 187262987Sian#else 188262987Sian#define PUSHFRAMEINSVC \ 189262987Sian stmdb sp, {r0-r3}; /* Save 4 registers */ \ 190262987Sian mov r0, lr; /* Save xxx32 r14 */ \ 191262987Sian mov r1, sp; /* Save xxx32 sp */ \ 192262987Sian mrs r3, spsr; /* Save xxx32 spsr */ \ 193263033Sian mrs r2, cpsr; /* Get the CPSR */ \ 194263033Sian bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 195263033Sian orr r2, r2, #(PSR_SVC32_MODE); \ 196263033Sian msr cpsr_c, r2; /* Punch into SVC mode */ \ 197262987Sian mov r2, sp; /* Save SVC sp */ \ 198262987Sian bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 199279667Sandrew sub sp, sp, #(4 * 17); /* Pad trapframe to keep alignment */ \ 200279667Sandrew /* and for dtrace to emulate push/pop */ \ 201262987Sian str r0, [sp, #-4]!; /* Push return address */ \ 202262987Sian str lr, [sp, #-4]!; /* Push SVC lr */ \ 203262987Sian str r2, [sp, #-4]!; /* Push SVC sp */ \ 204263033Sian msr spsr_fsxc, r3; /* Restore correct spsr */ \ 205262987Sian ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 206262987Sian sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 207262987Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 208262987Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 209262987Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 210263033Sian mov r0, r0; /* NOP for previous instruction */ \ 211262987Sian mrs r0, spsr; /* Put the SPSR on the stack */ \ 212262987Sian str r0, [sp, #-4]! 213262987Sian#endif 214262987Sian 215262987Sian/* 216262987Sian * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 217262987Sian * in SVC32 mode and restore the saved processor mode and PC. 218262987Sian * This should be used when the SVC lr register needs to be restored on 219262987Sian * exit. 220262987Sian */ 221262987Sian 222284115Sandrew#if __ARM_ARCH < 6 223262987Sian#define PULLFRAMEFROMSVCANDEXIT \ 224263033Sian ldr r0, [sp], #4; /* Get the SPSR from stack */ \ 225263033Sian msr spsr_fsxc, r0; /* restore SPSR */ \ 226263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 227263033Sian mov r0, r0; /* NOP for previous instruction */ \ 228262987Sian add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 229262987Sian ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 230283366Sandrew#else 231262987Sian#define PULLFRAMEFROMSVCANDEXIT \ 232263033Sian ldr r0, [sp], #4; /* Get the SPSR from stack */ \ 233263033Sian msr spsr_fsxc, r0; /* restore SPSR */ \ 234262987Sian clrex; \ 235263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 236263033Sian mov r0, r0; /* NOP for previous instruction */ \ 237262987Sian add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 238262987Sian ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 239262987Sian#endif 240262987Sian 241262987Sian/* 242262987Sian * Unwind hints so we can unwind past functions that use 243262987Sian * PULLFRAMEFROMSVCANDEXIT. They are run in reverse order. 244262987Sian * As the last thing we do is restore the stack pointer 245262987Sian * we can ignore the padding at the end of struct trapframe. 246262987Sian */ 247262987Sian#define UNWINDSVCFRAME \ 248262987Sian .save {r13-r15}; /* Restore sp, lr, pc */ \ 249262987Sian .pad #(2*4); /* Skip user sp and lr */ \ 250262987Sian .save {r0-r12}; /* Restore r0-r12 */ \ 251262987Sian .pad #(4) /* Skip spsr */ 252262987Sian 253276196Sian#define DO_AST \ 254276196Sian ldr r0, [sp]; /* Get the SPSR from stack */ \ 255276196Sian mrs r4, cpsr; /* save CPSR */ \ 256276196Sian orr r1, r4, #(PSR_I|PSR_F); \ 257276196Sian msr cpsr_c, r1; /* Disable interrupts */ \ 258276196Sian and r0, r0, #(PSR_MODE); /* Returning to USR mode? */ \ 259276196Sian teq r0, #(PSR_USR32_MODE); \ 260276196Sian bne 2f; /* Nope, get out now */ \ 261276196Sian bic r4, r4, #(PSR_I|PSR_F); \ 262276196Sian1: GET_CURTHREAD_PTR(r5); \ 263276196Sian ldr r1, [r5, #(TD_FLAGS)]; \ 264276196Sian and r1, r1, #(TDF_ASTPENDING|TDF_NEEDRESCHED); \ 265276196Sian teq r1, #0; \ 266276196Sian beq 2f; /* Nope. Just bail */ \ 267276196Sian msr cpsr_c, r4; /* Restore interrupts */ \ 268276196Sian mov r0, sp; \ 269276196Sian bl _C_LABEL(ast); /* ast(frame) */ \ 270276196Sian orr r0, r4, #(PSR_I|PSR_F); \ 271276196Sian msr cpsr_c, r0; \ 272276197Sian b 1b; \ 273262987Sian2: 274262987Sian 275262987Sian 276262987Sian/* 277263033Sian * Entry point for a Software Interrupt (SWI). 278129198Scognet * 279263033Sian * The hardware switches to svc32 mode on a swi, so we're already on the 280263033Sian * right stack; just build a trapframe and call the handler. 281129198Scognet */ 282129198ScognetASENTRY_NP(swi_entry) 283263033Sian PUSHFRAME /* Build the trapframe on the */ 284263033Sian mov r0, sp /* scv32 stack, pass it to the */ 285263033Sian bl _C_LABEL(swi_handler) /* swi handler. */ 286262987Sian /* 287262987Sian * The fork_trampoline() code in swtch.S aranges for the MI fork_exit() 288262987Sian * to return to swi_exit here, to return to userland. The net effect is 289262987Sian * that a newly created thread appears to return from a SWI just like 290262987Sian * the parent thread that created it. 291262987Sian */ 292269390SianASEENTRY_NP(swi_exit) 293263033Sian DO_AST /* Handle pending signals. */ 294263033Sian PULLFRAME /* Deallocate trapframe. */ 295263033Sian movs pc, lr /* Return to userland. */ 296263033Sian STOP_UNWINDING /* Don't unwind into user mode. */ 297269390SianEEND(swi_exit) 298248361SandrewEND(swi_entry) 299129198Scognet 300129198Scognet/* 301263033Sian * Standard exception exit handler. 302129198Scognet * 303263033Sian * This is used to return from all exceptions except SWI. It uses DO_AST and 304263033Sian * PULLFRAMEFROMSVCANDEXIT and can only be called if the exception entry code 305263033Sian * used PUSHFRAMEINSVC. 306263033Sian * 307263033Sian * If the return is to user mode, this uses DO_AST to deliver any pending 308263033Sian * signals and/or handle TDF_NEEDRESCHED first. 309129198Scognet */ 310263033SianASENTRY_NP(exception_exit) 311263033Sian DO_AST /* Handle pending signals. */ 312263033Sian PULLFRAMEFROMSVCANDEXIT /* Return. */ 313263033Sian UNWINDSVCFRAME /* Special unwinding for exceptions. */ 314263033SianEND(exception_exit) 315263033Sian 316263033Sian/* 317263033Sian * Entry point for a Prefetch Abort exception. 318263033Sian * 319263033Sian * The hardware switches to the abort mode stack; we switch to svc32 before 320283366Sandrew * calling the handler, then return directly to the original mode/stack 321263033Sian * on exit (without transitioning back through the abort mode stack). 322263033Sian */ 323129198ScognetASENTRY_NP(prefetch_abort_entry) 324129198Scognet#ifdef __XSCALE__ 325129198Scognet nop /* Make absolutely sure any pending */ 326129198Scognet nop /* imprecise aborts have occurred. */ 327129198Scognet#endif 328263033Sian sub lr, lr, #4 /* Adjust the lr. Transition to scv32 */ 329263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 330263033Sian adr lr, exception_exit /* Return from handler via standard */ 331263033Sian mov r0, sp /* exception exit routine. Pass the */ 332276206Sian mov r1, #1 /* Type flag */ 333276206Sian b _C_LABEL(abort_handler) 334248361SandrewEND(prefetch_abort_entry) 335129198Scognet 336129198Scognet/* 337263033Sian * Entry point for a Data Abort exception. 338129198Scognet * 339263033Sian * The hardware switches to the abort mode stack; we switch to svc32 before 340283366Sandrew * calling the handler, then return directly to the original mode/stack 341263033Sian * on exit (without transitioning back through the abort mode stack). 342129198Scognet */ 343129198ScognetASENTRY_NP(data_abort_entry) 344129198Scognet#ifdef __XSCALE__ 345129198Scognet nop /* Make absolutely sure any pending */ 346129198Scognet nop /* imprecise aborts have occurred. */ 347129198Scognet#endif 348263033Sian sub lr, lr, #8 /* Adjust the lr. Transition to scv32 */ 349263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 350276206Sian adr lr, exception_exit /* Exception exit routine */ 351276206Sian mov r0, sp /* Trapframe to the handler */ 352276206Sian mov r1, #0 /* Type flag */ 353276206Sian b _C_LABEL(abort_handler) 354248361SandrewEND(data_abort_entry) 355129198Scognet 356129198Scognet/* 357263033Sian * Entry point for an Undefined Instruction exception. 358129198Scognet * 359263033Sian * The hardware switches to the undefined mode stack; we switch to svc32 before 360283366Sandrew * calling the handler, then return directly to the original mode/stack 361263033Sian * on exit (without transitioning back through the undefined mode stack). 362129198Scognet */ 363263033SianASENTRY_NP(undefined_entry) 364263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 365291852Sandrew mov r4, r0 /* R0 contains SPSR */ 366263033Sian adr lr, exception_exit /* Return from handler via standard */ 367291852Sandrew mov r0, sp /* exception exit routine. pass frame */ 368291852Sandrew 369291852Sandrew ldr r2, [sp, #(TF_PC)] /* load pc */ 370291852Sandrew#if __ARM_ARCH >= 7 371291852Sandrew tst r4, #(PSR_T) /* test if PSR_T */ 372291852Sandrew subne r2, r2, #(THUMB_INSN_SIZE) 373291852Sandrew subeq r2, r2, #(INSN_SIZE) 374291852Sandrew#else 375291852Sandrew sub r2, r2, #(INSN_SIZE) /* fix pc */ 376291852Sandrew#endif 377291852Sandrew str r2, [sp, #TF_PC] /* store pc */ 378291852Sandrew 379291852Sandrew#ifdef KDTRACE_HOOKS 380291852Sandrew /* Check if dtrace is enabled */ 381291852Sandrew ldr r1, =_C_LABEL(dtrace_invop_jump_addr) 382291852Sandrew ldr r3, [r1] 383291852Sandrew cmp r3, #0 384291852Sandrew beq undefinedinstruction 385291852Sandrew 386291852Sandrew and r4, r4, #(PSR_MODE) /* Mask out unneeded bits */ 387291852Sandrew cmp r4, #(PSR_USR32_MODE) /* Check if we came from usermode */ 388291852Sandrew beq undefinedinstruction 389291852Sandrew 390291852Sandrew ldr r4, [r2] /* load instrution */ 391291852Sandrew ldr r1, =FBT_BREAKPOINT /* load fbt inv op */ 392291852Sandrew cmp r1, r4 393291852Sandrew bne undefinedinstruction 394291852Sandrew 395291852Sandrew bx r3 /* call invop_jump_addr */ 396291852Sandrew#endif 397291852Sandrew b undefinedinstruction /* call stadnard handler */ 398263033SianEND(undefined_entry) 399129198Scognet 400129198Scognet/* 401263033Sian * Entry point for a normal IRQ. 402129198Scognet * 403263033Sian * The hardware switches to the IRQ mode stack; we switch to svc32 before 404283366Sandrew * calling the handler, then return directly to the original mode/stack 405263033Sian * on exit (without transitioning back through the IRQ mode stack). 406129198Scognet */ 407262979SianASENTRY_NP(irq_entry) 408263033Sian sub lr, lr, #4 /* Adjust the lr. Transition to scv32 */ 409263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 410263033Sian adr lr, exception_exit /* Return from handler via standard */ 411263033Sian mov r0, sp /* exception exit routine. Pass the */ 412292426Sadrian b _C_LABEL(intr_irq_handler)/* trapframe to the handler. */ 413283366SandrewEND(irq_entry) 414262979Sian 415129198Scognet/* 416263033Sian * Entry point for an FIQ interrupt. 417129198Scognet * 418283366Sandrew * We don't currently support FIQ handlers very much. Something can 419262980Sian * install itself in the FIQ vector using code (that may or may not work 420262980Sian * these days) in fiq.c. If nobody does that and an FIQ happens, this 421262980Sian * default handler just disables FIQs and otherwise ignores it. 422262980Sian */ 423262980SianASENTRY_NP(fiq_entry) 424262980Sian mrs r8, cpsr /* FIQ handling isn't supported, */ 425271398Sandrew bic r8, #(PSR_F) /* just disable FIQ and return. */ 426262980Sian msr cpsr_c, r8 /* The r8 we trash here is the */ 427262980Sian subs pc, lr, #4 /* banked FIQ-mode r8. */ 428262980SianEND(fiq_entry) 429262980Sian 430262980Sian/* 431263033Sian * Entry point for an Address Exception exception. 432263033Sian * This is an arm26 exception that should never happen. 433263033Sian */ 434263033SianASENTRY_NP(addr_exception_entry) 435263034Sian mov r3, lr 436263034Sian mrs r2, spsr 437263033Sian mrs r1, cpsr 438263033Sian adr r0, Laddr_exception_msg 439263034Sian b _C_LABEL(panic) 440263033SianLaddr_exception_msg: 441263033Sian .asciz "Address Exception CPSR=0x%08x SPSR=0x%08x LR=0x%08x\n" 442263033Sian .balign 4 443263033SianEND(addr_exception_entry) 444263033Sian 445263033Sian/* 446283366Sandrew * Entry point for the system Reset vector. 447263033Sian * This should never happen, so panic. 448263033Sian */ 449263033SianASENTRY_NP(reset_entry) 450263034Sian mov r1, lr 451263033Sian adr r0, Lreset_panicmsg 452263034Sian b _C_LABEL(panic) 453263033Sian /* NOTREACHED */ 454263033SianLreset_panicmsg: 455263033Sian .asciz "Reset vector called, LR = 0x%08x" 456263033Sian .balign 4 457263033SianEND(reset_entry) 458263033Sian 459263033Sian/* 460262980Sian * page0 and page0_data -- An image of the ARM vectors which is copied to 461262980Sian * the ARM vectors page (high or low) as part of CPU initialization. The 462262980Sian * code that does the copy assumes that page0_data holds one 32-bit word 463262980Sian * of data for each of the predefined ARM vectors. It also assumes that 464283366Sandrew * page0_data follows the vectors in page0, but other stuff can appear 465283366Sandrew * between the two. We currently leave room between the two for some fiq 466262980Sian * handler code to be copied in. 467262980Sian */ 468262980Sian .global _C_LABEL(page0), _C_LABEL(page0_data) 469262980Sian 470262980Sian_C_LABEL(page0): 471262980Sian ldr pc, .Lreset_entry 472262980Sian ldr pc, .Lundefined_entry 473262980Sian ldr pc, .Lswi_entry 474262980Sian ldr pc, .Lprefetch_abort_entry 475262980Sian ldr pc, .Ldata_abort_entry 476262980Sian ldr pc, .Laddr_exception_entry 477262980Sian ldr pc, .Lirq_entry 478262980Sian.fiqv: ldr pc, .Lfiq_entry 479262980Sian .space 256 /* room for some fiq handler code */ 480262980Sian 481262980Sian_C_LABEL(page0_data): 482262980Sian.Lreset_entry: .word reset_entry 483262980Sian.Lundefined_entry: .word undefined_entry 484262980Sian.Lswi_entry: .word swi_entry 485262980Sian.Lprefetch_abort_entry: .word prefetch_abort_entry 486262980Sian.Ldata_abort_entry: .word data_abort_entry 487262980Sian.Laddr_exception_entry: .word addr_exception_entry 488262980Sian.Lirq_entry: .word irq_entry 489262980Sian.Lfiq_entry: .word fiq_entry 490262980Sian 491262980Sian/* 492262980Sian * These items are used by the code in fiq.c to install what it calls the 493262980Sian * "null" handler. It's actually our default vector entry that just jumps 494262980Sian * to the default handler which just disables FIQs and returns. 495262980Sian */ 496262980Sian .global _C_LABEL(fiq_nullhandler_code), _C_LABEL(fiq_nullhandler_size) 497262980Sian 498262980Sian_C_LABEL(fiq_nullhandler_code): 499262980Sian .word .fiqv 500262980Sian_C_LABEL(fiq_nullhandler_size): 501262980Sian .word 4 502262980Sian 503262980Sian 504