source: rtems/c/src/lib/libcpu/powerpc/new-exceptions/bspsupport/ppc_exc.S @ 38f5e61

4.104.114.95
Last change on this file since 38f5e61 was 38f5e61, checked in by Till Straumann <strauman@…>, on 07/10/08 at 21:29:27

2008-07-10 Till Straumann <strauman@…>

  • new-exceptions/bspsupport/ppc_exc.S: must disable interrupts prior to restoring SRRs (thanks to Sebastian Huber)
  • Property mode set to 100644
File size: 10.8 KB
Line 
1/*
2 * (c) 1999, Eric Valette valette@crf.canon.fr
3 *
4 * Modified and partially rewritten by Till Straumann, 2007
5 *
6 * Low-level assembly code for PPC exceptions.
7 *
8 * This file was written with the goal to eliminate
9 * ALL #ifdef <cpu_flavor> conditionals -- please do not
10 * reintroduce such statements.
11 */
12
13/* Load macro definitions */
14#include "ppc_exc_asm_macros.h"
15
16/******************************************************/
17/*  PROLOGUES                                         */
18/******************************************************/
19
20        /*
21         * Expand prologue snippets for classic, ppc405-critical, bookE-critical
22         * and E500 machine-check, synchronous and asynchronous exceptions
23         */
24        PPC_EXC_MIN_PROLOG_SYNC  _NAME=tmpl_std        _VEC=0 _PRI=std  _FLVR=std
25        PPC_EXC_MIN_PROLOG_SYNC  _NAME=tmpl_p405_crit  _VEC=0 _PRI=crit _FLVR=p405_crit
26        PPC_EXC_MIN_PROLOG_SYNC  _NAME=tmpl_bookE_crit _VEC=0 _PRI=crit _FLVR=bookE_crit
27        PPC_EXC_MIN_PROLOG_SYNC  _NAME=tmpl_e500_mchk  _VEC=0 _PRI=mchk _FLVR=e500_mchk
28
29        PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_std        _VEC=0 _PRI=std  _FLVR=std
30        PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_p405_crit  _VEC=0 _PRI=crit _FLVR=p405_crit
31        PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_bookE_crit _VEC=0 _PRI=crit _FLVR=bookE_crit
32        PPC_EXC_MIN_PROLOG_ASYNC _NAME=tmpl_e500_mchk  _VEC=0 _PRI=mchk _FLVR=e500_mchk
33
34        .global ppc_exc_min_prolog_size
35ppc_exc_min_prolog_size      = 4 * 4
36
37    /* Special prologue for 603e-style CPUs.
38         *
39         * 603e shadows GPR0..GPR3 for certain exceptions. We must switch
40     * that off before we can use the stack pointer. Note that this is
41     * ONLY safe if the shadowing is actually active -- otherwise, r1
42     * is destroyed. We deliberately use r1 so problems become obvious
43     * if this is misused!
44     */
45        .global ppc_exc_tgpr_clr_prolog
46ppc_exc_tgpr_clr_prolog:
47    mfmsr   r1
48    rlwinm  r1,r1,0,15,13
49    mtmsr   r1
50    isync
51        /* FALL THRU TO 'auto' PROLOG */
52
53/* Determine vector dynamically/automatically
54 *
55 * BUT: - only standard exceptions (no critical ones)
56 *      - vector offset must be on 256 Byte boundary.
57 */
58        .global ppc_exc_min_prolog_auto
59ppc_exc_min_prolog_auto:
60        stwu    r1, -EXCEPTION_FRAME_END(r1)
61        stw             r3, GPR3_OFFSET(r1)
62        mflr    r3
63        bla  wrap_auto
64
65        .global ppc_exc_tgpr_clr_prolog_size
66ppc_exc_tgpr_clr_prolog_size = . - ppc_exc_tgpr_clr_prolog
67
68/*
69 * Automatic vector, asynchronous exception; however,
70 * automatic vector calculation is less efficient than
71 * using an explicit vector in a minimal prolog snippet.
72 * The latter method is preferable since there usually
73 * are few asynchronous exceptions.
74 *
75 * For generic exceptions (which are the bulk) using
76 * the 'auto' prologue is OK since performance is not
77 * really an issue.
78 */
79        .global ppc_exc_min_prolog_auto_async
80ppc_exc_min_prolog_auto_async:
81        stw             r1, ppc_exc_lock_std@sdarel(r13)
82        stw             r3, ppc_exc_gpr3_std@sdarel(r13)
83        mflr    r3
84        bla  wrap_auto_async
85
86/******************************************************/
87/*  WRAPPERS                                          */
88/******************************************************/
89
90        /* Tag start and end of the wrappers.
91         * If exceptions are installed farther removed
92         * from the text area than 32M then the wrappers
93         * must be moved to an area that is reachable
94         * from where the prologues reside. Branches into
95         * C-code are far.
96         */
97
98        .global __ppc_exc_wrappers_start
99__ppc_exc_wrappers_start = .
100
101        /* Expand wrappers for different exception flavors */
102
103        /* Standard/classic powerpc */
104        WRAP _FLVR=std _PRI=std _SRR0=srr0 _SRR1=srr1 _RFI=rfi
105
106        /* ppc405 has a critical exception using srr2/srr3 */
107        WRAP _FLVR=p405_crit _PRI=crit _SRR0=srr2 _SRR1=srr3 _RFI=rfci
108
109        /* bookE has critical exception using csrr0 cssr1 */
110        WRAP _FLVR=bookE_crit _PRI=crit _SRR0=csrr0 _SRR1=csrr1 _RFI=rfci
111
112        /* e500 has machine-check exception using mcsrr0 mcssr1 */
113        WRAP _FLVR=e500_mchk _PRI=mchk _SRR0=mcsrr0 _SRR1=mcsrr1 _RFI=rfmci
114
115
116        /* LR holds vector, r3 holds orig. LR */
117wrap_auto:
118        stw             r14, GPR14_OFFSET(r1)
119        /* find address where we jumped from */
120        mflr    r14
121        /* restore LR     */
122        mtlr    r3
123        /* compute vector into R3 */
124        rlwinm  r3, r14, 24, 26, 31
125        /* we're now in almost the same state as if called by
126         * min_prolog_std but we must skip saving r14
127         * since that's done already
128         */
129        b       wrap_no_save_r14_std
130
131wrap_auto_async:
132        stwu    r1, -EXCEPTION_FRAME_END(r1)
133        stw             r14, GPR14_OFFSET(r1)
134        /* find address where we jumped from */
135        mflr    r14
136        /* restore LR     */
137        mtlr    r3
138        /* set upper bits to indicate that non-volatile
139         * registers should not be saved/restored.
140         */
141        li      r3, 0xffff8000
142        /* compute vector into R3 */
143        rlwimi  r3, r14, 24, 26, 31
144        /* we're now in almost the same state as if called by
145         * min_prolog_std but we must skip saving r14
146         * since that's done already
147         */
148        b       wrap_no_save_r14_std
149
150/*
151 * Common code for all flavors of exception and whether
152 * they are synchronous or asynchronous.
153 *
154 * Call with
155 *  r3 : vector
156 *  r4 : srr0
157 *  r5 : srr1
158 *  r14: exception frame
159 *  cr4: OR of lower-priority locks
160 *  cr2: exception type (asyn/isr [<0] or synchronous [>=0])
161 *  lr : is updated by 'bl'
162 * all others: original state
163 *
164 * If this is an asynchronous exception ( cr2 < 0 ):
165 *   - save volatile registers only,
166 *   - disable thread dispatching,
167 *   - switch to interrupt stack (if necessary),
168 *   - call the C-dispatcher,
169 *   - switch back the stack,
170 *   - decrement the dispatch-disable level
171 *   - check if it is safe to dispatch (disable-level must be 0
172 *     AND no lower-priority asynchronous exception must be under
173 *     way (as indicated by the lock variables).
174 *   - If it would be OK to dispatch, call the C-wrapup code.
175 *   - restore volatile registers
176 *
177 * Otherwise, i.e., if we are dealing with a synchronous exception
178 * then:
179 *   - save all registers
180 *   - call the C-dispatcher
181 *   - restore registers
182 */
183
184wrap_common:
185        stw             r4, SRR0_FRAME_OFFSET(r14)
186        stw             r5, SRR1_FRAME_OFFSET(r14)
187
188        /* prepare for calling C code; */
189
190        /* use non-volatile r15 for remembering lr */
191        stw             r15, GPR15_OFFSET(r14)
192
193        /* save vector; negative if only scratch regs. are valid */
194        stw             r3,  EXCEPTION_NUMBER_OFFSET(r14)
195
196        /* save scratch registers */
197
198        /* r2 should be unused or fixed anyways (eabi sdata2) */
199        stw             r0,  GPR0_OFFSET(r14)
200        stw             r2,  GPR2_OFFSET(r14)
201        stw             r6,  GPR6_OFFSET(r14)
202        stw             r7,  GPR7_OFFSET(r14)
203        stw             r8,  GPR8_OFFSET(r14)
204        stw             r9,  GPR9_OFFSET(r14)
205        stw             r10, GPR10_OFFSET(r14)
206        stw             r11, GPR11_OFFSET(r14)
207        stw             r12, GPR12_OFFSET(r14)
208        /* r13 must be fixed anyways (sysv sdata) */
209
210        /* save LR */
211        mflr    r15
212
213        mfctr   r4
214        mfxer   r5
215        stw             r4,  EXC_CTR_OFFSET(r14)
216        stw             r5,  EXC_XER_OFFSET(r14)
217
218        /*
219         * Switch MMU / RI on if necessary;
220         * remember decision in cr3
221         */
222        lwz             r4,  ppc_exc_msr_bits@sdarel(r13)
223        cmpwi   cr3, r4, 0
224        beq             cr3, 1f
225        mfmsr   r5
226        or              r5, r5, r4
227        mtmsr   r5
228        sync
229        isync
2301:
231
232        /* If this is a asynchronous exception we skip ahead */
233        blt             cr2, skip_save_nonvolatile_regs
234
235        /* YES; they want everything ('normal exception') */
236
237        /* save original stack pointer */
238        lwz             r5,  EXC_MIN_GPR1(r14)
239        stw             r5,  GPR1_OFFSET(r14)
240
241        stw             r13, GPR13_OFFSET(r14)
242
243        /* store r16..r31 into the exception frame */
244        stmw    r16, GPR16_OFFSET(r14)
245
246skip_save_nonvolatile_regs:
247        /* store address of exception frame in r4; vector is in r3 */
248        addi  r4, r14, FRAME_LINK_SPACE
249
250        /* load hi-halfword of C wrapper address */
251        lis             r5, ppc_exc_C_wrapper@h
252        /* clear CR[6] to make sure no vararg callee assumes that
253         * there are any valid FP regs
254         */
255        crxor 6,6,6
256        /* merge lo-halfword of C wrapper address */
257        ori             r5, r5, ppc_exc_C_wrapper@l
258        /* Far branch to ppc_C_wrapper */
259        mtlr    r5
260        blrl
261
262        /* do not clobber r3 since we pass the return value
263         * of ppc_exc_C_wrapper on to ppc_exc_wrapup
264         */
265
266        /* skip decrementing the thread-dispatch disable level
267         * and calling ppc_exc_wrapup if this is a synchronous
268         * exception.
269         */
270        bge             cr2, restore_nonvolatile_regs
271
272        /* decrement ISR nest level;
273         * disable all interrupts.
274         * (Disabling IRQs here is not necessary if we
275         * use the stack-switching strategy which tests
276         * if we are alreay on the ISR-stack as opposed
277         * to test the nesting level; see ppc_exc_asm_macros.h)
278         */
279        lwz             r4,  ppc_exc_msr_irq_mask@sdarel(r13)
280        mfmsr   r5
281        andc    r4, r5, r4
282        mtmsr   r4
283        lwz             r4, _ISR_Nest_level@sdarel(r13)
284        addi    r4, r4, -1
285        stw             r4, _ISR_Nest_level@sdarel(r13)
286
287        /*
288         * switch back to original stack (r14 == r1 if we are
289         * still on the IRQ stack).
290         */
291        mr              r1, r14
292
293        /* restore interrupt mask */
294        mtmsr   r5
295
296        /* decrement thread_dispatch level and check
297         * if we have to run the dispatcher.
298         */
299        lwz             r5,  _Thread_Dispatch_disable_level@sdarel(r13)
300        addic.  r5,  r5, -1
301        stw             r5,  _Thread_Dispatch_disable_level@sdarel(r13)
302       
303        /* test _Thread_Dispatch_disable nesting level AND
304         * lower priority locks (in cr4); ONLY if
305         * _Thread_Dispatch_disable_level == 0 AND no lock is set
306         * then call ppc_exc_wrapup which may do a context switch.
307         */
308        crand   EQ(cr0), EQ(cr0), EQ(cr4)
309        bne             2f
310        crxor   6,6,6
311        /* Far branch to ppc_exc_wrapup */
312        lis             r5, ppc_exc_wrapup@h
313        addi    r4, r14, FRAME_LINK_SPACE
314        ori             r5, r5, ppc_exc_wrapup@l
315        mtlr    r5
316        blrl
3172:
318        lwz             r14, GPR14_OFFSET(r1)
319
320        /* we can skip restoring r16..r31 */
321        b               skip_restore_nonvolatile_regs
322
323restore_nonvolatile_regs:
324        /* synchronous exc: restore everything from the exception frame */
325        lwz             r14, GPR14_OFFSET(r1)
326
327        /* restore stack pointer */
328        lwz             r5,  GPR1_OFFSET(r1)
329        stw             r5,  EXC_MIN_GPR1(r1)
330
331        /* restore non-volatile regs */
332        lwz             r13, GPR13_OFFSET(r1)
333        lmw             r16, GPR16_OFFSET(r1)
334
335skip_restore_nonvolatile_regs:
336        lwz             r3,  EXC_XER_OFFSET(r1)
337        lwz             r4,  EXC_CTR_OFFSET(r1)
338        mtxer   r3
339        mtctr   r4
340
341        /* restore lr, r15 */
342        mtlr    r15
343        lwz             r15, GPR15_OFFSET(r1)
344
345        /* restore scratch regs */
346        lwz             r12, GPR12_OFFSET(r1)
347        lwz             r11, GPR11_OFFSET(r1)
348        lwz             r10, GPR10_OFFSET(r1)
349        lwz             r9,  GPR9_OFFSET(r1)
350        lwz             r8,  GPR8_OFFSET(r1)
351        lwz             r7,  GPR7_OFFSET(r1)
352        lwz             r6,  GPR6_OFFSET(r1)
353        /* r4, r5 are eventually restored by caller */
354        lwz             r3,  GPR3_OFFSET(r1)
355        lwz             r2,  GPR2_OFFSET(r1)
356        /* r1, is eventually restored by caller */
357        lwz             r0,  GPR0_OFFSET(r1)
358
359        beq  cr3, 2f
360        /* restore MSR settings */
361        lwz             r5,  ppc_exc_msr_bits@sdarel(r13)
362        mfmsr   r4
363        andc    r4, r4, r5
364        mtmsr   r4
365        sync
366        isync
3672:
368
369        lwz             r4,  EXC_CR_OFFSET(r1)
370        mtcr    r4
371
372        /* Must disable interrupts prior to restoring SSRs.
373         * Here's a scenario discovered by Sebastian Huber:
374         *  1) CE happens between writing to SRR and RFI
375         *  2) CE handler does something which requires a task switch
376         *  3) CE wrapper returns and determines that task switch
377     *     is OK since EE lock is not held, dispatch-disable level
378         *     is zero etc.
379         *  4) switch to other task enables EE
380         *  5) eventually, switch back to task interrupted by 1)
381         *  6) RFI happens but SRR contents have been clobbered.
382         */
383        lwz             r4,  ppc_exc_msr_irq_mask@sdarel(r13)
384        mfmsr   r5
385        andc    r4, r5, r4
386        mtmsr   r4
387
388        /* restore SRR and stack */
389        lwz             r4,  SRR0_FRAME_OFFSET(r1)
390        lwz             r5,  SRR1_FRAME_OFFSET(r1)
391        blr
392       
393        .global __ppc_exc_wrappers_end
394__ppc_exc_wrappers_end = .
Note: See TracBrowser for help on using the repository browser.