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