exception.S revision 299069
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 51284115Sandrew#include <machine/acle-compat.h> 52129198Scognet#include <machine/asm.h> 53129198Scognet#include <machine/armreg.h> 54129198Scognet#include <machine/asmacros.h> 55291852Sandrew#include <machine/trap.h> 56291852Sandrew 57129198Scognet__FBSDID("$FreeBSD: head/sys/arm/arm/exception.S 299069 2016-05-04 15:48:59Z pfg $"); 58129198Scognet 59278529Sgnn#ifdef KDTRACE_HOOKS 60278529Sgnn .bss 61278529Sgnn .align 4 62291852Sandrew .global _C_LABEL(dtrace_invop_jump_addr) 63291852Sandrew_C_LABEL(dtrace_invop_jump_addr): 64278529Sgnn .word 0 65278529Sgnn .word 0 66278529Sgnn#endif 67278529Sgnn 68283366Sandrew .text 69276596Sian .align 2 70129198Scognet 71129198Scognet/* 72262997Sian * ASM macros for pushing and pulling trapframes from the stack 73262997Sian * 74262997Sian * These macros are used to handle the irqframe and trapframe structures 75262997Sian * defined above. 76262997Sian */ 77262997Sian 78262997Sian/* 79262997Sian * PUSHFRAME - macro to push a trap frame on the stack in the current mode 80262997Sian * Since the current mode is used, the SVC lr field is not defined. 81262997Sian * 82262997Sian * NOTE: r13 and r14 are stored separately as a work around for the 83262997Sian * SA110 rev 2 STM^ bug 84262997Sian */ 85284115Sandrew#if __ARM_ARCH < 6 86262997Sian#define PUSHFRAME \ 87262997Sian sub sp, sp, #4; /* Align the stack */ \ 88262997Sian str lr, [sp, #-4]!; /* Push the return address */ \ 89262997Sian sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 90262997Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 91262997Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 92262997Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 93263033Sian mov r0, r0; /* NOP for previous instruction */ \ 94262997Sian mrs r0, spsr; /* Put the SPSR on the stack */ \ 95262997Sian str r0, [sp, #-4]!; \ 96262997Sian ldr r0, =ARM_RAS_START; \ 97262997Sian mov r1, #0; \ 98262997Sian str r1, [r0]; \ 99262997Sian mov r1, #0xffffffff; \ 100262997Sian str r1, [r0, #4]; 101262997Sian#else 102262997Sian#define PUSHFRAME \ 103262997Sian sub sp, sp, #4; /* Align the stack */ \ 104262997Sian str lr, [sp, #-4]!; /* Push the return address */ \ 105262997Sian sub sp, sp, #(4*17); /* Adjust the stack pointer */ \ 106262997Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 107262997Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 108262997Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 109263033Sian mov r0, r0; /* NOP for previous instruction */ \ 110262997Sian mrs r0, spsr; /* Put the SPSR on the stack */ \ 111262997Sian str r0, [sp, #-4]!; 112262997Sian#endif 113262997Sian 114262997Sian/* 115262997Sian * PULLFRAME - macro to pull a trap frame from the stack in the current mode 116262997Sian * Since the current mode is used, the SVC lr field is ignored. 117262997Sian */ 118262997Sian 119284115Sandrew#if __ARM_ARCH < 6 120262997Sian#define PULLFRAME \ 121263033Sian ldr r0, [sp], #4; /* Get the SPSR from stack */ \ 122263033Sian msr spsr_fsxc, r0; \ 123263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 124263033Sian mov r0, r0; /* NOP for previous instruction */ \ 125262997Sian add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 126263033Sian ldr lr, [sp], #4; /* Pull the return address */ \ 127262997Sian add sp, sp, #4 /* Align the stack */ 128283366Sandrew#else 129262997Sian#define PULLFRAME \ 130263033Sian ldr r0, [sp], #4 ; /* Get the SPSR from stack */ \ 131263033Sian msr spsr_fsxc, r0; \ 132262997Sian clrex; \ 133263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 134263033Sian mov r0, r0; /* NOP for previous instruction */ \ 135262997Sian add sp, sp, #(4*17); /* Adjust the stack pointer */ \ 136263033Sian ldr lr, [sp], #4; /* Pull the return address */ \ 137262997Sian add sp, sp, #4 /* Align the stack */ 138262997Sian#endif 139262997Sian 140262997Sian/* 141262987Sian * PUSHFRAMEINSVC - macro to push a trap frame on the stack in SVC32 mode 142262987Sian * This should only be used if the processor is not currently in SVC32 143262987Sian * mode. The processor mode is switched to SVC mode and the trap frame is 144262987Sian * stored. The SVC lr field is used to store the previous value of 145262987Sian * lr in SVC mode. 146262987Sian * 147262987Sian * NOTE: r13 and r14 are stored separately as a work around for the 148262987Sian * SA110 rev 2 STM^ bug 149262987Sian */ 150284115Sandrew#if __ARM_ARCH < 6 151262987Sian#define PUSHFRAMEINSVC \ 152262987Sian stmdb sp, {r0-r3}; /* Save 4 registers */ \ 153262987Sian mov r0, lr; /* Save xxx32 r14 */ \ 154262987Sian mov r1, sp; /* Save xxx32 sp */ \ 155262987Sian mrs r3, spsr; /* Save xxx32 spsr */ \ 156263033Sian mrs r2, cpsr; /* Get the CPSR */ \ 157263033Sian bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 158263033Sian orr r2, r2, #(PSR_SVC32_MODE); \ 159263033Sian msr cpsr_c, r2; /* Punch into SVC mode */ \ 160262987Sian mov r2, sp; /* Save SVC sp */ \ 161262987Sian bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 162279667Sandrew sub sp, sp, #(4 * 17); /* Pad trapframe to keep alignment */ \ 163279667Sandrew /* and for dtrace to emulate push/pop */ \ 164262987Sian str r0, [sp, #-4]!; /* Push return address */ \ 165262987Sian str lr, [sp, #-4]!; /* Push SVC lr */ \ 166262987Sian str r2, [sp, #-4]!; /* Push SVC sp */ \ 167263033Sian msr spsr_fsxc, r3; /* Restore correct spsr */ \ 168262987Sian ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 169262987Sian sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 170262987Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 171262987Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 172262987Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 173263033Sian mov r0, r0; /* NOP for previous instruction */ \ 174262987Sian ldr r5, =ARM_RAS_START; /* Check if there's any RAS */ \ 175263033Sian ldr r4, [r5, #4]; /* reset it to point at the */ \ 176263033Sian cmp r4, #0xffffffff; /* end of memory if necessary; */ \ 177263033Sian movne r1, #0xffffffff; /* leave value in r4 for later */ \ 178299069Spfg strne r1, [r5, #4]; /* comparison against PC. */ \ 179263033Sian ldr r3, [r5]; /* Retrieve global RAS_START */ \ 180263033Sian cmp r3, #0; /* and reset it if non-zero. */ \ 181263033Sian movne r1, #0; /* If non-zero RAS_START and */ \ 182263033Sian strne r1, [r5]; /* PC was lower than RAS_END, */ \ 183263033Sian ldrne r1, [r0, #16]; /* adjust the saved PC so that */ \ 184263033Sian cmpne r4, r1; /* execution later resumes at */ \ 185263033Sian strhi r3, [r0, #16]; /* the RAS_START location. */ \ 186263033Sian mrs r0, spsr; \ 187263033Sian str r0, [sp, #-4]! 188262987Sian#else 189262987Sian#define PUSHFRAMEINSVC \ 190262987Sian stmdb sp, {r0-r3}; /* Save 4 registers */ \ 191262987Sian mov r0, lr; /* Save xxx32 r14 */ \ 192262987Sian mov r1, sp; /* Save xxx32 sp */ \ 193262987Sian mrs r3, spsr; /* Save xxx32 spsr */ \ 194263033Sian mrs r2, cpsr; /* Get the CPSR */ \ 195263033Sian bic r2, r2, #(PSR_MODE); /* Fix for SVC mode */ \ 196263033Sian orr r2, r2, #(PSR_SVC32_MODE); \ 197263033Sian msr cpsr_c, r2; /* Punch into SVC mode */ \ 198262987Sian mov r2, sp; /* Save SVC sp */ \ 199262987Sian bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ 200279667Sandrew sub sp, sp, #(4 * 17); /* Pad trapframe to keep alignment */ \ 201279667Sandrew /* and for dtrace to emulate push/pop */ \ 202262987Sian str r0, [sp, #-4]!; /* Push return address */ \ 203262987Sian str lr, [sp, #-4]!; /* Push SVC lr */ \ 204262987Sian str r2, [sp, #-4]!; /* Push SVC sp */ \ 205263033Sian msr spsr_fsxc, r3; /* Restore correct spsr */ \ 206262987Sian ldmdb r1, {r0-r3}; /* Restore 4 regs from xxx mode */ \ 207262987Sian sub sp, sp, #(4*15); /* Adjust the stack pointer */ \ 208262987Sian stmia sp, {r0-r12}; /* Push the user mode registers */ \ 209262987Sian add r0, sp, #(4*13); /* Adjust the stack pointer */ \ 210262987Sian stmia r0, {r13-r14}^; /* Push the user mode registers */ \ 211263033Sian mov r0, r0; /* NOP for previous instruction */ \ 212262987Sian mrs r0, spsr; /* Put the SPSR on the stack */ \ 213262987Sian str r0, [sp, #-4]! 214262987Sian#endif 215262987Sian 216262987Sian/* 217262987Sian * PULLFRAMEFROMSVCANDEXIT - macro to pull a trap frame from the stack 218262987Sian * in SVC32 mode and restore the saved processor mode and PC. 219262987Sian * This should be used when the SVC lr register needs to be restored on 220262987Sian * exit. 221262987Sian */ 222262987Sian 223284115Sandrew#if __ARM_ARCH < 6 224262987Sian#define PULLFRAMEFROMSVCANDEXIT \ 225263033Sian ldr r0, [sp], #4; /* Get the SPSR from stack */ \ 226263033Sian msr spsr_fsxc, r0; /* restore SPSR */ \ 227263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 228263033Sian mov r0, r0; /* NOP for previous instruction */ \ 229262987Sian add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 230262987Sian ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 231283366Sandrew#else 232262987Sian#define PULLFRAMEFROMSVCANDEXIT \ 233263033Sian ldr r0, [sp], #4; /* Get the SPSR from stack */ \ 234263033Sian msr spsr_fsxc, r0; /* restore SPSR */ \ 235262987Sian clrex; \ 236263033Sian ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \ 237263033Sian mov r0, r0; /* NOP for previous instruction */ \ 238262987Sian add sp, sp, #(4*15); /* Adjust the stack pointer */ \ 239262987Sian ldmia sp, {sp, lr, pc}^ /* Restore lr and exit */ 240262987Sian#endif 241262987Sian 242262987Sian/* 243262987Sian * Unwind hints so we can unwind past functions that use 244262987Sian * PULLFRAMEFROMSVCANDEXIT. They are run in reverse order. 245262987Sian * As the last thing we do is restore the stack pointer 246262987Sian * we can ignore the padding at the end of struct trapframe. 247262987Sian */ 248262987Sian#define UNWINDSVCFRAME \ 249262987Sian .save {r13-r15}; /* Restore sp, lr, pc */ \ 250262987Sian .pad #(2*4); /* Skip user sp and lr */ \ 251262987Sian .save {r0-r12}; /* Restore r0-r12 */ \ 252262987Sian .pad #(4) /* Skip spsr */ 253262987Sian 254276196Sian#define DO_AST \ 255276196Sian ldr r0, [sp]; /* Get the SPSR from stack */ \ 256276196Sian mrs r4, cpsr; /* save CPSR */ \ 257276196Sian orr r1, r4, #(PSR_I|PSR_F); \ 258276196Sian msr cpsr_c, r1; /* Disable interrupts */ \ 259276196Sian and r0, r0, #(PSR_MODE); /* Returning to USR mode? */ \ 260276196Sian teq r0, #(PSR_USR32_MODE); \ 261276196Sian bne 2f; /* Nope, get out now */ \ 262276196Sian bic r4, r4, #(PSR_I|PSR_F); \ 263276196Sian1: GET_CURTHREAD_PTR(r5); \ 264276196Sian ldr r1, [r5, #(TD_FLAGS)]; \ 265276196Sian and r1, r1, #(TDF_ASTPENDING|TDF_NEEDRESCHED); \ 266276196Sian teq r1, #0; \ 267276196Sian beq 2f; /* Nope. Just bail */ \ 268276196Sian msr cpsr_c, r4; /* Restore interrupts */ \ 269276196Sian mov r0, sp; \ 270276196Sian bl _C_LABEL(ast); /* ast(frame) */ \ 271276196Sian orr r0, r4, #(PSR_I|PSR_F); \ 272276196Sian msr cpsr_c, r0; \ 273276197Sian b 1b; \ 274262987Sian2: 275262987Sian 276262987Sian 277262987Sian/* 278263033Sian * Entry point for a Software Interrupt (SWI). 279129198Scognet * 280263033Sian * The hardware switches to svc32 mode on a swi, so we're already on the 281263033Sian * right stack; just build a trapframe and call the handler. 282129198Scognet */ 283129198ScognetASENTRY_NP(swi_entry) 284263033Sian PUSHFRAME /* Build the trapframe on the */ 285263033Sian mov r0, sp /* scv32 stack, pass it to the */ 286263033Sian bl _C_LABEL(swi_handler) /* swi handler. */ 287262987Sian /* 288262987Sian * The fork_trampoline() code in swtch.S aranges for the MI fork_exit() 289262987Sian * to return to swi_exit here, to return to userland. The net effect is 290262987Sian * that a newly created thread appears to return from a SWI just like 291262987Sian * the parent thread that created it. 292262987Sian */ 293269390SianASEENTRY_NP(swi_exit) 294263033Sian DO_AST /* Handle pending signals. */ 295263033Sian PULLFRAME /* Deallocate trapframe. */ 296263033Sian movs pc, lr /* Return to userland. */ 297263033Sian STOP_UNWINDING /* Don't unwind into user mode. */ 298269390SianEEND(swi_exit) 299248361SandrewEND(swi_entry) 300129198Scognet 301129198Scognet/* 302263033Sian * Standard exception exit handler. 303129198Scognet * 304263033Sian * This is used to return from all exceptions except SWI. It uses DO_AST and 305263033Sian * PULLFRAMEFROMSVCANDEXIT and can only be called if the exception entry code 306263033Sian * used PUSHFRAMEINSVC. 307263033Sian * 308263033Sian * If the return is to user mode, this uses DO_AST to deliver any pending 309263033Sian * signals and/or handle TDF_NEEDRESCHED first. 310129198Scognet */ 311263033SianASENTRY_NP(exception_exit) 312263033Sian DO_AST /* Handle pending signals. */ 313263033Sian PULLFRAMEFROMSVCANDEXIT /* Return. */ 314263033Sian UNWINDSVCFRAME /* Special unwinding for exceptions. */ 315263033SianEND(exception_exit) 316263033Sian 317263033Sian/* 318263033Sian * Entry point for a Prefetch Abort exception. 319263033Sian * 320263033Sian * The hardware switches to the abort mode stack; we switch to svc32 before 321283366Sandrew * calling the handler, then return directly to the original mode/stack 322263033Sian * on exit (without transitioning back through the abort mode stack). 323263033Sian */ 324129198ScognetASENTRY_NP(prefetch_abort_entry) 325129198Scognet#ifdef __XSCALE__ 326129198Scognet nop /* Make absolutely sure any pending */ 327129198Scognet nop /* imprecise aborts have occurred. */ 328129198Scognet#endif 329263033Sian sub lr, lr, #4 /* Adjust the lr. Transition to scv32 */ 330263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 331263033Sian adr lr, exception_exit /* Return from handler via standard */ 332263033Sian mov r0, sp /* exception exit routine. Pass the */ 333276206Sian mov r1, #1 /* Type flag */ 334276206Sian b _C_LABEL(abort_handler) 335248361SandrewEND(prefetch_abort_entry) 336129198Scognet 337129198Scognet/* 338263033Sian * Entry point for a Data Abort exception. 339129198Scognet * 340263033Sian * The hardware switches to the abort mode stack; we switch to svc32 before 341283366Sandrew * calling the handler, then return directly to the original mode/stack 342263033Sian * on exit (without transitioning back through the abort mode stack). 343129198Scognet */ 344129198ScognetASENTRY_NP(data_abort_entry) 345129198Scognet#ifdef __XSCALE__ 346129198Scognet nop /* Make absolutely sure any pending */ 347129198Scognet nop /* imprecise aborts have occurred. */ 348129198Scognet#endif 349263033Sian sub lr, lr, #8 /* Adjust the lr. Transition to scv32 */ 350263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 351276206Sian adr lr, exception_exit /* Exception exit routine */ 352276206Sian mov r0, sp /* Trapframe to the handler */ 353276206Sian mov r1, #0 /* Type flag */ 354276206Sian b _C_LABEL(abort_handler) 355248361SandrewEND(data_abort_entry) 356129198Scognet 357129198Scognet/* 358263033Sian * Entry point for an Undefined Instruction exception. 359129198Scognet * 360263033Sian * The hardware switches to the undefined mode stack; we switch to svc32 before 361283366Sandrew * calling the handler, then return directly to the original mode/stack 362263033Sian * on exit (without transitioning back through the undefined mode stack). 363129198Scognet */ 364263033SianASENTRY_NP(undefined_entry) 365263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 366291852Sandrew mov r4, r0 /* R0 contains SPSR */ 367263033Sian adr lr, exception_exit /* Return from handler via standard */ 368291852Sandrew mov r0, sp /* exception exit routine. pass frame */ 369291852Sandrew 370291852Sandrew ldr r2, [sp, #(TF_PC)] /* load pc */ 371291852Sandrew#if __ARM_ARCH >= 7 372291852Sandrew tst r4, #(PSR_T) /* test if PSR_T */ 373291852Sandrew subne r2, r2, #(THUMB_INSN_SIZE) 374291852Sandrew subeq r2, r2, #(INSN_SIZE) 375291852Sandrew#else 376291852Sandrew sub r2, r2, #(INSN_SIZE) /* fix pc */ 377291852Sandrew#endif 378291852Sandrew str r2, [sp, #TF_PC] /* store pc */ 379291852Sandrew 380291852Sandrew#ifdef KDTRACE_HOOKS 381291852Sandrew /* Check if dtrace is enabled */ 382291852Sandrew ldr r1, =_C_LABEL(dtrace_invop_jump_addr) 383291852Sandrew ldr r3, [r1] 384291852Sandrew cmp r3, #0 385291852Sandrew beq undefinedinstruction 386291852Sandrew 387291852Sandrew and r4, r4, #(PSR_MODE) /* Mask out unneeded bits */ 388291852Sandrew cmp r4, #(PSR_USR32_MODE) /* Check if we came from usermode */ 389291852Sandrew beq undefinedinstruction 390291852Sandrew 391291852Sandrew ldr r4, [r2] /* load instrution */ 392291852Sandrew ldr r1, =FBT_BREAKPOINT /* load fbt inv op */ 393291852Sandrew cmp r1, r4 394291852Sandrew bne undefinedinstruction 395291852Sandrew 396291852Sandrew bx r3 /* call invop_jump_addr */ 397291852Sandrew#endif 398291852Sandrew b undefinedinstruction /* call stadnard handler */ 399263033SianEND(undefined_entry) 400129198Scognet 401129198Scognet/* 402263033Sian * Entry point for a normal IRQ. 403129198Scognet * 404263033Sian * The hardware switches to the IRQ mode stack; we switch to svc32 before 405283366Sandrew * calling the handler, then return directly to the original mode/stack 406263033Sian * on exit (without transitioning back through the IRQ mode stack). 407129198Scognet */ 408262979SianASENTRY_NP(irq_entry) 409263033Sian sub lr, lr, #4 /* Adjust the lr. Transition to scv32 */ 410263033Sian PUSHFRAMEINSVC /* mode stack, build trapframe there. */ 411263033Sian adr lr, exception_exit /* Return from handler via standard */ 412263033Sian mov r0, sp /* exception exit routine. Pass the */ 413292426Sadrian b _C_LABEL(intr_irq_handler)/* trapframe to the handler. */ 414283366SandrewEND(irq_entry) 415262979Sian 416129198Scognet/* 417263033Sian * Entry point for an FIQ interrupt. 418129198Scognet * 419283366Sandrew * We don't currently support FIQ handlers very much. Something can 420262980Sian * install itself in the FIQ vector using code (that may or may not work 421262980Sian * these days) in fiq.c. If nobody does that and an FIQ happens, this 422262980Sian * default handler just disables FIQs and otherwise ignores it. 423262980Sian */ 424262980SianASENTRY_NP(fiq_entry) 425262980Sian mrs r8, cpsr /* FIQ handling isn't supported, */ 426271398Sandrew bic r8, #(PSR_F) /* just disable FIQ and return. */ 427262980Sian msr cpsr_c, r8 /* The r8 we trash here is the */ 428262980Sian subs pc, lr, #4 /* banked FIQ-mode r8. */ 429262980SianEND(fiq_entry) 430262980Sian 431262980Sian/* 432263033Sian * Entry point for an Address Exception exception. 433263033Sian * This is an arm26 exception that should never happen. 434263033Sian */ 435263033SianASENTRY_NP(addr_exception_entry) 436263034Sian mov r3, lr 437263034Sian mrs r2, spsr 438263033Sian mrs r1, cpsr 439263033Sian adr r0, Laddr_exception_msg 440263034Sian b _C_LABEL(panic) 441263033SianLaddr_exception_msg: 442263033Sian .asciz "Address Exception CPSR=0x%08x SPSR=0x%08x LR=0x%08x\n" 443263033Sian .balign 4 444263033SianEND(addr_exception_entry) 445263033Sian 446263033Sian/* 447283366Sandrew * Entry point for the system Reset vector. 448263033Sian * This should never happen, so panic. 449263033Sian */ 450263033SianASENTRY_NP(reset_entry) 451263034Sian mov r1, lr 452263033Sian adr r0, Lreset_panicmsg 453263034Sian b _C_LABEL(panic) 454263033Sian /* NOTREACHED */ 455263033SianLreset_panicmsg: 456263033Sian .asciz "Reset vector called, LR = 0x%08x" 457263033Sian .balign 4 458263033SianEND(reset_entry) 459263033Sian 460263033Sian/* 461262980Sian * page0 and page0_data -- An image of the ARM vectors which is copied to 462262980Sian * the ARM vectors page (high or low) as part of CPU initialization. The 463262980Sian * code that does the copy assumes that page0_data holds one 32-bit word 464262980Sian * of data for each of the predefined ARM vectors. It also assumes that 465283366Sandrew * page0_data follows the vectors in page0, but other stuff can appear 466283366Sandrew * between the two. We currently leave room between the two for some fiq 467262980Sian * handler code to be copied in. 468262980Sian */ 469262980Sian .global _C_LABEL(page0), _C_LABEL(page0_data) 470262980Sian 471262980Sian_C_LABEL(page0): 472262980Sian ldr pc, .Lreset_entry 473262980Sian ldr pc, .Lundefined_entry 474262980Sian ldr pc, .Lswi_entry 475262980Sian ldr pc, .Lprefetch_abort_entry 476262980Sian ldr pc, .Ldata_abort_entry 477262980Sian ldr pc, .Laddr_exception_entry 478262980Sian ldr pc, .Lirq_entry 479262980Sian.fiqv: ldr pc, .Lfiq_entry 480262980Sian .space 256 /* room for some fiq handler code */ 481262980Sian 482262980Sian_C_LABEL(page0_data): 483262980Sian.Lreset_entry: .word reset_entry 484262980Sian.Lundefined_entry: .word undefined_entry 485262980Sian.Lswi_entry: .word swi_entry 486262980Sian.Lprefetch_abort_entry: .word prefetch_abort_entry 487262980Sian.Ldata_abort_entry: .word data_abort_entry 488262980Sian.Laddr_exception_entry: .word addr_exception_entry 489262980Sian.Lirq_entry: .word irq_entry 490262980Sian.Lfiq_entry: .word fiq_entry 491262980Sian 492262980Sian/* 493262980Sian * These items are used by the code in fiq.c to install what it calls the 494262980Sian * "null" handler. It's actually our default vector entry that just jumps 495262980Sian * to the default handler which just disables FIQs and returns. 496262980Sian */ 497262980Sian .global _C_LABEL(fiq_nullhandler_code), _C_LABEL(fiq_nullhandler_size) 498262980Sian 499262980Sian_C_LABEL(fiq_nullhandler_code): 500262980Sian .word .fiqv 501262980Sian_C_LABEL(fiq_nullhandler_size): 502262980Sian .word 4 503262980Sian 504262980Sian 505