summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/arm/arm_exc_interrupt.S
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/score/cpu/arm/arm_exc_interrupt.S')
-rw-r--r--cpukit/score/cpu/arm/arm_exc_interrupt.S177
1 files changed, 177 insertions, 0 deletions
diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S
new file mode 100644
index 0000000000..e269e13455
--- /dev/null
+++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S
@@ -0,0 +1,177 @@
+/**
+ * @file
+ *
+ * @ingroup ScoreCPU
+ *
+ * @brief ARM interrupt exception prologue and epilogue.
+ */
+
+/*
+ * Copyright (c) 2009
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * D-82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+/*
+ * The upper EXCHANGE_SIZE bytes of the INT stack area are used for data
+ * exchange between INT and SVC mode. Below of this is the actual INT stack.
+ * The exchange area is only accessed if INT is disabled.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/asm.h>
+#include <rtems/score/percpu.h>
+
+#define EXCHANGE_LR r4
+#define EXCHANGE_SPSR r5
+#define EXCHANGE_CPSR r6
+#define EXCHANGE_INT_SP r7
+
+#define EXCHANGE_LIST {EXCHANGE_LR, EXCHANGE_SPSR, EXCHANGE_CPSR, EXCHANGE_INT_SP}
+#define EXCHANGE_SIZE 16
+
+#define CONTEXT_LIST {r0, r1, r2, r3, EXCHANGE_LR, EXCHANGE_SPSR, r12}
+#define CONTEXT_SIZE 28
+
+.extern _Thread_Dispatch_disable_level
+
+.extern bsp_interrupt_dispatch
+
+.arm
+.globl arm_exc_interrupt
+arm_exc_interrupt:
+
+ /* Save exchange registers to exchange area */
+ stmdb sp, EXCHANGE_LIST
+
+ /* Set exchange registers */
+ mov EXCHANGE_LR, lr
+ mrs EXCHANGE_SPSR, spsr
+ mrs EXCHANGE_CPSR, cpsr
+ sub EXCHANGE_INT_SP, sp, #EXCHANGE_SIZE
+
+ /* Switch to SVC mode */
+ orr EXCHANGE_CPSR, EXCHANGE_CPSR, #0x1
+ msr cpsr, EXCHANGE_CPSR
+
+ /*
+ * Save context. We save the LR separately because it has to be
+ * restored in SVC mode. The other registers can be restored in INT
+ * mode.
+ */
+ stmdb sp!, CONTEXT_LIST
+ stmdb sp!, {lr}
+
+ /* Remember INT stack pointer */
+ mov r1, EXCHANGE_INT_SP
+
+ /* Restore exchange registers from exchange area */
+ ldmia r1, EXCHANGE_LIST
+
+ /* Get interrupt nest level */
+ ldr r0, =ISR_NEST_LEVEL
+ ldr r2, [r0]
+
+ /* Switch stack if necessary and save original stack pointer */
+ mov r3, sp
+ cmp r2, #0
+ moveq sp, r1
+ stmdb sp!, {r3}
+
+ /* Switch to THUMB instructions if necessary */
+ SWITCH_FROM_ARM_TO_THUMB r1
+
+ /* Increment interrupt nest and thread dispatch disable level */
+ ldr r1, =_Thread_Dispatch_disable_level
+ ldr r3, [r1]
+ add r2, #1
+ add r3, #1
+ str r2, [r0]
+ str r3, [r1]
+
+ /* Call BSP dependent interrupt dispatcher */
+ bl bsp_interrupt_dispatch
+
+ /* Decrement interrupt nest and thread dispatch disable level */
+ ldr r0, =ISR_NEST_LEVEL
+ ldr r1, =_Thread_Dispatch_disable_level
+ ldr r2, [r0]
+ ldr r3, [r1]
+ sub r2, #1
+ sub r3, #1
+ str r2, [r0]
+ str r3, [r1]
+
+ /* Restore stack pointer */
+ SWITCH_FROM_THUMB_TO_ARM
+ ldr sp, [sp]
+ SWITCH_FROM_ARM_TO_THUMB r0
+
+ /* Check thread dispatch disable level */
+ cmp r3, #0
+ bne thread_dispatch_done
+
+ /* Check context switch necessary */
+ ldr r0, =DISPATCH_NEEDED
+ ldrb r1, [r0]
+ cmp r1, #0
+ beq thread_dispatch_done
+
+ /* This aligns thread_dispatch_done on a 4 byte boundary */
+#ifdef __thumb__
+ nop
+#endif /* __thumb__ */
+
+do_thread_dispatch:
+
+ /* Thread dispatch */
+ bl _Thread_Dispatch
+
+thread_dispatch_done:
+
+ /* Switch to ARM instructions if necessary */
+ SWITCH_FROM_THUMB_TO_ARM
+
+ /* Restore link register */
+ ldmia sp!, {lr}
+
+ /*
+ * XXX: Remember and restore stack pointer. The data on the stack is
+ * still in use. So the stack is now in an inconsistent state. The
+ * FIQ handler implementation must not use this area.
+ */
+ mov r0, sp
+ add sp, #CONTEXT_SIZE
+
+ /* Get INT mode program status register */
+ mrs r1, cpsr
+ bic r1, r1, #0x1
+
+ /* Switch to INT mode */
+ msr cpsr, r1
+
+ /* Save EXCHANGE_LR and EXCHANGE_SPSR registers to exchange area */
+ stmdb sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
+
+ /* Restore context */
+ ldmia r0, CONTEXT_LIST
+
+ /* Set return address and program status */
+ mov lr, EXCHANGE_LR
+ msr spsr, EXCHANGE_SPSR
+
+ /* Restore EXCHANGE_LR and EXCHANGE_SPSR registers from exchange area */
+ ldmia sp!, {EXCHANGE_LR, EXCHANGE_SPSR}
+
+ /* Return from interrupt */
+ subs pc, lr, #4