summaryrefslogtreecommitdiffstats
path: root/cpukit/score/cpu/arm
diff options
context:
space:
mode:
authorThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2009-07-17 15:16:50 +0000
committerThomas Doerfler <Thomas.Doerfler@embedded-brains.de>2009-07-17 15:16:50 +0000
commit9364cf663fc1dcebcc1b87cc4cec7beae5490031 (patch)
treea3788a17e3f6a72264a9bde798274805c56d9257 /cpukit/score/cpu/arm
parentremove obsolete files (diff)
downloadrtems-9364cf663fc1dcebcc1b87cc4cec7beae5490031.tar.bz2
adding lpc24xx BSP parts
Diffstat (limited to 'cpukit/score/cpu/arm')
-rw-r--r--cpukit/score/cpu/arm/arm_exc_handler_high.c115
-rw-r--r--cpukit/score/cpu/arm/arm_exc_handler_low.S176
-rw-r--r--cpukit/score/cpu/arm/arm_exc_interrupt.S229
3 files changed, 520 insertions, 0 deletions
diff --git a/cpukit/score/cpu/arm/arm_exc_handler_high.c b/cpukit/score/cpu/arm/arm_exc_handler_high.c
new file mode 100644
index 0000000000..0b256ffc7e
--- /dev/null
+++ b/cpukit/score/cpu/arm/arm_exc_handler_high.c
@@ -0,0 +1,115 @@
+/**
+ * @file
+ *
+ * ARM exception support code.
+ */
+
+/*
+ * COPYRIGHT (c) 2000 Canon Research Centre France SA.
+ * Emmanuel Raguet, mailto:raguet@crf.canon.fr
+ *
+ * Copyright (c) 2002 Advent Networks, Inc
+ * Jay Monkman <jmonkman@adventnetworks.com>
+ *
+ * Copyright (c) 2007 Ray xu <rayx.cn@gmail.com>
+ *
+ * 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.
+ *
+ * Moved from file 'cpukit/score/cpu/arm/cpu.c'.
+ *
+ * $Id$
+ */
+
+#include <rtems/system.h>
+#include <rtems.h>
+#include <rtems/bspIo.h>
+#include <rtems/score/isr.h>
+#include <rtems/score/wkspace.h>
+#include <rtems/score/thread.h>
+#include <rtems/score/cpu.h>
+
+static void _defaultExcHandler (CPU_Exception_frame *ctx)
+{
+ printk("\n\r");
+ printk("----------------------------------------------------------\n\r");
+#if 1
+ printk("Exception 0x%x caught at PC 0x%x by thread %d\n",
+ ctx->register_ip, ctx->register_lr - 4,
+ _Thread_Executing->Object.id);
+#endif
+ printk("----------------------------------------------------------\n\r");
+ printk("Processor execution context at time of the fault was :\n\r");
+ printk("----------------------------------------------------------\n\r");
+#if 0
+ printk(" r0 = %8x r1 = %8x r2 = %8x r3 = %8x\n\r",
+ ctx->register_r0, ctx->register_r1,
+ ctx->register_r2, ctx->register_r3);
+ printk(" r4 = %8x r5 = %8x r6 = %8x r7 = %8x\n\r",
+ ctx->register_r4, ctx->register_r5,
+ ctx->register_r6, ctx->register_r7);
+ printk(" r8 = %8x r9 = %8x r10 = %8x\n\r",
+ ctx->register_r8, ctx->register_r9, ctx->register_r10);
+ printk(" fp = %8x ip = %8x sp = %8x pc = %8x\n\r",
+ ctx->register_fp, ctx->register_ip,
+ ctx->register_sp, ctx->register_lr - 4);
+ printk("----------------------------------------------------------\n\r");
+#endif
+ if (_ISR_Nest_level > 0) {
+ /*
+ * In this case we shall not delete the task interrupted as
+ * it has nothing to do with the fault. We cannot return either
+ * because the eip points to the faulty instruction so...
+ */
+ printk("Exception while executing ISR!!!. System locked\n\r");
+ while(1);
+ }
+ else {
+ printk("*********** FAULTY THREAD WILL BE DELETED **************\n\r");
+ rtems_task_delete(_Thread_Executing->Object.id);
+ }
+}
+
+typedef void (*cpuExcHandlerType) (CPU_Exception_frame*);
+
+cpuExcHandlerType _currentExcHandler = _defaultExcHandler;
+
+extern void _Exception_Handler_Undef_Swi(void);
+extern void _Exception_Handler_Abort(void);
+extern void _exc_data_abort(void);
+
+
+
+/* FIXME: put comments here */
+void rtems_exception_init_mngt(void)
+{
+ ISR_Level level;
+
+ _CPU_ISR_Disable(level);
+ _CPU_ISR_install_vector(ARM_EXCEPTION_UNDEF,
+ _Exception_Handler_Undef_Swi,
+ NULL);
+
+ _CPU_ISR_install_vector(ARM_EXCEPTION_SWI,
+ _Exception_Handler_Undef_Swi,
+ NULL);
+
+ _CPU_ISR_install_vector(ARM_EXCEPTION_PREF_ABORT,
+ _Exception_Handler_Abort,
+ NULL);
+
+ _CPU_ISR_install_vector(ARM_EXCEPTION_DATA_ABORT,
+ _exc_data_abort,
+ NULL);
+
+ _CPU_ISR_install_vector(ARM_EXCEPTION_FIQ,
+ _Exception_Handler_Abort,
+ NULL);
+
+ _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ,
+ _Exception_Handler_Abort,
+ NULL);
+
+ _CPU_ISR_Enable(level);
+}
diff --git a/cpukit/score/cpu/arm/arm_exc_handler_low.S b/cpukit/score/cpu/arm/arm_exc_handler_low.S
new file mode 100644
index 0000000000..b333ef5d6a
--- /dev/null
+++ b/cpukit/score/cpu/arm/arm_exc_handler_low.S
@@ -0,0 +1,176 @@
+/**
+ * @file
+ *
+ * ARM exception support code.
+ */
+
+/*
+ * $Id$
+ *
+ * Copyright (c) 2007 by Ray Xu, <Rayx.cn@gmail.com>
+ * Thumb support added.
+ *
+ * Copyright (c) 2002 by Advent Networks, Inc.
+ * Jay Monkman <jmonkman@adventnetworks.com>
+ *
+ * COPYRIGHT (c) 2000 Canon Research Centre France SA.
+ * Emmanuel Raguet, mailto:raguet@crf.canon.fr
+ *
+ * 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.
+ *
+ * Moved from file 'cpukit/score/cpu/arm/cpu_asm.S'.
+ *
+ */
+
+#include <rtems/asm.h>
+#include <rtems/score/cpu_asm.h>
+
+/*
+ * function declaration macro (start body in ARM mode)
+ */
+#ifdef __thumb__
+ #define FUNC_START_ARM(_name_) \
+ .code 16 ;\
+ .thumb_func ;\
+ .globl _name_ ;\
+_name_: ;\
+ bx pc ;\
+ .code 32 ;\
+_name_ ## _ARM:
+#else
+ #define FUNC_START_ARM(_name_) \
+ .globl _name_; \
+_name_:
+#endif
+
+ .text
+
+/* FIXME: _Exception_Handler_Undef_Swi is untested */
+FUNC_START_ARM(_Exception_Handler_Undef_Swi)
+/* FIXME: This should use load and store multiple instructions */
+ sub r13,r13,#SIZE_REGS
+ str r4, [r13, #REG_R4]
+ str r5, [r13, #REG_R5]
+ str r6, [r13, #REG_R6]
+ str r7, [r13, #REG_R7]
+ str r8, [r13, #REG_R8]
+ str r9, [r13, #REG_R9]
+ str r10, [r13, #REG_R10]
+ str r11, [r13, #REG_R11]
+ str sp, [r13, #REG_SP]
+ str lr, [r13, #REG_LR]
+ mrs r0, cpsr /* read the status */
+ and r0, r0,#0x1f /* we keep the mode as exception number */
+ str r0, [r13, #REG_PC] /* we store it in a free place */
+ mov r0, r13 /* put frame address in r0 (C arg 1) */
+
+ ldr r1, =SWI_Handler
+ ldr lr, =_go_back_1
+ ldr pc,[r1] /* call handler */
+_go_back_1:
+ ldr r4, [r13, #REG_R4]
+ ldr r5, [r13, #REG_R5]
+ ldr r6, [r13, #REG_R6]
+ ldr r7, [r13, #REG_R7]
+ ldr r8, [r13, #REG_R8]
+ ldr r9, [r13, #REG_R9]
+ ldr r10, [r13, #REG_R10]
+ ldr r11, [r13, #REG_R11]
+ ldr sp, [r13, #REG_SP]
+ ldr lr, [r13, #REG_LR]
+ add r13,r13,#SIZE_REGS
+ movs pc,r14 /* return */
+
+/* FIXME: _Exception_Handler_Abort is untested */
+FUNC_START_ARM(_Exception_Handler_Abort)
+/* FIXME: This should use load and store multiple instructions */
+ sub r13,r13,#SIZE_REGS
+ str r4, [r13, #REG_R4]
+ str r5, [r13, #REG_R5]
+ str r6, [r13, #REG_R6]
+ str r7, [r13, #REG_R7]
+ str r8, [r13, #REG_R8]
+ str r9, [r13, #REG_R9]
+ str sp, [r13, #REG_R11]
+ str lr, [r13, #REG_SP]
+ str lr, [r13, #REG_LR]
+ mrs r0, cpsr /* read the status */
+ and r0, r0,#0x1f /* we keep the mode as exception number */
+ str r0, [r13, #REG_PC] /* we store it in a free place */
+ mov r0, r13 /* put frame address in ro (C arg 1) */
+
+ ldr r1, =_currentExcHandler
+ ldr lr, =_go_back_2
+ ldr pc,[r1] /* call handler */
+_go_back_2:
+ ldr r4, [r13, #REG_R4]
+ ldr r5, [r13, #REG_R5]
+ ldr r6, [r13, #REG_R6]
+ ldr r7, [r13, #REG_R7]
+ ldr r8, [r13, #REG_R8]
+ ldr r9, [r13, #REG_R9]
+ ldr r10, [r13, #REG_R10]
+ ldr sp, [r13, #REG_R11]
+ ldr lr, [r13, #REG_SP]
+ ldr lr, [r13, #REG_LR]
+ add r13,r13,#SIZE_REGS
+#ifdef __thumb__
+ subs r11, r14,#4
+ bx r11
+ nop
+#else
+ subs pc,r14,#4 /* return */
+#endif
+
+#define ABORT_REGS_OFFS 32-REG_R4
+#define ABORT_SIZE_REGS SIZE_REGS+ABORT_REGS_OFFS
+
+FUNC_START_ARM(_exc_data_abort)
+ sub sp, sp, #ABORT_SIZE_REGS /* reserve register frame */
+ stmia sp, {r0-r11}
+ add sp, sp, #ABORT_REGS_OFFS /* the Context_Control structure starts by CPSR, R4, ... */
+
+ str ip, [sp, #REG_PC] /* store R12 (ip) somewhere, oh hackery, hackery, hack */
+ str lr, [sp, #REG_LR]
+
+ mov r1, lr
+ ldr r0, [r1, #-8] /* r0 = bad instruction */
+ mrs r1, spsr /* r1 = spsr */
+ mov r2, r13 /* r2 = exception frame of Context_Control type */
+#if defined(__thumb__)
+ .code 32
+ /*arm to thumb*/
+ adr r5, to_thumb + 1
+ bx r5
+ .code 16
+to_thumb:
+#endif
+ bl do_data_abort
+#if defined(__thumb__)
+/*back to arm*/
+ .code 16
+thumb_to_arm:
+ .align 2
+ adr r5, arm_code
+ bx r5
+ nop
+ .code 32
+arm_code:
+#endif
+
+ ldr lr, [sp, #REG_LR]
+ ldr ip, [sp, #REG_PC] /* restore R12 (ip) */
+
+ sub sp, sp, #ABORT_REGS_OFFS
+ ldmia sp, {r0-r11}
+ add sp, sp, #ABORT_SIZE_REGS
+#ifdef __thumb__
+ subs r11, r14, #4 /* return to the instruction */
+ bx r11
+ nop
+#else
+ subs pc, r14, #4
+#endif
+ /* _AFTER_ the aborted one */
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..7cfd56ff00
--- /dev/null
+++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S
@@ -0,0 +1,229 @@
+/**
+ * @file
+ *
+ * @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.
+ */
+
+/*
+ * These two non-volatile registers contain the program status for INT and SVC
+ * mode. It is important that they are directly accessible in THUMB
+ * instruction mode.
+ */
+#define MODE_INT r4
+#define MODE_SVC r5
+
+/*
+ * These three non-volatile registers are used to exchange information between
+ * INT and SVC mode.
+ */
+#define SCRATCH_0 r6
+#define SCRATCH_1 r7
+#define SCRATCH_2 r8
+
+/* List of scratch registers. They will be saved and restored in INT mode. */
+#define SCRATCH_LIST {SCRATCH_0, SCRATCH_1, SCRATCH_2}
+
+/*
+ * List of all volatile registers (r0, r1, r2, r3, r12 and lr), registers
+ * containing the interrupt context (return address in SCRATCH_0 and saved
+ * program status in SCRATCH_1) and non-volatile registers used for modes
+ * (MODE_INT and MODE_SVC). They will be saved and restored in SVC mode.
+ */
+#define TASK_CONTEXT_LIST \
+ {r0, r1, r2, r3, MODE_INT, MODE_SVC, SCRATCH_0, SCRATCH_1, r12, lr}
+
+/*
+ * List of all volatile registers (r0, r1, r2, r3, r12 and lr) and the saved
+ * program status (SCRATCH_0 register). They will be saved and restored in INT
+ * mode.
+ */
+#define INTERRUPT_CONTEXT_LIST \
+ {r0, r1, r2, r3, SCRATCH_0, r12, lr}
+
+.extern _ISR_Thread_dispatch
+.extern _ISR_Nest_level
+.extern _Thread_Dispatch_disable_level
+.extern bsp_interrupt_dispatch
+
+.arm
+.globl arm_exc_interrupt
+arm_exc_interrupt:
+
+ /* Save scratch registers on INT stack */
+ stmdb sp!, SCRATCH_LIST
+
+ /* Increment interrupt nest level */
+ ldr SCRATCH_0, =_ISR_Nest_level
+ ldr SCRATCH_1, [SCRATCH_0]
+ add SCRATCH_2, SCRATCH_1, #1
+ str SCRATCH_2, [SCRATCH_0]
+
+ /* Branch for nested interrupts */
+ cmp SCRATCH_1, #0
+ bne nested_interrupt_context_save
+
+ /* Move interrupt context and CPSR to scratch registers */
+ mov SCRATCH_0, lr
+ mrs SCRATCH_1, spsr
+ mrs SCRATCH_2, cpsr
+
+ /* Switch to SVC mode */
+ orr SCRATCH_2, SCRATCH_2, #0x1
+ msr cpsr_c, SCRATCH_2
+
+ /* Save context on SVC stack */
+ stmdb sp!, TASK_CONTEXT_LIST
+
+ /* Save SVC mode program status to non-volatile register */
+ mov MODE_SVC, SCRATCH_2
+
+ /* Save INT mode program status to non-volatile register */
+ bic MODE_INT, MODE_SVC, #0x1
+
+ /* Switch to INT mode */
+ msr cpsr_c, MODE_INT
+
+ /* Restore scratch registers from INT stack */
+ ldmia sp!, SCRATCH_LIST
+
+ /*
+ * At this point the INT stack is in the exception entry state and
+ * contains no data for us. The context is saved on the SVC stack. We
+ * can easily switch modes via the registers MODE_INT and MODE_SVC
+ * which are valid through subroutine calls. We can use all volatile
+ * registers in both modes. Note that this comment describes the non
+ * nested interrupt entry. For a nested interrupt things are
+ * different, since we can save everything on the INT stack and there
+ * is no need to switch modes.
+ */
+
+task_context_save_done:
+
+ /* Switch to THUMB instructions if necessary */
+#ifdef __thumb__
+ add r0, pc, #1
+ bx r0
+.thumb
+#endif /* __thumb__ */
+
+ /* Increment thread dispatch disable level */
+ ldr r1, =_Thread_Dispatch_disable_level
+ ldr r3, [r1]
+ add r3, r3, #1
+ str r3, [r1]
+
+ /* Call BSP dependent interrrupt 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, r2, #1
+ sub r3, r3, #1
+ str r2, [r0]
+ str r3, [r1]
+
+ /* Switch to ARM instructions if necessary */
+#ifdef __thumb__
+.align 2
+ bx pc
+.arm
+#endif /* __thumb__ */
+
+ /* Branch if we have a nested interrupt */
+ cmp r2, #0
+ bne nested_interrupt_return
+
+ /* Branch if thread dispatching is disabled */
+ cmp r3, #0
+ bne thread_dispatch_done
+
+ /*
+ * Switch to SVC mode. It is important to call the thread dispatcher
+ * in SVC mode since overwise the INT stack may need to store an
+ * arbitrary number of contexts and it may lead to an invalid order of
+ * stack operations.
+ */
+ msr cpsr_c, MODE_SVC
+
+ /* Call thread dispatcher */
+#ifdef __thumb__
+ ldr r0, =_ISR_Thread_dispatch
+ mov lr, pc
+ bx r0
+.thumb
+ bx pc
+ nop
+.arm
+#else
+ bl _ISR_Thread_dispatch
+#endif
+
+ /* Switch to INT mode */
+ msr cpsr_c, MODE_INT
+
+thread_dispatch_done:
+
+ /* Save scratch registers on INT stack */
+ stmdb sp!, SCRATCH_LIST
+
+ /* Switch to SVC mode */
+ msr cpsr_c, MODE_SVC
+
+ /* Move INT mode program status to scratch register */
+ mov SCRATCH_2, MODE_INT
+
+ /* Restore context from SVC stack */
+ ldmia sp!, TASK_CONTEXT_LIST
+
+ /* Switch to INT mode */
+ msr cpsr_c, SCRATCH_2
+
+ /* Restore interrupt context */
+ mov lr, SCRATCH_0
+ msr spsr, SCRATCH_1
+
+ /* Restore scratch registers from INT stack */
+ ldmia sp!, SCRATCH_LIST
+
+ /* Return from interrupt */
+ subs pc, lr, #4
+
+nested_interrupt_context_save:
+
+ /* Move saved program status register to scratch register */
+ mrs SCRATCH_0, spsr
+
+ /* Save context on INT stack */
+ stmdb sp!, INTERRUPT_CONTEXT_LIST
+
+ b task_context_save_done
+
+nested_interrupt_return:
+
+ /* Restore context from INT stack */
+ ldmia sp!, INTERRUPT_CONTEXT_LIST
+
+ /* Restore saved program status register */
+ msr spsr, SCRATCH_0
+
+ /* Restore scratch registers from INT stack */
+ ldmia sp!, SCRATCH_LIST
+
+ /* Return from interrupt */
+ subs pc, lr, #4