source: rtems/c/src/lib/libbsp/powerpc/shared/irq/irq_asm.S @ 677c3d81

4.104.114.84.95
Last change on this file since 677c3d81 was 5b8eb3f0, checked in by Till Straumann <strauman@…>, on 11/30/05 at 02:21:11

2005-11-29 Till Straumann <strauman@…>

  • shared/irq/irq_asm.S, shared/vectors/vectors.S: Clear CR[6] before invoking high-level handler to make sure no varargs fn callee assumes there are FP arguments.
  • Property mode set to 100644
File size: 9.0 KB
Line 
1/*
2 *  This file contains the assembly code for the PowerPC
3 *  IRQ veneers for RTEMS.
4 *
5 *  The license and distribution terms for this file may be
6 *  found in found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  Modified to support the MCP750.
10 *  Modifications Copyright (C) 1999 Eric Valette. valette@crf.canon.fr
11 *
12 *  Till Straumann <strauman@slac.stanford.edu>, 2003/7:
13 *    - store isr nesting level in _ISR_Nest_level rather than
14 *      SPRG0 - RTEMS relies on that variable.
15 *  Till Straumann <strauman@slac.stanford.edu>, 2005/4:
16 *    - DONT enable FP across ISR since fpregs are not saved!!
17 *      FPU is used by Thread_Dispatch however...
18 *
19 * $Id$
20 */
21
22#include <rtems/asm.h>
23#include <rtems/score/cpu.h>
24#include <bsp/vectors.h>
25#include <libcpu/raw_exception.h>
26
27#define SYNC \
28        sync; \
29        isync
30
31        .text
32        .p2align 5
33
34        PUBLIC_VAR(decrementer_exception_vector_prolog_code)
35
36SYM (decrementer_exception_vector_prolog_code):
37        /*
38         * let room for exception frame
39         */
40        stwu    r1, - (EXCEPTION_FRAME_END)(r1)
41        stw     r4, GPR4_OFFSET(r1)
42        li      r4, ASM_DEC_VECTOR
43        ba      shared_raw_irq_code_entry
44
45        PUBLIC_VAR (decrementer_exception_vector_prolog_code_size)
46
47        decrementer_exception_vector_prolog_code_size = . - decrementer_exception_vector_prolog_code
48
49        PUBLIC_VAR(external_exception_vector_prolog_code)
50
51SYM (external_exception_vector_prolog_code):
52        /*
53         * let room for exception frame
54         */
55        stwu    r1, - (EXCEPTION_FRAME_END)(r1)
56        stw     r4, GPR4_OFFSET(r1)
57        li      r4, ASM_EXT_VECTOR
58        ba      shared_raw_irq_code_entry
59
60        PUBLIC_VAR (external_exception_vector_prolog_code_size)
61
62        external_exception_vector_prolog_code_size = . - external_exception_vector_prolog_code
63
64        PUBLIC_VAR(shared_raw_irq_code_entry)
65        PUBLIC_VAR(C_dispatch_irq_handler)
66
67        .p2align 5
68SYM (shared_raw_irq_code_entry):
69        /*
70         * Entry conditions :
71         *      Registers already saved : R1, R4
72         *      R1  :   points to a location with enough room for the
73         *              interrupt frame
74         *      R4  :   vector number
75         */
76        /*
77         * Save SRR0/SRR1 As soon As possible as it is the minimal needed
78         * to reenable exception processing
79         */
80        stw     r0, GPR0_OFFSET(r1)
81        /* PPC EABI: R2 is reserved (pointer to short data .sdata2) - we won't touch it
82         * but we still save/restore it, just in case...
83         */
84        stw     r2, GPR2_OFFSET(r1)
85        stw     r3, GPR3_OFFSET(r1)
86
87        mfsrr0  r0
88        mfsrr1  r3
89
90        stw     r0, SRR0_FRAME_OFFSET(r1)
91        stw     r3, SRR1_FRAME_OFFSET(r1)
92
93        mfmsr   r3
94        /*
95         * Enable data and instruction address translation, exception recovery
96         */
97        ori     r3, r3, MSR_RI | MSR_IR | MSR_DR
98        mtmsr   r3
99        SYNC
100        /*
101         * Push C scratch registers on the current stack. It may
102         * actually be the thread stack or the interrupt stack.
103         * Anyway we have to make it in order to be able to call C/C++
104         * functions. Depending on the nesting interrupt level, we will
105         * switch to the right stack later.
106         */
107        stw     r5, GPR5_OFFSET(r1)
108        stw     r6, GPR6_OFFSET(r1)
109        stw     r7, GPR7_OFFSET(r1)
110        stw     r8, GPR8_OFFSET(r1)
111        stw     r9, GPR9_OFFSET(r1)
112        stw     r10, GPR10_OFFSET(r1)
113        stw     r11, GPR11_OFFSET(r1)
114        stw     r12, GPR12_OFFSET(r1)
115        stw     r13, GPR13_OFFSET(r1)
116
117        mfcr    r5
118        mfctr   r6
119        mfxer   r7
120        mflr    r8
121
122        stw     r5,  EXC_CR_OFFSET(r1)
123        stw     r6,  EXC_CTR_OFFSET(r1)
124        stw     r7,  EXC_XER_OFFSET(r1)
125        stw     r8,  EXC_LR_OFFSET(r1)
126
127        /*
128         * Add some non volatile registers to store information
129         * that will be used when returning from C handler
130         */
131        stw     r14, GPR14_OFFSET(r1)
132        stw     r15, GPR15_OFFSET(r1)
133        /*
134         * save current stack pointer location in R14
135         */
136        addi    r14, r1, 0
137        /*
138         * store part of _Thread_Dispatch_disable_level address in R15
139         */
140        addis r15,0, _Thread_Dispatch_disable_level@ha
141#if BROKEN_ISR_NEST_LEVEL
142        /*
143         * Get current nesting level in R3
144         */
145        mfspr   r3, SPRG0
146#else
147        /*
148         * Retrieve current nesting level from _ISR_Nest_level
149         */
150        lis             r7, _ISR_Nest_level@ha
151        lwz             r3, _ISR_Nest_level@l(r7)
152#endif
153        /*
154         * Check if stack switch is necessary
155         */
156        cmpwi   r3,0
157        bne     nested
158        mfspr   r1, SPRG1
159
160nested:
161        /*
162         * Start Incrementing nesting level in R3
163         */
164        addi    r3,r3,1
165        /*
166         * Start Incrementing _Thread_Dispatch_disable_level R4 = _Thread_Dispatch_disable_level
167         */
168        lwz     r6,_Thread_Dispatch_disable_level@l(r15)
169#if BROKEN_ISR_NEST_LEVEL
170        /*
171         * Store new nesting level in SPRG0
172         */
173        mtspr   SPRG0, r3
174#else
175        /* store new nesting level in _ISR_Nest_level */
176        stw             r3, _ISR_Nest_level@l(r7)
177#endif
178
179        addi    r6, r6, 1
180        mfmsr   r5
181        /*
182         * store new _Thread_Dispatch_disable_level value
183         */
184        stw     r6, _Thread_Dispatch_disable_level@l(r15)
185        /*
186         * We are now running on the interrupt stack. External and decrementer
187         * exceptions are still disabled. I see no purpose trying to optimize
188         * further assembler code.
189         */
190        /*
191         * Call C exception handler for decrementer Interrupt frame is passed just
192         * in case...
193         */
194        addi    r3, r14, 0x8
195        /* clear CR[6] to make sure no varargs fn callee assumes there are FP args passed */
196        crxor   6,6,6
197        bl      C_dispatch_irq_handler /* C_dispatch_irq_handler(cpu_interrupt_frame* r3, vector r4) */
198        /*
199         * start decrementing nesting level. Note : do not test result against 0
200         * value as an easy exit condition because if interrupt nesting level > 1
201         * then _Thread_Dispatch_disable_level > 1
202         */
203#if BROKEN_ISR_NEST_LEVEL
204        mfspr   r4, SPRG0
205#else
206        lis             r7, _ISR_Nest_level@ha
207        lwz             r4, _ISR_Nest_level@l(r7)
208#endif
209        /*
210         * start decrementing _Thread_Dispatch_disable_level
211         */
212        lwz     r3,_Thread_Dispatch_disable_level@l(r15)
213        addi    r4, r4, -1      /* Continue decrementing nesting level */
214        addi    r3, r3, -1      /* Continue decrementing _Thread_Dispatch_disable_level */
215#if BROKEN_ISR_NEST_LEVEL
216        mtspr   SPRG0, r4       /* End decrementing nesting level */
217#else
218        stw             r4, _ISR_Nest_level@l(r7) /* End decrementing nesting level */
219#endif
220        stw     r3,_Thread_Dispatch_disable_level@l(r15) /* End decrementing _Thread_Dispatch_disable_level */
221        cmpwi   r3, 0
222        /*
223         * switch back to original stack (done here just optimize registers
224         * contention. Could have been done before...)
225         */
226        addi    r1, r14, 0
227        bne     easy_exit /* if (_Thread_Dispatch_disable_level != 0) goto easy_exit */
228        /*
229         * Here we are running again on the thread system stack.
230         * We have interrupt nesting level = _Thread_Dispatch_disable_level = 0.
231         * Interrupt are still disabled. Time to check if scheduler request to
232         * do something with the current thread...
233         */
234        addis   r4, 0, _Context_Switch_necessary@ha
235        lwz     r5, _Context_Switch_necessary@l(r4)
236        cmpwi   r5, 0
237        bne     switch
238
239        addis   r6, 0, _ISR_Signals_to_thread_executing@ha
240        lwz     r7, _ISR_Signals_to_thread_executing@l(r6)
241        cmpwi   r7, 0
242        li      r8, 0
243        beq     easy_exit
244        stw     r8, _ISR_Signals_to_thread_executing@l(r6)
245        /*
246         * going to call _ThreadProcessSignalsFromIrq
247         * Push a complete exception like frame...
248         */
249        stmw    r16, GPR16_OFFSET(r1)
250        addi    r3, r1, 0x8
251        /*
252         * compute SP at exception entry
253         */
254        addi    r4, r1, EXCEPTION_FRAME_END
255        /*
256         * store it at the right place
257         */
258        stw     r4, GPR1_OFFSET(r1)
259        /*
260         * Call High Level signal handling code
261         */
262        bl      _ThreadProcessSignalsFromIrq
263        /*
264         * start restoring exception like frame
265         */
266        lwz     r31,  EXC_CTR_OFFSET(r1)
267        lwz     r30,  EXC_XER_OFFSET(r1)
268        lwz     r29,  EXC_CR_OFFSET(r1)
269        lwz     r28,  EXC_LR_OFFSET(r1)
270
271        mtctr   r31
272        mtxer   r30
273        mtcr    r29
274        mtlr    r28
275
276        lmw     r4, GPR4_OFFSET(r1)
277        lwz     r2, GPR2_OFFSET(r1)
278        lwz     r0, GPR0_OFFSET(r1)
279
280        /*
281         * Disable data and instruction translation. Make path non recoverable...
282         */
283        mfmsr   r3
284        xori    r3, r3, MSR_RI | MSR_IR | MSR_DR
285        mtmsr   r3
286        SYNC
287        /*
288         * Restore rfi related settings
289         */
290
291        lwz     r3, SRR1_FRAME_OFFSET(r1)
292        mtsrr1  r3
293        lwz     r3, SRR0_FRAME_OFFSET(r1)
294        mtsrr0  r3
295
296        lwz     r3, GPR3_OFFSET(r1)
297        addi    r1,r1, EXCEPTION_FRAME_END
298        SYNC
299        rfi
300
301switch:
302#if ( PPC_HAS_FPU != 0 )
303#if ! defined( CPU_USE_DEFERRED_FP_SWITCH )
304#error missing include file???
305#endif
306        mfmsr  r4
307#if ( CPU_USE_DEFERRED_FP_SWITCH == TRUE )
308        /* if the executing thread has FP enabled propagate
309         * this now so _Thread_Dispatch can save/restore the FPREGS
310         * NOTE: it is *crucial* to disable the FPU across the
311         *       user ISR [independent of using the 'deferred'
312         *       strategy or not]. We don't save FP regs across
313         *       the user ISR and hence we prefer an exception to
314         *       be raised rather than experiencing corruption.
315         */
316        lwz    r3, SRR1_FRAME_OFFSET(r1)
317        rlwimi r4, r3, 0, 18, 18 /* MSR_FP */
318#else
319        ori    r4, r4, MSR_FP
320#endif
321        mtmsr  r4
322#endif
323        bl      SYM (_Thread_Dispatch)
324
325easy_exit:
326        /*
327         * start restoring interrupt frame
328         */
329        lwz     r3,  EXC_CTR_OFFSET(r1)
330        lwz     r4,  EXC_XER_OFFSET(r1)
331        lwz     r5,  EXC_CR_OFFSET(r1)
332        lwz     r6,  EXC_LR_OFFSET(r1)
333
334        mtctr   r3
335        mtxer   r4
336        mtcr    r5
337        mtlr    r6
338
339        lwz     r15, GPR15_OFFSET(r1)
340        lwz     r14, GPR14_OFFSET(r1)
341        lwz     r13, GPR13_OFFSET(r1)
342        lwz     r12, GPR12_OFFSET(r1)
343        lwz     r11, GPR11_OFFSET(r1)
344        lwz     r10, GPR10_OFFSET(r1)
345        lwz     r9, GPR9_OFFSET(r1)
346        lwz     r8, GPR8_OFFSET(r1)
347        lwz     r7, GPR7_OFFSET(r1)
348        lwz     r6, GPR6_OFFSET(r1)
349        lwz     r5, GPR5_OFFSET(r1)
350
351        /*
352         * Disable nested exception processing, data and instruction
353         * translation.
354         */
355        mfmsr   r3
356        xori    r3, r3, MSR_RI | MSR_IR | MSR_DR
357        mtmsr   r3
358        SYNC
359        /*
360         * Restore rfi related settings
361         */
362
363        lwz     r4, SRR1_FRAME_OFFSET(r1)
364        lwz     r3, SRR0_FRAME_OFFSET(r1)
365        lwz     r2, GPR2_OFFSET(r1)
366        lwz     r0, GPR0_OFFSET(r1)
367
368        mtsrr1  r4
369        mtsrr0  r3
370        lwz     r4, GPR4_OFFSET(r1)
371        lwz     r3, GPR3_OFFSET(r1)
372        addi    r1,r1, EXCEPTION_FRAME_END
373        SYNC
374        rfi
Note: See TracBrowser for help on using the repository browser.