diff options
Diffstat (limited to 'bsps/powerpc/ss555/start/irq_asm.S')
-rw-r--r-- | bsps/powerpc/ss555/start/irq_asm.S | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/bsps/powerpc/ss555/start/irq_asm.S b/bsps/powerpc/ss555/start/irq_asm.S new file mode 100644 index 0000000000..52911c48e3 --- /dev/null +++ b/bsps/powerpc/ss555/start/irq_asm.S @@ -0,0 +1,312 @@ +/* + * irq_asm.S + * + * This file contains the assembly code for the PowerPC + * IRQ veneers for RTEMS. + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + * + * + * MPC5xx port sponsored by Defence Research and Development Canada - Suffield + * Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca) + * + * Derived from libbsp/powerpc/mbx8xx/irq/irq_asm.S: + * + * Modified to support the MCP750. + * Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr + * + * Till Straumann <strauman@slac.stanford.edu>, 2003/7: + * - store isr nesting level in _ISR_Nest_level rather than + * SPRG0 - RTEMS relies on that variable. + */ + +#include <rtems/asm.h> +#include <rtems/score/cpu.h> +#include <rtems/score/percpu.h> +#include <libcpu/vectors.h> +#include <libcpu/raw_exception.h> + + +#define SYNC \ + sync; \ + isync + +/* + * Common handler for interrupt exceptions. + * + * The function CPU_rtems_irq_mng_init() initializes the decrementer and + * external interrupt entries in the exception handler table with pointers + * to this routine, which saves the remainder of the interrupted code's + * state, then calls C_dispatch_irq_handler(). + * + * On entry, R1 points to a new exception stack frame in which R3, R4, and + * LR have been saved. R4 holds the exception number. + */ + PUBLIC_VAR(C_dispatch_irq_handler) + + PUBLIC_VAR(dispatch_irq_handler) +SYM (dispatch_irq_handler): + /* + * Save SRR0/SRR1 As soon As possible as it is the minimal needed + * to re-enable exception processing. + * + * Note that R2 should never change (it's the EABI pointer to + * .sdata2), but we save it just in case. + */ + stw r0, GPR0_OFFSET(r1) + stw r2, GPR2_OFFSET(r1) + + mfsrr0 r0 + mfsrr1 r3 + + stw r0, SRR0_FRAME_OFFSET(r1) + stw r3, SRR1_FRAME_OFFSET(r1) + + /* + * Enable exception recovery. Also enable FP so that FP context + * can be saved and restored (using FP instructions). + */ + mfmsr r3 + ori r3, r3, MSR_RI | MSR_FP + mtmsr r3 + SYNC + + /* + * Push C scratch registers on the current stack. It may actually be + * the thread stack or the interrupt stack. Anyway we have to make + * it in order to be able to call C/C++ functions. Depending on the + * nesting interrupt level, we will switch to the right stack later. + */ + stw r5, GPR5_OFFSET(r1) + stw r6, GPR6_OFFSET(r1) + stw r7, GPR7_OFFSET(r1) + stw r8, GPR8_OFFSET(r1) + stw r9, GPR9_OFFSET(r1) + stw r10, GPR10_OFFSET(r1) + stw r11, GPR11_OFFSET(r1) + stw r12, GPR12_OFFSET(r1) + stw r13, GPR13_OFFSET(r1) + + mfcr r5 + mfctr r6 + mfxer r7 + + stw r5, EXC_CR_OFFSET(r1) + stw r6, EXC_CTR_OFFSET(r1) + stw r7, EXC_XER_OFFSET(r1) + + /* + * Add some non volatile registers to store information that will be + * used when returning from C handler. + */ + stw r14, GPR14_OFFSET(r1) + stw r15, GPR15_OFFSET(r1) + + /* + * Save current stack pointer location in R14. + */ + addi r14, r1, 0 + + /* + * store part of THREAD_DISPATCH_DISABLE_LEVEL address in R15 + */ + addis r15, 0, THREAD_DISPATCH_DISABLE_LEVEL@ha + + /* + * Retrieve current nesting level from _ISR_Nest_level + */ + lis r7, ISR_NEST_LEVEL@ha + lwz r3, ISR_NEST_LEVEL@l(r7) + + /* + * Check if stack switch is necessary + */ + cmpwi r3, 0 + bne nested + + mfspr r1, SPRG1 /* switch to interrupt stack */ +nested: + + /* + * Start Incrementing nesting level in R3 + */ + addi r3, r3, 1 + + /* + * Start Incrementing THREAD_DISPATCH_DISABLE_LEVEL R4 = THREAD_DISPATCH_DISABLE_LEVEL + */ + lwz r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15) + + /* store new nesting level in _ISR_Nest_level */ + stw r3, ISR_NEST_LEVEL@l(r7) + + addi r6, r6, 1 + + /* + * store new THREAD_DISPATCH_DISABLE_LEVEL value + */ + stw r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15) + + /* + * We are now running on the interrupt stack. External and decrementer + * exceptions are still disabled. I see no purpose trying to optimize + * further assembler code. + */ + + /* + * Call C exception handler for decrementer or external interrupt. + * Pass frame along just in case.. + * + * C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) + */ + addi r3, r14, 0x8 + bl C_dispatch_irq_handler + + /* + * start decrementing nesting level. Note : do not test result against 0 + * value as an easy exit condition because if interrupt nesting level > 1 + * then THREAD_DISPATCH_DISABLE_LEVEL > 1 + */ + lis r7, ISR_NEST_LEVEL@ha + lwz r4, ISR_NEST_LEVEL@l(r7) + + /* + * start decrementing THREAD_DISPATCH_DISABLE_LEVEL + */ + lwz r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) + + addi r4, r4, -1 /* Continue decrementing nesting level */ + addi r3, r3, -1 /* Continue decrementing THREAD_DISPATCH_DISABLE_LEVEL */ + + stw r4, ISR_NEST_LEVEL@l(r7) /* End decrementing nesting level */ + stw r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) /* End decrementing THREAD_DISPATCH_DISABLE_LEVEL */ + + cmpwi r3, 0 + + /* + * switch back to original stack (done here just optimize registers + * contention. Could have been done before...) + */ + addi r1, r14, 0 + bne easy_exit /* if (THREAD_DISPATCH_DISABLE_LEVEL != 0) goto easy_exit */ + + /* + * Here we are running again on the thread system stack. + * We have interrupt nesting level = THREAD_DISPATCH_DISABLE_LEVEL = 0. + * Interrupt are still disabled. Time to check if scheduler request to + * do something with the current thread... + */ + addis r4, 0, DISPATCH_NEEDED@ha + lbz r5, DISPATCH_NEEDED@l(r4) + cmpwi r5, 0 + beq easy_exit + + /* + * going to call _Thread_Dispatch + * Push a complete exception like frame... + */ + stmw r16, GPR16_OFFSET(r1) + addi r3, r1, 0x8 + + /* + * compute SP at exception entry + */ + addi r4, r1, EXCEPTION_FRAME_END + + /* + * store it at the right place + */ + stw r4, GPR1_OFFSET(r1) + + /* + * Call High Level signal handling code + */ + bl _Thread_Dispatch + + /* + * start restoring exception like frame + */ + lwz r31, EXC_CTR_OFFSET(r1) + lwz r30, EXC_XER_OFFSET(r1) + lwz r29, EXC_CR_OFFSET(r1) + lwz r28, EXC_LR_OFFSET(r1) + + mtctr r31 + mtxer r30 + mtcr r29 + mtlr r28 + + lmw r4, GPR4_OFFSET(r1) + lwz r2, GPR2_OFFSET(r1) + lwz r0, GPR0_OFFSET(r1) + + /* + * Make path non recoverable... + */ + mtspr nri, r0 + SYNC + + /* + * Restore rfi related settings + */ + + lwz r3, SRR1_FRAME_OFFSET(r1) + mtsrr1 r3 + lwz r3, SRR0_FRAME_OFFSET(r1) + mtsrr0 r3 + + lwz r3, GPR3_OFFSET(r1) + addi r1,r1, EXCEPTION_FRAME_END + SYNC + rfi + + +easy_exit: + /* + * start restoring interrupt frame + */ + lwz r3, EXC_CTR_OFFSET(r1) + lwz r4, EXC_XER_OFFSET(r1) + lwz r5, EXC_CR_OFFSET(r1) + lwz r6, EXC_LR_OFFSET(r1) + + mtctr r3 + mtxer r4 + mtcr r5 + mtlr r6 + + lwz r15, GPR15_OFFSET(r1) + lwz r14, GPR14_OFFSET(r1) + lwz r13, GPR13_OFFSET(r1) + lwz r12, GPR12_OFFSET(r1) + lwz r11, GPR11_OFFSET(r1) + lwz r10, GPR10_OFFSET(r1) + lwz r9, GPR9_OFFSET(r1) + lwz r8, GPR8_OFFSET(r1) + lwz r7, GPR7_OFFSET(r1) + lwz r6, GPR6_OFFSET(r1) + lwz r5, GPR5_OFFSET(r1) + + /* + * Disable nested exception processing. + */ + mtspr nri, r0 + SYNC + + /* + * Restore rfi related settings + */ + lwz r4, SRR1_FRAME_OFFSET(r1) + lwz r3, SRR0_FRAME_OFFSET(r1) + lwz r2, GPR2_OFFSET(r1) + lwz r0, GPR0_OFFSET(r1) + + mtsrr1 r4 + mtsrr0 r3 + lwz r4, GPR4_OFFSET(r1) + lwz r3, GPR3_OFFSET(r1) + addi r1,r1, EXCEPTION_FRAME_END + SYNC + rfi |