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 |
---|
35 | ppc_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 |
---|
46 | ppc_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 |
---|
59 | ppc_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 |
---|
66 | ppc_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 |
---|
80 | ppc_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 */ |
---|
117 | wrap_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 | |
---|
131 | wrap_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 | |
---|
184 | wrap_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 |
---|
230 | 1: |
---|
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 | |
---|
246 | skip_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 |
---|
317 | 2: |
---|
318 | lwz r14, GPR14_OFFSET(r1) |
---|
319 | |
---|
320 | /* we can skip restoring r16..r31 */ |
---|
321 | b skip_restore_nonvolatile_regs |
---|
322 | |
---|
323 | restore_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 | |
---|
335 | skip_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 |
---|
367 | 2: |
---|
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 = . |
---|