trap_subr.S revision 1.28 1 /* $NetBSD: trap_subr.S,v 1.28 2020/03/01 23:23:36 rin Exp $ */
2
3 /*
4 * Copyright 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Eduardo Horvath and Simon Burge for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
23 * written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 /*
39 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
40 * Copyright (C) 1995, 1996 TooLs GmbH.
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by TooLs GmbH.
54 * 4. The name of TooLs GmbH may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
62 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
63 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
64 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
65 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
66 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 /*
70 * NOTICE: This is not a standalone file. to use it, #include it in
71 * your port's locore.S, like so:
72 *
73 * #include <powerpc/ibm4xx/trap_subr.S>
74 */
75
76 /*
77 * XXX Interrupt and spill stacks need to be per-CPU.
78 */
79
80 #define GET_PCB(rX) \
81 GET_CPUINFO(rX); \
82 lwz rX,CI_CURPCB(rX)
83
84 #define STANDARD_PROLOG(savearea) \
85 mtsprg1 %r1; /* save SP */ \
86 GET_CPUINFO(%r1); \
87 stmw %r28,(savearea+CPUSAVE_R28)(%r1); /* free r28-r31 */ \
88 mflr %r28; /* save LR */ \
89 mfcr %r29; /* save CR */ \
90 mfsrr0 %r30; \
91 mfsrr1 %r31; /* Test whether we already had PR set */ \
92 stmw %r30,(savearea+CPUSAVE_SRR0)(%r1); /* save srr0/srr1 */ \
93 mfsprg1 %r1; /* restore SP */ \
94 mtcr %r31; \
95 bf MSR_PR,1f; /* branch if MSR[PR] is clear */ \
96 GET_PCB(%r1); \
97 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \
98 1:
99
100 #define ACCESS_PROLOG(savearea) \
101 mtsprg1 %r1; /* save SP temporalily */ \
102 GET_CPUINFO(%r1); \
103 stmw %r28,(savearea+CPUSAVE_R28)(%r1); /* free r28-r31 */ \
104 mflr %r28; /* save LR */ \
105 mfcr %r29; /* save CR */ \
106 mfdear %r30; \
107 mfesr %r31; \
108 stmw %r30,(savearea+CPUSAVE_DEAR)(%r1); /* save esr/dear */ \
109 mfsrr0 %r30; \
110 mfsrr1 %r31; /* Test whether we already had PR set */ \
111 stmw %r30,(savearea+CPUSAVE_SRR0)(%r1); /* save srr0/srr1 */ \
112 mfsprg1 %r1; /* restore SP */ \
113 mtcr %r31; \
114 bf MSR_PR,1f; /* branch if MSR[PR] is clear */ \
115 GET_PCB(%r1); \
116 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \
117 1:
118
119 #define CRITICAL_PROLOG(savearea) \
120 mtsprg1 %r1; /* save SP */ \
121 GET_CPUINFO(%r1); \
122 stmw %r28,(savearea+CPUSAVE_R28)(%r1); /* free r28-r31 */ \
123 mflr %r28; /* save LR */ \
124 mfcr %r29; /* save CR */ \
125 mfsrr2 %r30; /* Fake a standard trap */ \
126 mfsrr3 %r31; /* Test whether we already had PR set */ \
127 stmw %r30,(savearea+CPUSAVE_SRR0)(%r1); /* save srr0/srr1 */ \
128 mfsprg1 %r1; /* restore SP */ \
129 mtcr %r31; \
130 bf MSR_PR,1f; /* branch if MSR[PR] is clear */ \
131 GET_PCB(%r1); \
132 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \
133 1:
134
135
136 /* Standard handler saves r1,r28-31,LR,CR, sets up the stack and calls s_trap */
137 #define STANDARD_EXC_HANDLER(name)\
138 .globl _C_LABEL(name ## trap),_C_LABEL(name ## size) ; \
139 _C_LABEL(name ## trap): \
140 STANDARD_PROLOG(CI_TEMPSAVE); \
141 bla s_trap; \
142 _C_LABEL(name ## size) = .-_C_LABEL(name ## trap)
143
144 /* Access exceptions also need DEAR and ESR saved */
145 #define ACCESS_EXC_HANDLER(name)\
146 .globl _C_LABEL(name ## trap),_C_LABEL(name ## size) ; \
147 _C_LABEL(name ## trap): \
148 ACCESS_PROLOG(CI_TEMPSAVE); \
149 bla s_trap; \
150 _C_LABEL(name ## size) = .-_C_LABEL(name ## trap)
151
152 /* Maybe this should call ddb.... */
153 #define CRITICAL_EXC_HANDLER(name)\
154 .globl _C_LABEL(name ## trap),_C_LABEL(name ## size) ; \
155 _C_LABEL(name ## trap): \
156 CRITICAL_PROLOG(CI_TEMPSAVE); \
157 bla s_trap; \
158 _C_LABEL(name ## size) = .-_C_LABEL(name ## trap)
159
160 #define INTR_PROLOG(tempsave) \
161 mtsprg1 %r1; /* save SP */ \
162 GET_CPUINFO(%r1); \
163 stmw %r28,(tempsave+CPUSAVE_R28)(%r1); /* free r28-r31 */ \
164 mflr %r28; /* save LR */ \
165 mfcr %r29; /* save CR */ \
166 mfxer %r30; /* save XER */ \
167 mfsrr1 %r31; \
168 mtcr %r31; \
169 mfsprg1 %r1; /* restore SP */ \
170 bf MSR_PR,1f; /* branch if PSL_PR is false */ \
171 GET_PCB(%r1); \
172 addi %r1,%r1,USPACE-CALLFRAMELEN; /* stack is top of user struct */ \
173 1:
174
175 .text
176 STANDARD_EXC_HANDLER(default)
177 ACCESS_EXC_HANDLER(access)
178 CRITICAL_EXC_HANDLER(critical)
179
180 /*
181 * This one for the external interrupt handler.
182 */
183 .globl _C_LABEL(extint),_C_LABEL(extsize)
184 _C_LABEL(extint):
185 INTR_PROLOG(CI_TEMPSAVE)
186 ba extintr
187 _C_LABEL(extsize) = .-_C_LABEL(extint)
188
189
190 #if defined(DDB) || defined(KGDB)
191 /*
192 * In case of DDB we want a separate trap catcher for it
193 */
194 .globl _C_LABEL(ddblow),_C_LABEL(ddbsize)
195 _C_LABEL(ddblow):
196 ACCESS_PROLOG(CI_DDBSAVE)
197 bla ddbtrap
198 _C_LABEL(ddbsize) = .-_C_LABEL(ddblow)
199 #endif /* DDB || KGDB */
200
201 #ifdef DEBUG
202 #define TRAP_IF_ZERO(r) tweqi r,0
203 #else
204 #define TRAP_IF_ZERO(r)
205 #endif
206
207 #define ENABLE_TRANSLATION(pidreg,tmpreg) \
208 mfpid pidreg; \
209 li tmpreg,KERNEL_PID; \
210 mtpid tmpreg; \
211 mfmsr tmpreg; \
212 ori tmpreg,tmpreg,(PSL_DR|PSL_IR)@l; \
213 mtmsr tmpreg; \
214 isync
215
216 /*
217 * FRAME_SETUP assumes:
218 * SPRG1 SP (r1)
219 * savearea r28-r31,DEAR,ESR,SRR0,SRR1
220 * (DEAR & ESR only for access traps)
221 * %r28 LR
222 * %r29 CR
223 * %r1 kernel stack
224 * LR trap type
225 */
226 #define FRAME_SETUP(savearea) \
227 /* Have to enable translation to allow access of kernel stack: */ \
228 ENABLE_TRANSLATION(%r30,%r31); \
229 mfsprg1 %r31; \
230 stwu %r31,-FRAMELEN(%r1); \
231 stw %r30,FRAME_PID(%r1); \
232 stw %r0,FRAME_R0(%r1); \
233 stw %r31,FRAME_R1(%r1); \
234 stw %r2,FRAME_R2(%r1); \
235 GET_CPUINFO(%r2); \
236 stw %r28,FRAME_LR(%r1); \
237 stw %r29,FRAME_CR(%r1); \
238 lmw %r28,(savearea+CPUSAVE_R28)(%r2); \
239 stmw %r3,FRAME_R3(%r1); \
240 lmw %r28,(savearea+CPUSAVE_DEAR)(%r2); \
241 lwz %r13,CI_CURLWP(%r2); \
242 mfxer %r3; \
243 mfctr %r4; \
244 mflr %r5; \
245 andi. %r5,%r5,0xff00; \
246 stw %r3,FRAME_XER(%r1); \
247 stw %r4,FRAME_CTR(%r1); \
248 stw %r5,FRAME_EXC(%r1); \
249 stw %r28,FRAME_DEAR(%r1); \
250 stw %r29,FRAME_ESR(%r1); \
251 stw %r30,FRAME_SRR0(%r1); \
252 stw %r31,FRAME_SRR1(%r1)
253
254 #define FRAME_SAVE_CALLEE \
255 stmw %r14,FRAME_R14(%r1)
256
257 #define FRAME_RESTORE \
258 lwz %r6,FRAME_LR(%r1); \
259 lwz %r7,FRAME_CR(%r1); \
260 lwz %r8,FRAME_XER(%r1); \
261 lwz %r9,FRAME_CTR(%r1); \
262 lwz %r10,FRAME_SRR0(%r1); \
263 lwz %r11,FRAME_SRR1(%r1); \
264 mtlr %r6; \
265 mtcr %r7; \
266 mtxer %r8; \
267 mtctr %r9; \
268 mtsrr0 %r10; \
269 mtsrr1 %r11; \
270 lwz %r13,FRAME_R13(%r1); \
271 lwz %r12,FRAME_R12(%r1); \
272 lwz %r11,FRAME_R11(%r1); \
273 lwz %r10,FRAME_R10(%r1); \
274 lwz %r9,FRAME_R9(%r1); \
275 lwz %r8,FRAME_R8(%r1); \
276 lwz %r7,FRAME_R7(%r1); \
277 lwz %r6,FRAME_R6(%r1); \
278 lwz %r5,FRAME_R5(%r1); \
279 lwz %r4,FRAME_R4(%r1); \
280 lwz %r3,FRAME_R3(%r1); \
281 lwz %r2,FRAME_R2(%r1); \
282 lwz %r0,FRAME_R1(%r1); \
283 mtsprg1 %r0; \
284 lwz %r0,FRAME_R0(%r1)
285
286 /*
287 * Now the common trap catching code.
288 */
289 s_trap:
290 FRAME_SETUP(CI_TEMPSAVE)
291 /* R31 = SRR1 */
292 /* Now we can recover interrupts again: */
293 trapagain:
294 wrtee %r31 /* reenable interrupts */
295 /* Call C trap code: */
296 addi %r3,%r1,FRAME_TF
297 bl _C_LABEL(trap)
298 .globl _C_LABEL(trapexit)
299 _C_LABEL(trapexit):
300 /* Disable interrupts: */
301 wrteei 0
302
303 /* Test AST pending: */
304 mtcr %r31
305 bf MSR_PR,trapleave_to_kernel /* branch if MSR[PR] is false */
306
307 lwz %r4,L_MD_ASTPENDING(%r13)
308 andi. %r4,%r4,1
309 beq trapleave_to_user
310
311 li %r6,EXC_AST
312 stw %r6,FRAME_EXC(%r1)
313 b trapagain
314
315 trapleave_to_kernel:
316 lmw %r14, FRAME_R14(%r1) /* restore callee registers */
317
318 intrleave_to_kernel:
319 FRAME_RESTORE /* old SP is now in sprg1 */
320
321 mtsprg2 %r30
322 mtsprg3 %r31
323 mfmsr %r30
324 li %r31,(PSL_DR|PSL_IR)@l
325 andc %r30,%r30,%r31
326 lwz %r31,FRAME_PID(%r1)
327 TRAP_IF_ZERO(%r31)
328 /*
329 * Now that we are done with the trapframe, we can load the original SP
330 */
331 mfsprg1 %r1
332 mtmsr %r30 /* disable translation */
333 isync
334 mtpid %r31
335 mfsprg3 %r31
336 mfsprg2 %r30
337 IBM405_ERRATA77_SYNC
338 rfi
339 ba . /* Protect against prefetch */
340
341 trapleave_to_user:
342 lmw %r14, FRAME_R14(%r1) /* restore callee registers */
343
344 intrleave_to_user:
345 /* Now restore regs: */
346 lwz %r3,FRAME_PID(%r1)
347 lwz %r4,FRAME_SRR1(%r1)
348 bl _C_LABEL(ctx_setup)
349 TRAP_IF_ZERO(%r3)
350 stw %r3,FRAME_PID(%r1)
351
352 FRAME_RESTORE /* old SP is now in sprg1 */
353
354 /*
355 * We are returning to userspace so we need to switch PIDs.
356 * Since the kernel executes out of what would be userspace,
357 * we need to turn off translation before we set the PID.
358 *
359 * Alterantively, we could map a kernel page at 0xfffff000
360 * that had the mtpid code in it and branch to it and avoid
361 * all this. (ba foo; foo: mtpid %r31; mfsprg3 %r31; rfi;)
362 */
363 mtsprg2 %r30
364 mtsprg3 %r31
365 mfmsr %r30
366 li %r31,(PSL_DR|PSL_IR)@l
367 andc %r30,%r30,%r31
368 lwz %r31,FRAME_PID(%r1)
369 TRAP_IF_ZERO(%r31)
370 /*
371 * Now that we are done with the trapframe, we can load the original SP
372 */
373 mfsprg1 %r1
374 mtmsr %r30 /* disable translation */
375 isync
376 mtpid %r31
377 mfsprg3 %r31
378 mfsprg2 %r30
379 IBM405_ERRATA77_SYNC
380 rfi
381 ba . /* Protect against prefetch */
382
383
384 .globl _C_LABEL(sctrap),_C_LABEL(scsize),_C_LABEL(sctrapexit)
385 _C_LABEL(sctrap):
386 STANDARD_PROLOG(CI_TEMPSAVE)
387 bla s_sctrap
388 _C_LABEL(scsize) = .-_C_LABEL(sctrap)
389
390 s_sctrap:
391 FRAME_SETUP(CI_TEMPSAVE)
392 /* Now we can recover interrupts again: */
393 wrteei 1 /* Enable interrupts */
394 /* Call the appropriate syscall handler: */
395 addi %r3,%r1,FRAME_TF
396 lwz %r4,L_PROC(%r13)
397 lwz %r4,P_MD_SYSCALL(%r4)
398 mtctr %r4
399 bctrl
400 _C_LABEL(sctrapexit):
401 b trapexit
402
403 /*
404 * External interrupt second level handler
405 */
406
407 #define INTR_SAVE(tempsave) \
408 /* Save non-volatile registers: */ \
409 stwu %r1,-FRAMELEN(%r1); /* temporarily */ \
410 stw %r0,FRAME_R0(%r1); \
411 mfsprg1 %r0; /* get original SP */ \
412 stw %r0,FRAME_R1(%r1); /* and store it */ \
413 stw %r2,FRAME_R2(%r1); \
414 stw %r3,FRAME_R3(%r1); \
415 stw %r4,FRAME_R4(%r1); \
416 stw %r5,FRAME_R5(%r1); \
417 stw %r6,FRAME_R6(%r1); \
418 stw %r7,FRAME_R7(%r1); \
419 stw %r8,FRAME_R8(%r1); \
420 stw %r9,FRAME_R9(%r1); \
421 stw %r10,FRAME_R10(%r1); \
422 stw %r11,FRAME_R11(%r1); \
423 stw %r12,FRAME_R12(%r1); \
424 stw %r13,FRAME_R13(%r1); \
425 mfctr %r31; \
426 stmw %r28,FRAME_LR(%r1); /* save LR, CR, XER, CTR */ \
427 GET_CPUINFO(%r5); \
428 lmw %r28,(tempsave+CPUSAVE_R28)(%r5); /* restore r28-r31 */ \
429 lwz %r13,CI_CURLWP(%r5); \
430 lwz %r5,CI_IDEPTH(%r5); \
431 mfsrr0 %r4; \
432 mfsrr1 %r3; \
433 stw %r5,FRAME_IDEPTH(%r1); \
434 stw %r4,FRAME_SRR0(%r1); \
435 stw %r3,FRAME_SRR1(%r1); \
436 /* interrupts are recoverable here, and enable translation */ \
437 ENABLE_TRANSLATION(%r0,%r5); \
438 stw %r0,FRAME_PID(%r1);
439
440 .globl _C_LABEL(extint_call)
441 extintr:
442 INTR_SAVE(CI_TEMPSAVE)
443 _C_LABEL(extint_call):
444 bl _C_LABEL(extint_call) /* to be filled in later */
445
446 intr_exit:
447 /* Disable interrupts */
448 wrteei 0
449 isync
450
451 lwz %r4,FRAME_SRR1(%r1)
452 /* Returning to user mode? */
453 mtcr %r4 /* saved SRR1 */
454 bf MSR_PR,intrleave_to_kernel /* branch if MSR[PR] is false */
455
456 lwz %r4,L_MD_ASTPENDING(%r13)/* Test AST pending */
457 andi. %r4,%r4,1
458 beq intrleave_to_user
459
460 FRAME_SAVE_CALLEE /* save rest of callee registers */
461 li %r6,EXC_AST
462 stw %r6,FRAME_EXC(%r1)
463 lwz %r31,FRAME_SRR1(%r1) /* move SRR1 to R31 */
464 b trapagain
465
466 /*
467 * PIT interrupt handler.
468 */
469 .align 5
470 _C_LABEL(pitint):
471 INTR_PROLOG(CI_TEMPSAVE)
472 INTR_SAVE(CI_TEMPSAVE)
473 addi %r3,%r1,FRAME_CF /* clock frame */
474 bl _C_LABEL(decr_intr)
475 b intr_exit
476
477 /*
478 * FIT interrupt handler.
479 */
480 .align 5
481 _C_LABEL(fitint):
482 INTR_PROLOG(CI_TEMPSAVE)
483 INTR_SAVE(CI_TEMPSAVE)
484 addi %r3,%r1,FRAME_CF /* clock frame */
485 bl _C_LABEL(stat_intr)
486 b intr_exit
487
488 #if defined(DDB) || defined(KGDB)
489 /*
490 * Deliberate entry to ddbtrap
491 */
492 .globl _C_LABEL(ddb_trap)
493 _C_LABEL(ddb_trap):
494 mtsprg1 %r1
495 GET_CPUINFO(%r4)
496 mfmsr %r3
497 stw %r3,(CI_DDBSAVE+CPUSAVE_SRR1)(%r4)
498 wrteei 0 /* disable interrupts */
499 isync
500 stmw %r28,CI_DDBSAVE(%r4)
501 mflr %r28
502 stw %r28,(CI_DDBSAVE+CPUSAVE_SRR0)(%r4)
503 li %r29,EXC_BPT
504 mtlr %r29
505 mfcr %r29
506
507 /*
508 * Now the ddb/kgdb trap catching code.
509 */
510 ddbtrap:
511 FRAME_SETUP(CI_DDBSAVE)
512 /* Call C trap code: */
513 addi %r3,%r1,FRAME_TF
514 bl _C_LABEL(ddb_trap_glue)
515 or. %r3,%r3,%r3
516 beq trapagain
517 b trapexit
518 #endif /* DDB || KGDB */
519