Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:59

0001 /*
0002  * irq_asm.S
0003  *
0004  *  This file contains the assembly code for the PowerPC
0005  *  IRQ veneers for RTEMS.
0006  *
0007  *  The license and distribution terms for this file may be
0008  *  found in the file LICENSE in this distribution or at
0009  *  http://www.rtems.org/license/LICENSE.
0010  *
0011  *
0012  *  MPC5xx port sponsored by Defence Research and Development Canada - Suffield
0013  *  Copyright (C) 2004, Real-Time Systems Inc. (querbach@realtime.bc.ca)
0014  *
0015  *  Derived from libbsp/powerpc/mbx8xx/irq/irq_asm.S:
0016  *
0017  *  Modified to support the MCP750.
0018  *  Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
0019  *
0020  *  Till Straumann <strauman@slac.stanford.edu>, 2003/7:
0021  *    - store isr nesting level in _ISR_Nest_level rather than
0022  *      SPRG0 - RTEMS relies on that variable.
0023  */
0024 
0025 #include <rtems/asm.h>
0026 #include <rtems/score/cpu.h>
0027 #include <rtems/score/percpu.h>
0028 #include <libcpu/vectors.h>
0029 #include <libcpu/raw_exception.h>
0030 #include <bsp.h>
0031 
0032 #define SYNC \
0033     sync; \
0034     isync
0035 
0036 /*
0037  * Common handler for interrupt exceptions.
0038  *
0039  * The function CPU_rtems_irq_mng_init() initializes the decrementer and
0040  * external interrupt entries in the exception handler table with pointers
0041  * to this routine, which saves the remainder of the interrupted code's
0042  * state, then calls C_dispatch_irq_handler().
0043  *
0044  * On entry, R1 points to a new exception stack frame in which R3, R4, and
0045  * LR have been saved.  R4 holds the exception number.
0046  */
0047     PUBLIC_VAR(C_dispatch_irq_handler)
0048 
0049     PUBLIC_VAR(dispatch_irq_handler)
0050 SYM (dispatch_irq_handler):
0051     /*
0052      * Save SRR0/SRR1 As soon As possible as it is the minimal needed
0053      * to re-enable exception processing.
0054      *
0055      * Note that R2 should never change (it's the EABI pointer to
0056      * .sdata2), but we save it just in case.
0057          */
0058     stw r0, GPR0_OFFSET(r1)
0059     stw r2, GPR2_OFFSET(r1)
0060 
0061     mfsrr0  r0
0062     mfsrr1  r3
0063 
0064     stw r0, SRR0_FRAME_OFFSET(r1)
0065     stw r3, SRR1_FRAME_OFFSET(r1)
0066 
0067     /*
0068      * Enable exception recovery.  Also enable FP so that FP context
0069      * can be saved and restored (using FP instructions).
0070      */
0071     mfmsr   r3
0072     ori     r3, r3, MSR_RI | MSR_FP
0073     mtmsr   r3
0074     SYNC
0075 
0076     /*
0077      * Push C scratch registers on the current stack. It may actually be
0078      * the thread stack or the interrupt stack.  Anyway we have to make
0079      * it in order to be able to call C/C++ functions. Depending on the
0080      * nesting interrupt level, we will switch to the right stack later.
0081      */
0082     stw r5, GPR5_OFFSET(r1)
0083     stw r6, GPR6_OFFSET(r1)
0084     stw r7, GPR7_OFFSET(r1)
0085     stw r8, GPR8_OFFSET(r1)
0086     stw r9, GPR9_OFFSET(r1)
0087     stw r10, GPR10_OFFSET(r1)
0088     stw r11, GPR11_OFFSET(r1)
0089     stw r12, GPR12_OFFSET(r1)
0090     stw r13, GPR13_OFFSET(r1)
0091 
0092     mfcr    r5
0093     mfctr   r6
0094     mfxer   r7
0095 
0096     stw r5,  EXC_CR_OFFSET(r1)
0097     stw r6,  EXC_CTR_OFFSET(r1)
0098     stw r7,  EXC_XER_OFFSET(r1)
0099 
0100     /*
0101      * Add some non volatile registers to store information that will be
0102      * used when returning from C handler.
0103      */
0104     stw r14, GPR14_OFFSET(r1)
0105     stw r15, GPR15_OFFSET(r1)
0106 
0107     /*
0108      * Save current stack pointer location in R14.
0109      */
0110     addi    r14, r1, 0
0111 
0112     /*
0113      * store part of THREAD_DISPATCH_DISABLE_LEVEL address in R15
0114      */
0115     addis r15, 0, THREAD_DISPATCH_DISABLE_LEVEL@ha
0116 
0117     /*
0118      * Retrieve current nesting level from _ISR_Nest_level
0119      */
0120     lis     r7, ISR_NEST_LEVEL@ha
0121     lwz     r3, ISR_NEST_LEVEL@l(r7)
0122 
0123     /*
0124      * Check if stack switch is necessary
0125      */
0126     cmpwi   r3, 0
0127     bne nested
0128 
0129     mfspr   r1, SPRG1       /* switch to interrupt stack */
0130 nested:
0131 
0132     /*
0133      * Start Incrementing nesting level in R3
0134      */
0135     addi    r3, r3, 1
0136 
0137     /*
0138      * Start Incrementing THREAD_DISPATCH_DISABLE_LEVEL R4 = THREAD_DISPATCH_DISABLE_LEVEL
0139      */
0140     lwz r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15)
0141 
0142     /* store new nesting level in _ISR_Nest_level */
0143     stw r3, ISR_NEST_LEVEL@l(r7)
0144 
0145     addi    r6, r6, 1
0146 
0147     /*
0148      * store new THREAD_DISPATCH_DISABLE_LEVEL value
0149      */
0150     stw r6, THREAD_DISPATCH_DISABLE_LEVEL@l(r15)
0151 
0152     /*
0153      * We are now running on the interrupt stack. External and decrementer
0154      * exceptions are still disabled. I see no purpose trying to optimize
0155      * further assembler code.
0156      */
0157 
0158     /*
0159      * Call C exception handler for decrementer or external interrupt.
0160      * Pass frame along just in case..
0161      *
0162      * C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4)
0163      */
0164     addi    r3, r14, 0x8
0165     bl  C_dispatch_irq_handler
0166 
0167     /*
0168      * start decrementing nesting level. Note : do not test result against 0
0169      * value as an easy exit condition because if interrupt nesting level > 1
0170      * then THREAD_DISPATCH_DISABLE_LEVEL > 1
0171      */
0172     lis     r7, ISR_NEST_LEVEL@ha
0173     lwz     r4, ISR_NEST_LEVEL@l(r7)
0174 
0175     /*
0176      * start decrementing THREAD_DISPATCH_DISABLE_LEVEL
0177      */
0178     lwz r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15)
0179 
0180     addi    r4, r4, -1  /* Continue decrementing nesting level */
0181     addi    r3, r3, -1  /* Continue decrementing THREAD_DISPATCH_DISABLE_LEVEL */
0182 
0183     stw r4, ISR_NEST_LEVEL@l(r7) /* End decrementing nesting level */
0184     stw r3,THREAD_DISPATCH_DISABLE_LEVEL@l(r15) /* End decrementing THREAD_DISPATCH_DISABLE_LEVEL */
0185 
0186     cmpwi   r3, 0
0187 
0188     /*
0189      * switch back to original stack (done here just optimize registers
0190      * contention. Could have been done before...)
0191      */
0192     addi    r1, r14, 0
0193     bne easy_exit /* if (THREAD_DISPATCH_DISABLE_LEVEL != 0) goto easy_exit */
0194 
0195     /*
0196      * Here we are running again on the thread system stack.
0197      * We have interrupt nesting level = THREAD_DISPATCH_DISABLE_LEVEL = 0.
0198      * Interrupt are still disabled. Time to check if scheduler request to
0199      * do something with the current thread...
0200      */
0201     addis   r4, 0, DISPATCH_NEEDED@ha
0202     lbz r5, DISPATCH_NEEDED@l(r4)
0203     cmpwi   r5, 0
0204     beq easy_exit
0205 
0206     /*
0207      * going to call _Thread_Dispatch
0208      * Push a complete exception like frame...
0209      */
0210     stmw    r16, GPR16_OFFSET(r1)
0211     addi    r3, r1, 0x8
0212 
0213         /*
0214          * compute SP at exception entry
0215          */
0216         addi    r4, r1, EXCEPTION_FRAME_END
0217 
0218         /*
0219          * store it at the right place
0220          */
0221         stw     r4, GPR1_OFFSET(r1)
0222 
0223     /*
0224      * Call High Level signal handling code
0225      */
0226     bl  _Thread_Dispatch
0227 
0228     /*
0229      * start restoring exception like frame
0230      */
0231     lwz r31,  EXC_CTR_OFFSET(r1)
0232     lwz r30,  EXC_XER_OFFSET(r1)
0233     lwz r29,  EXC_CR_OFFSET(r1)
0234     lwz r28,  EXC_LR_OFFSET(r1)
0235 
0236     mtctr   r31
0237     mtxer   r30
0238     mtcr    r29
0239     mtlr    r28
0240 
0241     lmw r4, GPR4_OFFSET(r1)
0242     lwz r2, GPR2_OFFSET(r1)
0243     lwz r0, GPR0_OFFSET(r1)
0244 
0245     /*
0246      * Make path non recoverable...
0247      */
0248     mtspr   nri, r0
0249     SYNC
0250 
0251     /*
0252      * Restore rfi related settings
0253      */
0254 
0255     lwz r3, SRR1_FRAME_OFFSET(r1)
0256     mtsrr1  r3
0257     lwz r3, SRR0_FRAME_OFFSET(r1)
0258     mtsrr0  r3
0259 
0260     lwz r3, GPR3_OFFSET(r1)
0261     addi    r1,r1, EXCEPTION_FRAME_END
0262     SYNC
0263     rfi
0264 
0265 
0266 easy_exit:
0267     /*
0268      * start restoring interrupt frame
0269      */
0270     lwz r3,  EXC_CTR_OFFSET(r1)
0271     lwz r4,  EXC_XER_OFFSET(r1)
0272     lwz r5,  EXC_CR_OFFSET(r1)
0273     lwz r6,  EXC_LR_OFFSET(r1)
0274 
0275     mtctr   r3
0276     mtxer   r4
0277     mtcr    r5
0278     mtlr    r6
0279 
0280     lwz r15, GPR15_OFFSET(r1)
0281     lwz r14, GPR14_OFFSET(r1)
0282     lwz r13, GPR13_OFFSET(r1)
0283     lwz r12, GPR12_OFFSET(r1)
0284     lwz r11, GPR11_OFFSET(r1)
0285     lwz r10, GPR10_OFFSET(r1)
0286     lwz r9, GPR9_OFFSET(r1)
0287     lwz r8, GPR8_OFFSET(r1)
0288     lwz r7, GPR7_OFFSET(r1)
0289     lwz r6, GPR6_OFFSET(r1)
0290     lwz r5, GPR5_OFFSET(r1)
0291 
0292     /*
0293      * Disable nested exception processing.
0294      */
0295     mtspr   nri, r0
0296     SYNC
0297 
0298     /*
0299      * Restore rfi related settings
0300      */
0301     lwz r4, SRR1_FRAME_OFFSET(r1)
0302     lwz r3, SRR0_FRAME_OFFSET(r1)
0303     lwz r2, GPR2_OFFSET(r1)
0304     lwz r0, GPR0_OFFSET(r1)
0305 
0306     mtsrr1  r4
0307     mtsrr0  r3
0308     lwz r4, GPR4_OFFSET(r1)
0309     lwz r3, GPR3_OFFSET(r1)
0310     addi    r1,r1, EXCEPTION_FRAME_END
0311     SYNC
0312     rfi