diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/kernel/head_booke.h |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/ppc/kernel/head_booke.h')
-rw-r--r-- | arch/ppc/kernel/head_booke.h | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h new file mode 100644 index 000000000000..884dac916bce --- /dev/null +++ b/arch/ppc/kernel/head_booke.h | |||
@@ -0,0 +1,340 @@ | |||
1 | #ifndef __HEAD_BOOKE_H__ | ||
2 | #define __HEAD_BOOKE_H__ | ||
3 | |||
4 | /* | ||
5 | * Macros used for common Book-e exception handling | ||
6 | */ | ||
7 | |||
8 | #define SET_IVOR(vector_number, vector_label) \ | ||
9 | li r26,vector_label@l; \ | ||
10 | mtspr SPRN_IVOR##vector_number,r26; \ | ||
11 | sync | ||
12 | |||
13 | #define NORMAL_EXCEPTION_PROLOG \ | ||
14 | mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ | ||
15 | mtspr SPRN_SPRG1,r11; \ | ||
16 | mtspr SPRN_SPRG4W,r1; \ | ||
17 | mfcr r10; /* save CR in r10 for now */\ | ||
18 | mfspr r11,SPRN_SRR1; /* check whether user or kernel */\ | ||
19 | andi. r11,r11,MSR_PR; \ | ||
20 | beq 1f; \ | ||
21 | mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\ | ||
22 | lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ | ||
23 | addi r1,r1,THREAD_SIZE; \ | ||
24 | 1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ | ||
25 | mr r11,r1; \ | ||
26 | stw r10,_CCR(r11); /* save various registers */\ | ||
27 | stw r12,GPR12(r11); \ | ||
28 | stw r9,GPR9(r11); \ | ||
29 | mfspr r10,SPRN_SPRG0; \ | ||
30 | stw r10,GPR10(r11); \ | ||
31 | mfspr r12,SPRN_SPRG1; \ | ||
32 | stw r12,GPR11(r11); \ | ||
33 | mflr r10; \ | ||
34 | stw r10,_LINK(r11); \ | ||
35 | mfspr r10,SPRN_SPRG4R; \ | ||
36 | mfspr r12,SPRN_SRR0; \ | ||
37 | stw r10,GPR1(r11); \ | ||
38 | mfspr r9,SPRN_SRR1; \ | ||
39 | stw r10,0(r11); \ | ||
40 | rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ | ||
41 | stw r0,GPR0(r11); \ | ||
42 | SAVE_4GPRS(3, r11); \ | ||
43 | SAVE_2GPRS(7, r11) | ||
44 | |||
45 | /* To handle the additional exception priority levels on 40x and Book-E | ||
46 | * processors we allocate a 4k stack per additional priority level. The various | ||
47 | * head_xxx.S files allocate space (exception_stack_top) for each priority's | ||
48 | * stack times the number of CPUs | ||
49 | * | ||
50 | * On 40x critical is the only additional level | ||
51 | * On 44x/e500 we have critical and machine check | ||
52 | * | ||
53 | * Additionally we reserve a SPRG for each priority level so we can free up a | ||
54 | * GPR to use as the base for indirect access to the exception stacks. This | ||
55 | * is necessary since the MMU is always on, for Book-E parts, and the stacks | ||
56 | * are offset from KERNELBASE. | ||
57 | * | ||
58 | */ | ||
59 | #define BOOKE_EXCEPTION_STACK_SIZE (8192) | ||
60 | |||
61 | /* CRIT_SPRG only used in critical exception handling */ | ||
62 | #define CRIT_SPRG SPRN_SPRG2 | ||
63 | /* MCHECK_SPRG only used in critical exception handling */ | ||
64 | #define MCHECK_SPRG SPRN_SPRG6W | ||
65 | |||
66 | #define MCHECK_STACK_TOP (exception_stack_top - 4096) | ||
67 | #define CRIT_STACK_TOP (exception_stack_top) | ||
68 | |||
69 | #ifdef CONFIG_SMP | ||
70 | #define BOOKE_LOAD_CRIT_STACK \ | ||
71 | mfspr r8,SPRN_PIR; \ | ||
72 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ | ||
73 | neg r8,r8; \ | ||
74 | addis r8,r8,CRIT_STACK_TOP@ha; \ | ||
75 | addi r8,r8,CRIT_STACK_TOP@l | ||
76 | #define BOOKE_LOAD_MCHECK_STACK \ | ||
77 | mfspr r8,SPRN_PIR; \ | ||
78 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ | ||
79 | neg r8,r8; \ | ||
80 | addis r8,r8,MCHECK_STACK_TOP@ha; \ | ||
81 | addi r8,r8,MCHECK_STACK_TOP@l | ||
82 | #else | ||
83 | #define BOOKE_LOAD_CRIT_STACK \ | ||
84 | lis r8,CRIT_STACK_TOP@h; \ | ||
85 | ori r8,r8,CRIT_STACK_TOP@l | ||
86 | #define BOOKE_LOAD_MCHECK_STACK \ | ||
87 | lis r8,MCHECK_STACK_TOP@h; \ | ||
88 | ori r8,r8,MCHECK_STACK_TOP@l | ||
89 | #endif | ||
90 | |||
91 | /* | ||
92 | * Exception prolog for critical exceptions. This is a little different | ||
93 | * from the normal exception prolog above since a critical exception | ||
94 | * can potentially occur at any point during normal exception processing. | ||
95 | * Thus we cannot use the same SPRG registers as the normal prolog above. | ||
96 | * Instead we use a portion of the critical exception stack at low physical | ||
97 | * addresses. | ||
98 | */ | ||
99 | |||
100 | #define CRITICAL_EXCEPTION_PROLOG \ | ||
101 | mtspr CRIT_SPRG,r8; \ | ||
102 | BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \ | ||
103 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ | ||
104 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ | ||
105 | mfcr r10; /* save CR in r10 for now */\ | ||
106 | mfspr r11,SPRN_CSRR1; /* check whether user or kernel */\ | ||
107 | andi. r11,r11,MSR_PR; \ | ||
108 | mr r11,r8; \ | ||
109 | mfspr r8,CRIT_SPRG; \ | ||
110 | beq 1f; \ | ||
111 | /* COMING FROM USER MODE */ \ | ||
112 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | ||
113 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | ||
114 | addi r11,r11,THREAD_SIZE; \ | ||
115 | 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ | ||
116 | stw r10,_CCR(r11); /* save various registers */\ | ||
117 | stw r12,GPR12(r11); \ | ||
118 | stw r9,GPR9(r11); \ | ||
119 | mflr r10; \ | ||
120 | stw r10,_LINK(r11); \ | ||
121 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ | ||
122 | stw r12,_DEAR(r11); /* since they may have had stuff */\ | ||
123 | mfspr r9,SPRN_ESR; /* in them at the point where the */\ | ||
124 | stw r9,_ESR(r11); /* exception was taken */\ | ||
125 | mfspr r12,SPRN_CSRR0; \ | ||
126 | stw r1,GPR1(r11); \ | ||
127 | mfspr r9,SPRN_CSRR1; \ | ||
128 | stw r1,0(r11); \ | ||
129 | mr r1,r11; \ | ||
130 | rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ | ||
131 | stw r0,GPR0(r11); \ | ||
132 | SAVE_4GPRS(3, r11); \ | ||
133 | SAVE_2GPRS(7, r11) | ||
134 | |||
135 | /* | ||
136 | * Exception prolog for machine check exceptions. This is similar to | ||
137 | * the critical exception prolog, except that machine check exceptions | ||
138 | * have their stack. | ||
139 | */ | ||
140 | #define MCHECK_EXCEPTION_PROLOG \ | ||
141 | mtspr MCHECK_SPRG,r8; \ | ||
142 | BOOKE_LOAD_MCHECK_STACK; /* r8 points to the mcheck stack */\ | ||
143 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ | ||
144 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ | ||
145 | mfcr r10; /* save CR in r10 for now */\ | ||
146 | mfspr r11,SPRN_MCSRR1; /* check whether user or kernel */\ | ||
147 | andi. r11,r11,MSR_PR; \ | ||
148 | mr r11,r8; \ | ||
149 | mfspr r8,MCHECK_SPRG; \ | ||
150 | beq 1f; \ | ||
151 | /* COMING FROM USER MODE */ \ | ||
152 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | ||
153 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | ||
154 | addi r11,r11,THREAD_SIZE; \ | ||
155 | 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ | ||
156 | stw r10,_CCR(r11); /* save various registers */\ | ||
157 | stw r12,GPR12(r11); \ | ||
158 | stw r9,GPR9(r11); \ | ||
159 | mflr r10; \ | ||
160 | stw r10,_LINK(r11); \ | ||
161 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ | ||
162 | stw r12,_DEAR(r11); /* since they may have had stuff */\ | ||
163 | mfspr r9,SPRN_ESR; /* in them at the point where the */\ | ||
164 | stw r9,_ESR(r11); /* exception was taken */\ | ||
165 | mfspr r12,SPRN_MCSRR0; \ | ||
166 | stw r1,GPR1(r11); \ | ||
167 | mfspr r9,SPRN_MCSRR1; \ | ||
168 | stw r1,0(r11); \ | ||
169 | mr r1,r11; \ | ||
170 | rlwinm r9,r9,0,14,12; /* clear MSR_WE (necessary?) */\ | ||
171 | stw r0,GPR0(r11); \ | ||
172 | SAVE_4GPRS(3, r11); \ | ||
173 | SAVE_2GPRS(7, r11) | ||
174 | |||
175 | /* | ||
176 | * Exception vectors. | ||
177 | */ | ||
178 | #define START_EXCEPTION(label) \ | ||
179 | .align 5; \ | ||
180 | label: | ||
181 | |||
182 | #define FINISH_EXCEPTION(func) \ | ||
183 | bl transfer_to_handler_full; \ | ||
184 | .long func; \ | ||
185 | .long ret_from_except_full | ||
186 | |||
187 | #define EXCEPTION(n, label, hdlr, xfer) \ | ||
188 | START_EXCEPTION(label); \ | ||
189 | NORMAL_EXCEPTION_PROLOG; \ | ||
190 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
191 | xfer(n, hdlr) | ||
192 | |||
193 | #define CRITICAL_EXCEPTION(n, label, hdlr) \ | ||
194 | START_EXCEPTION(label); \ | ||
195 | CRITICAL_EXCEPTION_PROLOG; \ | ||
196 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
197 | EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ | ||
198 | NOCOPY, crit_transfer_to_handler, \ | ||
199 | ret_from_crit_exc) | ||
200 | |||
201 | #define MCHECK_EXCEPTION(n, label, hdlr) \ | ||
202 | START_EXCEPTION(label); \ | ||
203 | MCHECK_EXCEPTION_PROLOG; \ | ||
204 | mfspr r5,SPRN_ESR; \ | ||
205 | stw r5,_ESR(r11); \ | ||
206 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
207 | EXC_XFER_TEMPLATE(hdlr, n+2, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), \ | ||
208 | NOCOPY, mcheck_transfer_to_handler, \ | ||
209 | ret_from_mcheck_exc) | ||
210 | |||
211 | #define EXC_XFER_TEMPLATE(hdlr, trap, msr, copyee, tfer, ret) \ | ||
212 | li r10,trap; \ | ||
213 | stw r10,TRAP(r11); \ | ||
214 | lis r10,msr@h; \ | ||
215 | ori r10,r10,msr@l; \ | ||
216 | copyee(r10, r9); \ | ||
217 | bl tfer; \ | ||
218 | .long hdlr; \ | ||
219 | .long ret | ||
220 | |||
221 | #define COPY_EE(d, s) rlwimi d,s,0,16,16 | ||
222 | #define NOCOPY(d, s) | ||
223 | |||
224 | #define EXC_XFER_STD(n, hdlr) \ | ||
225 | EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, NOCOPY, transfer_to_handler_full, \ | ||
226 | ret_from_except_full) | ||
227 | |||
228 | #define EXC_XFER_LITE(n, hdlr) \ | ||
229 | EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, NOCOPY, transfer_to_handler, \ | ||
230 | ret_from_except) | ||
231 | |||
232 | #define EXC_XFER_EE(n, hdlr) \ | ||
233 | EXC_XFER_TEMPLATE(hdlr, n, MSR_KERNEL, COPY_EE, transfer_to_handler_full, \ | ||
234 | ret_from_except_full) | ||
235 | |||
236 | #define EXC_XFER_EE_LITE(n, hdlr) \ | ||
237 | EXC_XFER_TEMPLATE(hdlr, n+1, MSR_KERNEL, COPY_EE, transfer_to_handler, \ | ||
238 | ret_from_except) | ||
239 | |||
240 | |||
241 | /* Check for a single step debug exception while in an exception | ||
242 | * handler before state has been saved. This is to catch the case | ||
243 | * where an instruction that we are trying to single step causes | ||
244 | * an exception (eg ITLB/DTLB miss) and thus the first instruction of | ||
245 | * the exception handler generates a single step debug exception. | ||
246 | * | ||
247 | * If we get a debug trap on the first instruction of an exception handler, | ||
248 | * we reset the MSR_DE in the _exception handler's_ MSR (the debug trap is | ||
249 | * a critical exception, so we are using SPRN_CSRR1 to manipulate the MSR). | ||
250 | * The exception handler was handling a non-critical interrupt, so it will | ||
251 | * save (and later restore) the MSR via SPRN_CSRR1, which will still have | ||
252 | * the MSR_DE bit set. | ||
253 | */ | ||
254 | #define DEBUG_EXCEPTION \ | ||
255 | START_EXCEPTION(Debug); \ | ||
256 | CRITICAL_EXCEPTION_PROLOG; \ | ||
257 | \ | ||
258 | /* \ | ||
259 | * If there is a single step or branch-taken exception in an \ | ||
260 | * exception entry sequence, it was probably meant to apply to \ | ||
261 | * the code where the exception occurred (since exception entry \ | ||
262 | * doesn't turn off DE automatically). We simulate the effect \ | ||
263 | * of turning off DE on entry to an exception handler by turning \ | ||
264 | * off DE in the CSRR1 value and clearing the debug status. \ | ||
265 | */ \ | ||
266 | mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ | ||
267 | andis. r10,r10,DBSR_IC@h; \ | ||
268 | beq+ 2f; \ | ||
269 | \ | ||
270 | lis r10,KERNELBASE@h; /* check if exception in vectors */ \ | ||
271 | ori r10,r10,KERNELBASE@l; \ | ||
272 | cmplw r12,r10; \ | ||
273 | blt+ 2f; /* addr below exception vectors */ \ | ||
274 | \ | ||
275 | lis r10,Debug@h; \ | ||
276 | ori r10,r10,Debug@l; \ | ||
277 | cmplw r12,r10; \ | ||
278 | bgt+ 2f; /* addr above exception vectors */ \ | ||
279 | \ | ||
280 | /* here it looks like we got an inappropriate debug exception. */ \ | ||
281 | 1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CSRR1 value */ \ | ||
282 | lis r10,DBSR_IC@h; /* clear the IC event */ \ | ||
283 | mtspr SPRN_DBSR,r10; \ | ||
284 | /* restore state and get out */ \ | ||
285 | lwz r10,_CCR(r11); \ | ||
286 | lwz r0,GPR0(r11); \ | ||
287 | lwz r1,GPR1(r11); \ | ||
288 | mtcrf 0x80,r10; \ | ||
289 | mtspr SPRN_CSRR0,r12; \ | ||
290 | mtspr SPRN_CSRR1,r9; \ | ||
291 | lwz r9,GPR9(r11); \ | ||
292 | lwz r12,GPR12(r11); \ | ||
293 | mtspr CRIT_SPRG,r8; \ | ||
294 | BOOKE_LOAD_CRIT_STACK; /* r8 points to the crit stack */ \ | ||
295 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ | ||
296 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ | ||
297 | mfspr r8,CRIT_SPRG; \ | ||
298 | \ | ||
299 | rfci; \ | ||
300 | b .; \ | ||
301 | \ | ||
302 | /* continue normal handling for a critical exception... */ \ | ||
303 | 2: mfspr r4,SPRN_DBSR; \ | ||
304 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
305 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) | ||
306 | |||
307 | #define INSTRUCTION_STORAGE_EXCEPTION \ | ||
308 | START_EXCEPTION(InstructionStorage) \ | ||
309 | NORMAL_EXCEPTION_PROLOG; \ | ||
310 | mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ | ||
311 | stw r5,_ESR(r11); \ | ||
312 | mr r4,r12; /* Pass SRR0 as arg2 */ \ | ||
313 | li r5,0; /* Pass zero as arg3 */ \ | ||
314 | EXC_XFER_EE_LITE(0x0400, handle_page_fault) | ||
315 | |||
316 | #define ALIGNMENT_EXCEPTION \ | ||
317 | START_EXCEPTION(Alignment) \ | ||
318 | NORMAL_EXCEPTION_PROLOG; \ | ||
319 | mfspr r4,SPRN_DEAR; /* Grab the DEAR and save it */ \ | ||
320 | stw r4,_DEAR(r11); \ | ||
321 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
322 | EXC_XFER_EE(0x0600, AlignmentException) | ||
323 | |||
324 | #define PROGRAM_EXCEPTION \ | ||
325 | START_EXCEPTION(Program) \ | ||
326 | NORMAL_EXCEPTION_PROLOG; \ | ||
327 | mfspr r4,SPRN_ESR; /* Grab the ESR and save it */ \ | ||
328 | stw r4,_ESR(r11); \ | ||
329 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
330 | EXC_XFER_STD(0x0700, ProgramCheckException) | ||
331 | |||
332 | #define DECREMENTER_EXCEPTION \ | ||
333 | START_EXCEPTION(Decrementer) \ | ||
334 | NORMAL_EXCEPTION_PROLOG; \ | ||
335 | lis r0,TSR_DIS@h; /* Setup the DEC interrupt mask */ \ | ||
336 | mtspr SPRN_TSR,r0; /* Clear the DEC interrupt */ \ | ||
337 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
338 | EXC_XFER_LITE(0x0900, timer_interrupt) | ||
339 | |||
340 | #endif /* __HEAD_BOOKE_H__ */ | ||