/*===============================================================*\ | Project: RTEMS generic MPC5200 BSP | +-----------------------------------------------------------------+ | File: irq_asm.S +-----------------------------------------------------------------+ | Partially based on the code references which are named below. | | Adaptions, modifications, enhancements and any recent parts of | | the code are: | | Copyright (c) 2005 | | 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. | | | +-----------------------------------------------------------------+ | this file contains the assembler portion of the irq handling | +-----------------------------------------------------------------+ \*===============================================================*/ /***********************************************************************/ /* */ /* Module: irq_asm.S */ /* Date: 07/17/2003 */ /* Purpose: RTEMS assembly code for PowerPC IRQ veneers */ /* */ /*---------------------------------------------------------------------*/ /* */ /* Description: This file contains the assembly code for the */ /* PowerPC IRQ veneers for RTEMS. */ /* */ /*---------------------------------------------------------------------*/ /* */ /* Code */ /* References: RTEMS assembly code for PowerPC IRQ veneers */ /* Module: irq_asm.S */ /* Project: RTEMS 4.6.0pre1 / MCF8260ads BSP */ /* Version 1.2 */ /* Date: 04/18/2002 */ /* */ /* Author(s) / Copyright(s): */ /* */ /* The license and distribution terms for this file may be */ /* found in found in the file LICENSE in this distribution or at */ /* http://www.rtems.com/license/LICENSE. */ /* */ /* Modified to support the MCP750. */ /* Modifications Copyright (C) 1999 Eric Valette.valette@crf.canon.fr*/ /* */ /*---------------------------------------------------------------------*/ /* */ /* Partially based on the code references which are named above. */ /* Adaptions, modifications, enhancements and any recent parts of */ /* the code are under the right of */ /* */ /* IPR Engineering, Dachauer Straße 38, D-80335 München */ /* Copyright(C) 2003 */ /* */ /*---------------------------------------------------------------------*/ /* */ /* IPR Engineering makes no representation or warranties with */ /* respect to the performance of this computer program, and */ /* specifically disclaims any responsibility for any damages, */ /* special or consequential, connected with the use of this program. */ /* */ /*---------------------------------------------------------------------*/ /* */ /* Version history: 1.0 */ /* */ /***********************************************************************/ /*#include */ #include "../vectors/vectors.h" #include /* for PPC_HAS_FPU */ #include #include #include #define SYNC \ sync; \ isync .text .p2align 5 PUBLIC_VAR(decrementer_exception_vector_prolog_code) SYM (decrementer_exception_vector_prolog_code): /* * let room for exception frame */ stwu r1, - (EXCEPTION_FRAME_END)(r1) stw r4, GPR4_OFFSET(r1) li r4, ASM_DEC_VECTOR ba shared_raw_irq_code_entry PUBLIC_VAR (decrementer_exception_vector_prolog_code_size) decrementer_exception_vector_prolog_code_size = . - decrementer_exception_vector_prolog_code PUBLIC_VAR(external_exception_vector_prolog_code) SYM (external_exception_vector_prolog_code): /* * let room for exception frame */ stwu r1, - (EXCEPTION_FRAME_END)(r1) stw r4, GPR4_OFFSET(r1) li r4, ASM_EXT_VECTOR ba shared_raw_irq_code_entry PUBLIC_VAR (external_exception_vector_prolog_code_size) external_exception_vector_prolog_code_size = . - external_exception_vector_prolog_code PUBLIC_VAR(system_management_exception_vector_prolog_code) SYM (system_management_exception_vector_prolog_code): /* * let room for exception frame */ stwu r1, - (EXCEPTION_FRAME_END)(r1) stw r4, GPR4_OFFSET(r1) li r4, ASM_SYSMGMT_VECTOR ba shared_raw_irq_code_entry PUBLIC_VAR (system_management_exception_vector_prolog_code_size) system_management_exception_vector_prolog_code_size = . - system_management_exception_vector_prolog_code PUBLIC_VAR(shared_raw_irq_code_entry) PUBLIC_VAR(C_dispatch_irq_handler) .p2align 5 SYM (shared_raw_irq_code_entry): /* * Entry conditions : * Registers already saved : R1, R4 * R1 : points to a location with enough room for the * interrupt frame * R4 : vector number */ /* * Save SRR0/SRR1 As soon As possible as it is the minimal needed * to reenable exception processing */ stw r0, GPR0_OFFSET(r1) stw r2, GPR2_OFFSET(r1) stw r3, GPR3_OFFSET(r1) mfsrr0 r0 mfsrr1 r2 mfmsr r3 stw r0, SRR0_FRAME_OFFSET(r1) stw r2, SRR1_FRAME_OFFSET(r1) /* * Enable data and instruction address translation, exception recovery * * also, on CPUs with FP, enable FP so that FP context can be * saved and restored (using FP instructions) */ #if (PPC_HAS_FPU == 0) ori r3, r3, MSR_RI | MSR_DR/*| MSR_IR*/ #else ori r3, r3, MSR_RI | MSR_DR | /*MSR_IR |*/ MSR_FP #endif 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 mflr r8 stw r5, EXC_CR_OFFSET(r1) stw r6, EXC_CTR_OFFSET(r1) stw r7, EXC_XER_OFFSET(r1) stw r8, EXC_LR_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 /* * Get current nesting level in R2 */ /* mfspr r2, SPRG0 */ addis r6, 0, _ISR_Nest_level@ha lwz r2, _ISR_Nest_level@l( r6 ) /* * Check if stack switch is necessary */ cmpwi r2,0 bne nested mfspr r1, SPRG1 nested: /* * Start Incrementing nesting level in R2 */ addi r2,r2,1 addis r6, 0, _ISR_Nest_level@ha stw r2, _ISR_Nest_level@l( r6 ) /* * Start Incrementing _Thread_Dispatch_disable_level R4 = _Thread_Dispatch_disable_level */ lwz r6,_Thread_Dispatch_disable_level@l(r15) /* * store new nesting level in SPRG0 */ /* mtspr SPRG0, r2 */ addi r6, r6, 1 mfmsr r5 /* * 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 Interrupt frame is passed just * in case... */ addi r3, r14, 0x8 bl C_dispatch_irq_handler /* C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) */ /* * 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 */ /* mfspr r2, SPRG0 */ addis r6, 0, _ISR_Nest_level@ha lwz r2, _ISR_Nest_level@l( r6 ) /* * start decrementing _Thread_Dispatch_disable_level */ lwz r3,_Thread_Dispatch_disable_level@l(r15) addi r2, r2, -1 /* Continue decrementing nesting level */ addi r3, r3, -1 /* Continue decrementing _Thread_Dispatch_disable_level */ stw r2, _ISR_Nest_level@l( r6 ) /* mtspr SPRG0, r2 */ /* 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, _Context_Switch_necessary@ha lwz r5, _Context_Switch_necessary@l(r4) cmpwi r5, 0 bne switch addis r6, 0, _ISR_Signals_to_thread_executing@ha lwz r7, _ISR_Signals_to_thread_executing@l(r6) cmpwi r7, 0 li r8, 0 beq easy_exit stw r8, _ISR_Signals_to_thread_executing@l(r6) /* * going to call _ThreadProcessSignalsFromIrq * Push a complete exception like frame... */ stmw r16, GPR16_OFFSET(r1) addi r3, r1, 0x8 /* * compute SP at exception entry */ addi r2, r1, EXCEPTION_FRAME_END /* * store it at the right place */ stw r2, GPR1_OFFSET(r1) /* * Call High Level signal handling code */ bl _ThreadProcessSignalsFromIrq /* * 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) /* * Disable data and instruction translation. Make path non recoverable... */ mfmsr r3 xori r3, r3, MSR_RI | MSR_DR/*| MSR_IR */ mtmsr r3 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 switch: bl SYM (_Thread_Dispatch) 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, data and instruction * translation. */ mfmsr r3 xori r3, r3, MSR_RI | MSR_DR/*| MSR_IR */ mtmsr r3 SYNC /* * Restore rfi related settings */ lwz r4, SRR1_FRAME_OFFSET(r1) lwz r2, SRR0_FRAME_OFFSET(r1) lwz r3, GPR3_OFFSET(r1) lwz r0, GPR0_OFFSET(r1) mtsrr1 r4 mtsrr0 r2 lwz r4, GPR4_OFFSET(r1) lwz r2, GPR2_OFFSET(r1) addi r1,r1, EXCEPTION_FRAME_END SYNC rfi