1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 .file "trap.s" 13 14 #include <sys/asm_linkage.h> 15 #include <sys/cpu_asm.h> 16 17 /* 18 * Create a section into which to place the exception vector, such that we can 19 * force it to be mapped where it needs to be. Currently at 0x0, since 20 * we don't set the high vector bit (SCTLR.V) 21 * 22 * Each instruction in the vector jumps to its own address + 24, which is the 23 * matching entry in exception_table. We do this to insure that we get 24 * effectively infinite displacement, which we can't achieve in one 25 * instruction otherwise (and gas complains). 26 * 27 * The handler for each exception type saves a trap frame (struct regs, though 28 * with some bits unusual) and calls the associated handler from trap_table. 29 * 30 * XXX: On CPUs with the security extensions, there are actually 2 additional 31 * exception vectors: secure, and monitor. We ignore them. 32 */ 33 .pushsection ".exception_vector", "ax" 34 ldr pc, [pc, #24] 35 ldr pc, [pc, #24] 36 ldr pc, [pc, #24] 37 ldr pc, [pc, #24] 38 ldr pc, [pc, #24] 39 ldr pc, [pc, #24] 40 ldr pc, [pc, #24] 41 ldr pc, [pc, #24] 42 .exception_table: 43 .word handle_reset /* Reset */ 44 .word handle_undef /* Undefined insn */ 45 .word handle_svc /* Supervisor Call */ 46 .word handle_prefetchabt /* Prefetch abort */ 47 .word handle_dataabt /* Data abort */ 48 .word 0x00000014 /* Reserved (infinite loops) */ 49 .word handle_irq /* IRQ */ 50 .word handle_fiq /* FIQ */ 51 .popsection 52 53 /* Clobbers r0 */ 54 #define CALL_HANDLER(scratch, trapno) \ 55 ldr scratch, =(trap_table + (4 * trapno)); \ 56 ldr scratch, [scratch]; \ 57 cmp scratch, #0; \ 58 beq 1f; \ 59 mov r0, sp; /* Pass our saved frame to the handler */ \ 60 blx scratch; /* Call the handler */ \ 61 1: 62 63 /* 64 * XXX: Note that we go to some contortions here to save in 'struct regs' style. 65 * 66 * This includes saving our own lr/spsr, for our own return _and_ saving them 67 * into the 'struct regs', and doing the register save unusually such that we 68 * get the 'struct regs' in order. 69 * 70 * Depending on the exact nature of 'struct regs', perhaps we should be 71 * bending it to our will, rather than letting it bend us? 72 * 73 * XXX: Note also that we're saving the current registers assuming that we 74 * came from supervisor mode. We should probably be saving the banked 75 * registers based on the mode in the spsr. (or we'll screw up when nested, 76 * or when userland traps, or...) 77 */ 78 #define PUSH_TRAP_FRAME(scratch) \ 79 srsdb sp!, #(CPU_MODE_SVC); /* Save lr and spsr for ourselves */ \ 80 cps #(CPU_MODE_SVC); \ 81 ldr lr, [sp]; /* Get lr back for the trap frame */ \ 82 sub sp, sp, #(4 * 17); /* Space for all our registers */ \ 83 stmia sp, {r0-r14}; /* XXX: Note we don't save pc */ \ 84 ldr scratch, [sp, #(4 * 18)]; /* skip 17 regs and the lr */ \ 85 str scratch, [sp, #(4 * 16)]; 86 87 #define POP_TRAP_FRAME_AND_RET() \ 88 ldmia sp, {r0-r14}; \ 89 add sp, sp, #(4 * 19); /* 17 regs + 2 for lr and spsr */ \ 90 rfedb sp; /* Return */ 91 92 /* 93 * XXX: None of these handlers are even vaguely aware that usermode exists, 94 * and make no effort to do the traditional things we would probably do on 95 * returning to user mode. They will need to be rethought at such a time 96 */ 97 .globl trap_table 98 99 #define DEFINE_HANDLER(name, code) \ 100 ENTRY(name) \ 101 PUSH_TRAP_FRAME(r0) \ 102 CALL_HANDLER(r1, code) \ 103 POP_TRAP_FRAME_AND_RET() \ 104 SET_SIZE(name) 105 106 DEFINE_HANDLER(handle_reset, ARM_EXCPT_RESET) 107 108 /* 109 * XXX: Note that in practice, if we use this for emulation, things 110 * might look pretty different, but I think that giving the handler the 111 * entire real frame which we restore gives us the flexibility to do it 112 * this way. 113 */ 114 DEFINE_HANDLER(handle_undef, ARM_EXCPT_UNDINS) 115 116 DEFINE_HANDLER(handle_svc, ARM_EXCPT_SVC) 117 DEFINE_HANDLER(handle_prefetchabt, ARM_EXCPT_PREFETCH) 118 DEFINE_HANDLER(handle_dataabt, ARM_EXCPT_DATA) 119 120 /* 121 * XXX: These assume that we really want vectored interrupts, and thus that 122 * we'll only ever see these if something went wrong (we took a 123 * non-vectored interrupt 124 * 125 * They may need extension (to pull info from the PIC this early, or 126 * whatever.) if we choose to use non-vectored interrupts. 127 */ 128 DEFINE_HANDLER(handle_irq, ARM_EXCPT_IRQ) 129 DEFINE_HANDLER(handle_fiq, ARM_EXCPT_FIQ)