diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-07-17 15:16:50 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-07-17 15:16:50 +0000 |
commit | 9364cf663fc1dcebcc1b87cc4cec7beae5490031 (patch) | |
tree | a3788a17e3f6a72264a9bde798274805c56d9257 /cpukit | |
parent | remove obsolete files (diff) | |
download | rtems-9364cf663fc1dcebcc1b87cc4cec7beae5490031.tar.bz2 |
adding lpc24xx BSP parts
Diffstat (limited to 'cpukit')
-rw-r--r-- | cpukit/score/cpu/arm/arm_exc_handler_high.c | 115 | ||||
-rw-r--r-- | cpukit/score/cpu/arm/arm_exc_handler_low.S | 176 | ||||
-rw-r--r-- | cpukit/score/cpu/arm/arm_exc_interrupt.S | 229 |
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 |