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)