1/*        $NetBSD: trap_subr.S,v 1.87 2025/04/29 14:33:26 tsutsui Exp $         */
2
3/*
4 * Copyright (C) 1995, 1996 Wolfgang Solfrank.
5 * Copyright (C) 1995, 1996 TooLs GmbH.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *        This product includes software developed by TooLs GmbH.
19 * 4. The name of TooLs GmbH may not be used to endorse or promote products
20 *    derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * NOTICE: This is not a standalone file.  to use it, #include it in
36 * your port's locore.S, like so:
37 *
38 *        #include <powerpc/powerpc/trap_subr.S>
39 */
40
41#ifdef _KERNEL_OPT
42#include "opt_altivec.h"
43#include "opt_ddb.h"
44#include "opt_kgdb.h"
45#include "opt_ppcarch.h"
46#endif
47
48/* LINTSTUB: include <sys/param.h> */
49/* LINTSTUB: include <powerpc/oea/bat.h> */
50
51#ifdef ALTIVEC
52#define   SAVE_VRSAVE(tf,b)                                                     \
53          mfspr     b,SPR_VRSAVE;                                                         \
54          stint     b,FRAME_VRSAVE(tf);
55
56#define RESTORE_VRSAVE(tf,b)                                                    \
57          ldint     b,FRAME_VRSAVE(tf);                                         \
58          mtspr     SPR_VRSAVE,b;
59#else
60#define SAVE_VRSAVE(tf,b)
61#define RESTORE_VRSAVE(tf,b)
62#endif
63
64#if defined (PPC_OEA64) || defined (PPC_OEA64_BRIDGE)
65#define   RFI       rfid
66#else
67#define   RFI       rfi
68#endif /* PPC_OEA64 || PPC_OEA64_BRIDGE*/
69
70#if defined (PPC_OEA64_BRIDGE)
71#define ENABLE_64BIT_BRIDGE(t0)                                                           \
72          mfmsr     t0;                                                                   \
73          clrldi    t0,t0,1;                                                    \
74          mtmsrd    t0;
75#else
76#define ENABLE_64BIT_BRIDGE(t0)
77#endif /* PPC_OEA64_BRIDGE */
78
79#if defined(PPC_OEA64)
80/*
81 * User segment table is loaded through a pointer to the current pmap.
82 */
83#define RESTORE_USER_SRS(t0,t1)                                                           \
84          GET_CPUINFO(t0);                                                      \
85          ldptr     t0,CI_CURPM(t0);                                            \
86          ldreg     t0,PM_STEG(t0);                                                       \
87          mtasr     t0
88
89/*
90 * Kernel segment table is loaded directly from kernel_pmap_
91 */
92#define RESTORE_KERN_SRS(t0,t1)                                                           \
93          lis       t0,_C_LABEL(kernel_pmap_)@ha;                               \
94          ldreg     t0,_C_LABEL(kernel_pmap_)+PM_STEG@l(t0);                    \
95          mtasr     t0
96
97#elif defined(PPC_MPC8XX)
98
99/*
100 * PPC_MPC8XX don't have SRs to load
101 */
102#define RESTORE_USER_SRS(t0,t1)
103#define RESTORE_KERN_SRS(t0,t1)
104
105#else /* not OEA64 */
106
107/*
108 * Restore segment registers from array.
109 */
110#define   RESTORE_SRS(pmap,sr)          mtsr      0,sr; \
111          ldreg     sr,4(pmap);         mtsr      1,sr; \
112          ldreg     sr,8(pmap);         mtsr      2,sr; \
113          ldreg     sr,12(pmap);        mtsr      3,sr; \
114          ldreg     sr,16(pmap);        mtsr      4,sr; \
115          ldreg     sr,20(pmap);        mtsr      5,sr; \
116          ldreg     sr,24(pmap);        mtsr      6,sr; \
117          ldreg     sr,28(pmap);        mtsr      7,sr; \
118          ldreg     sr,32(pmap);        mtsr      8,sr; \
119          ldreg     sr,36(pmap);        mtsr      9,sr; \
120          ldreg     sr,40(pmap);        mtsr      10,sr; \
121          ldreg     sr,44(pmap);        mtsr      11,sr; \
122          ldreg     sr,48(pmap);        mtsr      12,sr; \
123          ldreg     sr,52(pmap);        mtsr      13,sr; \
124          ldreg     sr,56(pmap);        mtsr      14,sr; \
125          ldreg     sr,60(pmap);        mtsr      15,sr; isync;
126
127/*
128 * User SRs are loaded through a pointer to the current pmap.
129 * Note: oea_init() relies on the 601 instruction sequence.
130 */
131#define RESTORE_USER_SRS(pmap,sr)                                               \
132          GET_CPUINFO(pmap);                                                    \
133          ldptr     pmap,CI_CURPM(pmap);                                                  \
134          ldregu    sr,PM_SR(pmap);                                                       \
135          RESTORE_SRS(pmap,sr);                                                           \
136          /* Obliterate BATs on 601; reuse temporary registers. */    \
137          li        sr,0;                                                                 \
138          mtibatl   0,sr;                                                                 \
139          mtibatl   1,sr;                                                                 \
140          mtibatl   2,sr;                                                                 \
141          mtibatl   3,sr
142
143/*
144 * Kernel SRs are loaded directly from kernel_pmap_.
145 * Note: oea_init() relies on the 601 instruction sequence.
146 */
147#define RESTORE_KERN_SRS(pmap,sr)                                               \
148          lis       pmap,_C_LABEL(kernel_pmap_)@ha;                                       \
149          ldregu    sr,_C_LABEL(kernel_pmap_)+PM_SR@l(pmap);                    \
150          RESTORE_SRS(pmap,sr);                                                           \
151          /* Restore fixed BATs on 601; reuse temporary registers. */ \
152          lis       pmap,_C_LABEL(battable)@ha;                                 \
153          ldregu    sr,_C_LABEL(battable)@l(pmap);                                        \
154          mtibatu 0,sr;                                                                   \
155          ldreg     sr,4(pmap);         mtibatl 0,sr;                                     \
156          ldreg     sr,8(pmap);         mtibatu 1,sr;                                     \
157          ldreg     sr,12(pmap);        mtibatl 1,sr
158#endif /* (PPC_OEA64) */
159
160/*
161 * Save/restore MPC601 MQ register.
162 * Note: oea_init() relies on this instruction sequence.
163 */
164#if defined(PPC_OEA601)
165#define   SAVE_MQ(tf,b)                                                                   \
166          mfspr     b,SPR_MQ;                                                   \
167          streg     b,FRAME_MQ(tf);
168
169#define   RESTORE_MQ(tf,b)                                                      \
170          ldreg     b,FRAME_MQ(tf);                                                       \
171          mtspr     SPR_MQ,b;
172#else
173#define   SAVE_MQ(tf,b)
174#define   RESTORE_MQ(tf,b)
175#endif
176
177/*
178 * This code gets copied to all the trap vectors
179 * (except ISI/DSI, ALI, the interrupts).
180 */
181
182/* LINTSTUB: Var: int trapcode[1], trapsize[1]; */
183          .text
184          .globl    _C_LABEL(trapcode),_C_LABEL(trapsize)
185_C_LABEL(trapcode):
186          mtsprg1   %r1                           /* save SP */
187          ENABLE_64BIT_BRIDGE(%r1)
188          GET_CPUINFO(%r1)
189          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)     /* free r28 */
190          streg     %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)     /* free r29 */
191          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)     /* free r30 */
192          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)     /* free r31 */
193          mfsprg1   %r1                           /* restore SP */
194          mflr      %r28                          /* save LR */
195          mfcr      %r29                          /* save CR */
196/* Test whether we already had PR set */
197          mfsrr1    %r31
198          mtcr      %r31
199#if defined(DISTANT_KERNEL)
200          lis       %r31,s_trap@ha
201          addi      %r31,%r31,s_trap@l
202          mtlr      %r31
203          blrl
204#else
205          bla       s_trap
206#endif
207_C_LABEL(trapsize) = .-_C_LABEL(trapcode)
208
209/*
210 * For ALI: has to save DSISR and DAR
211 * Also used as dsitrap for BATless cpus.
212 */
213/* LINTSTUB: Var: int alicode[1], alisize[1]; */
214          .globl    _C_LABEL(alitrap),_C_LABEL(alisize)
215_C_LABEL(alitrap):
216          mtsprg1   %r1                           /* save SP */
217          ENABLE_64BIT_BRIDGE(%r1)
218          GET_CPUINFO(%r1)
219          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */
220          streg     %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r29 */
221          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */
222          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */
223          mfdar     %r30
224          mfdsisr   %r31
225          streg     %r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1)     /* save dar */
226          streg     %r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1)   /* save dsisr */
227          mfsprg1   %r1                           /* restore SP */
228          mflr      %r28                          /* save LR */
229          mfcr      %r29                          /* save CR */
230/* Test whether we already had PR set */
231          mfsrr1    %r31
232          mtcr      %r31
233#if defined(DISTANT_KERNEL)
234          lis       %r31,s_trap@ha
235          addi      %r31,%r31,s_trap@l
236          mtlr      %r31
237          blrl
238#else
239          bla       s_trap
240#endif
241_C_LABEL(alisize) = .-_C_LABEL(alitrap)
242
243#if !defined(PPC_MPC8XX)
244/*
245 * Similar to the above for DSI
246 * Has to handle BAT spills
247 * and standard pagetable spills
248 */
249/* LINTSTUB: Var: int dsicode[1], dsisize[1]; */
250          .globl    _C_LABEL(dsitrap),_C_LABEL(dsisize)
251_C_LABEL(dsitrap):
252          mtsprg1   %r1
253          ENABLE_64BIT_BRIDGE(%r1)
254          GET_CPUINFO(%r1)
255          streg     %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)     /* save r28 */
256          streg     %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)     /* save r29 */
257          streg     %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)     /* save r30 */
258          streg     %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)     /* save r31 */
259          mfsprg1   %r1
260          mfcr      %r29                          /* save CR */
261          mfsrr1    %r31                          /* test kernel mode */
262          mtcr      %r31
263#if !defined(PPC_MPC8XX)
264          mfxer     %r30                          /* save XER */
265          mtsprg2   %r30                          /* in SPRG2 */
266          bt        MSR_PR,1f           /* branch if PSL_PR is set */
267          mfdar     %r31                          /* get fault address */
268          rlwinm    %r31,%r31,3+(32-BAT_ADDR_SHIFT),BAT_ADDR_SHIFT-3,28
269                                                  /* get segment * 8 */
270
271          /* Get address of this CPU's current battable */
272          GET_CPUINFO(%r30)
273          ldreg     %r30,CI_BATTABLE(%r30)
274
275          /* Add offset to the slot we care about. */
276          add       %r31,%r31,%r30
277
278          /* get batu */
279          ldreg     %r30,0(%r31)
280          mtcr      %r30
281          bf        30,1f                         /* branch if supervisor valid is
282                                                     false */
283          /* get batl */
284          ldreg     %r31,SZREG(%r31)
285/* We randomly use the highest two bat registers here */
286          mftb      %r28
287          mtcr      %r28
288          .globl    dsitrap_fix_dbat4, dsitrap_fix_dbat5
289          .globl    dsitrap_fix_dbat6, dsitrap_fix_dbat7
290dsitrap_fix_dbat4:
291          bt        31,3f
292          /*
293           * If we are running on a CPU that has HIGHBAT, these will be replaced
294           * by instructions to test bit 30 (aka bit 1 for normal people) and if
295           * set skip ahead to 5f (4 instructions),  followed by instructions to
296           * update BAT4.
297           */
298          mtspr     SPR_DBAT2U,%r30               /*        bt        30,dsitrap_fix_dbat5 */
299          mtspr     SPR_DBAT2L,%r31               /*        mtspr     SPR_DBAT4U,%r30 */
300          b         8f                            /*        mtspr     SPR_DBAT4L,%r31 */
301          b         8f                            /*        do not remove */
302dsitrap_fix_dbat5:
303          mtspr     SPR_DBAT5U,%r30
304          mtspr     SPR_DBAT5L,%r31
305          b         8f
306dsitrap_fix_dbat6:
307          bt        30,3f
308          mtspr     SPR_DBAT6U,%r30
309          mtspr     SPR_DBAT6L,%r31
310          b         8f
3113:
312dsitrap_fix_dbat7:
313          /*
314           * If we are running on a CPU that has HIGHBAT, these will be replaced
315           * by instructions to update BAT7.
316           */
317          mtspr     SPR_DBAT3U,%r30               /*        mtspr     SPR_DBAT7U,%r30 */
318          mtspr     SPR_DBAT3L,%r31               /*        mtspr     SPR_DBAT7L,%r31 */
3198:
320          mfsprg2   %r30                          /* restore XER */
321          mtxer     %r30
322          mtcr      %r29                          /* restore CR */
323          mtsprg1   %r1
324          GET_CPUINFO(%r1)
325          ldreg     %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)     /* restore r28 */
326          ldreg     %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)     /* restore r29 */
327          ldreg     %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)     /* restore r30 */
328          ldreg     %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)     /* restore r31 */
329          mfsprg1   %r1
330          RFI                                     /* return to trapped code */
3311:
332#endif    /* !PPC_MPC8XX */
333          mflr      %r28                          /* save LR */
334          mtsprg1   %r1                           /* save SP */
335#if defined(DISTANT_KERNEL)
336          lis       %r31,disitrap@ha
337          addi      %r31,%r31,disitrap@l
338          mtlr      %r31
339          blrl
340#else
341          bla       disitrap
342#endif
343_C_LABEL(dsisize) = .-_C_LABEL(dsitrap)
344#endif /* !PPC_MPC8XX */
345
346#if defined(PPC_OEA601)
347/*
348 * Dedicated MPC601 version of the above.
349 * Considers different BAT format and combined implementation
350 * (being addressed as I-BAT).
351 */
352/* LINTSTUB: Var: int dsi601code[1], dsi601size[1]; */
353          .globl    _C_LABEL(dsi601trap),_C_LABEL(dsi601size)
354_C_LABEL(dsi601trap):
355          mtsprg1   %r1
356          ENABLE_64BIT_BRIDGE(%r1)
357          GET_CPUINFO(%r1)
358          streg     %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)     /* save r28 */
359          streg     %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)     /* save r29 */
360          streg     %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)     /* save r30 */
361          streg     %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)     /* save r31 */
362          mfsprg1   %r1
363          mfcr      %r29                          /* save CR */
364          mfxer     %r30                          /* save XER */
365          mtsprg2   %r30                          /* in SPRG2 */
366          mfsrr1    %r31                          /* test kernel mode */
367          mtcr      %r31
368          bt        MSR_PR,1f           /* branch if PSL_PR is set */
369          mfdar     %r31                          /* get fault address */
370          rlwinm    %r31,%r31,12,20,28  /* get "segment" battable offset */
371
372          /* Get address of this CPU's current battable */
373          GET_CPUINFO(%r30)
374          ldreg     %r30,CI_BATTABLE(%r30)
375
376          /* Add offset to the slot we care about. */
377          add       %r31,%r31,%r30
378
379          /* get batl */
380          ldreg     %r30,SZREG(%r31)
381          mtcr      %r30
382          bf        25,1f                         /* branch if Valid is false,
383                                                     presently assumes supervisor only */
384
385          /* get batu */
386          ldreg     %r31,0(%r31)
387/* We randomly use the highest two bat registers here */
388          mfspr     %r28,SPR_RTCL_R
389          andi.     %r28,%r28,128
390          bne       2f
391          mtibatu   2,%r31
392          mtibatl   2,%r30
393          b         3f
3942:
395          mtibatu   3,%r31
396          mtibatl   3,%r30
3973:
398          mfsprg2   %r30                          /* restore XER */
399          mtxer     %r30
400          mtcr      %r29                          /* restore CR */
401          mtsprg1   %r1
402          GET_CPUINFO(%r1)
403          ldreg     %r28,(CI_DISISAVE+CPUSAVE_R28)(%r1)     /* restore r28 */
404          ldreg     %r29,(CI_DISISAVE+CPUSAVE_R29)(%r1)     /* restore r29 */
405          ldreg     %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)     /* restore r30 */
406          ldreg     %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)     /* restore r31 */
407          mfsprg1   %r1
408          RFI                                     /* return to trapped code */
4091:
410          mflr      %r28                          /* save LR */
411          mtsprg1   %r1
412#if defined(DISTANT_KERNEL)
413          lis       %r31,disitrap@ha
414          addi      %r31,%r31,disitrap@l
415          mtlr      %r31
416          blrl
417#else
418          bla       disitrap
419#endif
420_C_LABEL(dsi601size) = .-_C_LABEL(dsi601trap)
421#endif /* defined(PPC_OEA601) */
422
423/*
424 * This one for the external interrupt handler.
425 */
426/* LINTSTUB: Var: int extint[1], extsize[1]; */
427          .globl    _C_LABEL(extint),_C_LABEL(extsize)
428_C_LABEL(extint):
429          mtsprg1   %r1                           /* save SP */
430          ENABLE_64BIT_BRIDGE(%r1)
431          GET_CPUINFO(%r1)
432          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)     /* save r28 */
433          streg     %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)     /* save r29 */
434          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)     /* save r30 */
435          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)     /* save r31 */
436          mflr      %r28                          /* save LR */
437          mfcr      %r29                          /* save CR */
438          mfsrr1    %r31
439          mtcr      %r31
440          mr        %r30,%r1
441          mfsprg1   %r1                           /* get old SP */
442          bf        MSR_PR,1f           /* branch if PSL_PR is true */
443          ldptr     %r1,CI_CURPCB(%r30) /* get kernel stack */
444          addi      %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
445          RESTORE_KERN_SRS(%r30, %r31)
4461:
447#if defined(DISTANT_KERNEL)
448          lis       %r31,extintr@ha
449          addi      %r31,%r31,extintr@l
450          mtlr      %r31
451          blr
452#else
453          ba        extintr
454#endif
455_C_LABEL(extsize) = .-_C_LABEL(extint)
456
457/*
458 * And this one for the decrementer interrupt handler.
459 */
460/* LINTSTUB: Var: int decrint[1], decrsize[1]; */
461          .globl    _C_LABEL(decrint),_C_LABEL(decrsize)
462_C_LABEL(decrint):
463          mtsprg1   %r1                           /* save SP */
464          ENABLE_64BIT_BRIDGE(%r1)
465          GET_CPUINFO(%r1)
466          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)     /* save r28 */
467          streg     %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)     /* save r29 */
468          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)     /* save r30 */
469          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)     /* save r31 */
470          mflr      %r28                          /* save LR */
471          mfcr      %r29                          /* save CR */
472          mfsrr1    %r31
473          mtcr      %r31
474          mr        %r30,%r1
475          mfsprg1   %r1                           /* yes, get old SP */
476          bf        MSR_PR,1f           /* branch if PSL_PR is true */
477          ldptr     %r1,CI_CURPCB(%r30) /* get kernel stack */
478          addi      %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
479          RESTORE_KERN_SRS(%r30, %r31)
4801:
481#if defined(DISTANT_KERNEL)
482          lis       %r31,decrintr@ha
483          addi      %r31,%r31,decrintr@l
484          mtlr      %r31
485          blr
486#else
487          ba        decrintr
488#endif
489_C_LABEL(decrsize) = .-_C_LABEL(decrint)
490
491#if !defined(PPC_OEA64) && !defined(PPC_MPC8XX)
492/*
493 * Now the tlb software load for 603 processors:
494 * (Code essentially from the 603e User Manual, Chapter 5, but
495 * corrected a lot.)
496 */
497/* LINTSTUB: Var: int tlbimiss[1], tlbimsize[1]; */
498          .globl    _C_LABEL(tlbimiss),_C_LABEL(tlbimsize)
499_C_LABEL(tlbimiss):
500          mfspr     %r2,SPR_HASH1                 /* get first pointer */
501          li        %r1,8
502          mfctr     %r0                           /* save counter */
503          mfspr     %r3,SPR_ICMP                  /* get first compare value */
504          addi      %r2,%r2,-8                    /* predec pointer */
5051:
506          mtctr     %r1                           /* load counter */
5072:
508          ldregu    %r1,8(%r2)                    /* get next pte */
509          cmplw     %r1,%r3                       /* see if found pte */
510          bdneq     2b                            /* loop if not eq */
511          bne       3f                            /* not found */
512          ldreg     %r1,4(%r2)                    /* load tlb entry lower word */
513          andi.     %r3,%r1,PTE_G                 /* check G-bit */
514          bne       4f                            /* if guarded, take ISI */
515          mtctr     %r0                           /* restore counter */
516          mfspr     %r0,SPR_IMISS                 /* get the miss address for the tlbli */
517          mfsrr1    %r3                           /* get the saved cr0 bits */
518          mtcrf     0x80,%r3            /* and restore */
519          ori       %r1,%r1,PTE_REF               /* set the reference bit */
520          mtspr     SPR_RPA,1           /* set the pte */
521          srwi      %r1,%r1,8           /* get byte 7 of pte */
522          tlbli     %r0                           /* load the itlb */
523          stb       %r1,6(%r2)                    /* update page table */
524          RFI
525
5263:        /* not found in pteg */
527          andi.     %r1,%r3,PTE_HID               /* have we already done second hash? */
528          bne       5f
529          mfspr     %r2,SPR_HASH2                 /* get the second pointer */
530          ori       %r3,%r3,PTE_HID               /* change the compare value */
531          li        %r1,8
532          addi      %r2,%r2,-8                    /* predec pointer */
533          b         1b
5344:        /* guarded */
535          mfsrr1    %r3
536          andi.     %r2,%r3,0xffff                /* clean upper srr1 */
537          oris      %r2,%r2,DSISR_PROTECT@h       /* set srr<4> to flag prot violation */
538          b         6f
5395:        /* not found anywhere */
540          mfsrr1    %r3
541          andi.     %r2,%r3,0xffff                /* clean upper srr1 */
542          oris      %r2,%r2,DSISR_NOTFOUND@h /* set srr1<1> to flag pte not found */
5436:
544          mtctr     %r0                           /* restore counter */
545          mtsrr1    %r2
546          mfmsr     %r0
547          xoris     %r0,%r0,PSL_TGPR@h  /* flip the msr<tgpr> bit */
548          mtcrf     0x80,%r3            /* restore cr0 */
549          mtmsr     %r0                           /* now with native gprs */
550          isync
551#if defined(PPC_HIGH_VEC)
552          ba        EXC_HIGHVEC+EXC_ISI
553#else
554          ba        EXC_ISI
555#endif
556_C_LABEL(tlbimsize) = .-_C_LABEL(tlbimiss)
557
558/* LINTSTUB: Var: int tlbdlmiss[1], tlbdlmsize[1]; */
559          .globl    _C_LABEL(tlbdlmiss),_C_LABEL(tlbdlmsize)
560_C_LABEL(tlbdlmiss):
561          mfspr     %r2,SPR_HASH1                 /* get first pointer */
562          li        %r1,8
563          mfctr     %r0                           /* save counter */
564          mfspr     %r3,SPR_DCMP                  /* get first compare value */
565          addi      %r2,%r2,-8                    /* predec pointer */
5661:
567          mtctr     %r1                           /* load counter */
5682:
569          ldregu    %r1,8(%r2)                    /* get next pte */
570          cmplw     %r1,%r3                       /* see if found pte */
571          bdneq     2b                            /* loop if not eq */
572          bne       3f                            /* not found */
573          ldreg     %r1,4(%r2)                    /* load tlb entry lower word */
574          mtctr     %r0                           /* restore counter */
575          mfspr     %r0,SPR_DMISS                 /* get the miss address for the tlbld */
576          mfsrr1    %r3                           /* get the saved cr0 bits */
577          mtcrf     0x80,%r3            /* and restore */
578          ori       %r1,%r1,PTE_REF               /* set the reference bit */
579          mtspr     SPR_RPA,%r1                   /* set the pte */
580          srwi      %r1,%r1,8           /* get byte 7 of pte */
581          tlbld     %r0                           /* load the dtlb */
582          stb       %r1,6(%r2)                    /* update page table */
583          RFI
584
5853:        /* not found in pteg */
586          andi.     %r1,%r3,PTE_HID               /* have we already done second hash? */
587          bne       5f
588          mfspr     %r2,SPR_HASH2                 /* get the second pointer */
589          ori       %r3,%r3,PTE_HID               /* change the compare value */
590          li        %r1,8
591          addi      %r2,%r2,-8                    /* predec pointer */
592          b         1b
5935:        /* not found anywhere */
594          mfsrr1    %r3
595          lis       %r1,DSISR_NOTFOUND@h          /* set dsisr<1> to flag pte not found */
596          mtctr     %r0                           /* restore counter */
597          andi.     %r2,%r3,0xffff                /* clean upper srr1 */
598          mtsrr1    %r2
599          mtdsisr   %r1                           /* load the dsisr */
600          mfspr     %r1,SPR_DMISS                 /* get the miss address */
601          mtdar     %r1                           /* put in dar */
602          mfmsr     %r0
603          xoris     %r0,%r0,PSL_TGPR@h  /* flip the msr<tgpr> bit */
604          mtcrf     0x80,%r3            /* restore cr0 */
605          mtmsr     %r0                           /* now with native gprs */
606          isync
607#if defined(PPC_HIGH_VEC)
608          ba        EXC_HIGHVEC+EXC_DSI
609#else
610          ba        EXC_DSI
611#endif
612_C_LABEL(tlbdlmsize) = .-_C_LABEL(tlbdlmiss)
613
614/* LINTSTUB: Var: int tlbdsmiss[1], tlbdsmsize[1]; */
615          .globl    _C_LABEL(tlbdsmiss),_C_LABEL(tlbdsmsize)
616_C_LABEL(tlbdsmiss):
617          mfspr     %r2,SPR_HASH1                 /* get first pointer */
618          li        %r1,8
619          mfctr     %r0                           /* save counter */
620          mfspr     %r3,SPR_DCMP                  /* get first compare value */
621          addi      %r2,%r2,-8                    /* predec pointer */
6221:
623          mtctr     %r1                           /* load counter */
6242:
625          ldregu    %r1,8(%r2)                    /* get next pte */
626          cmplw     %r1,%r3                       /* see if found pte */
627          bdneq     2b                            /* loop if not eq */
628          bne       3f                            /* not found */
629          ldreg     %r1,4(%r2)                    /* load tlb entry lower word */
630          andi.     %r3,%r1,PTE_CHG               /* check the C-bit */
631          beq       4f
6325:
633          mtctr     %r0                           /* restore counter */
634          mfspr     %r0,SPR_DMISS                 /* get the miss address for the tlbld */
635          mfsrr1    %r3                           /* get the saved cr0 bits */
636          mtcrf     0x80,%r3            /* and restore */
637          mtspr     SPR_RPA,%r1                   /* set the pte */
638          tlbld     %r0                           /* load the dtlb */
639          RFI
640
6413:        /* not found in pteg */
642          andi.     %r1,%r3,PTE_HID               /* have we already done second hash? */
643          bne       5f
644          mfspr     %r2,SPR_HASH2                 /* get the second pointer */
645          ori       %r3,%r3,PTE_HID               /* change the compare value */
646          li        %r1,8
647          addi      %r2,%r2,-8                    /* predec pointer */
648          b         1b
6494:        /* found, but C-bit = 0 */
650          rlwinm.   %r3,%r1,30,0,1                /* test PP */
651          bge-      7f
652          andi.     %r3,%r1,1
653          beq+      8f
6549:        /* found, but protection violation (PP==00)*/
655          mfsrr1    %r3
656          lis       %r1,(DSISR_PROTECT|DSISR_STORE)@h
657                                                  /* indicate protection violation
658                                                     on store */
659          b         1f
6607:        /* found, PP=1x */
661          mfspr     %r3,SPR_DMISS                 /* get the miss address */
662          mfsrin    %r1,%r3                       /* get the segment register */
663          mfsrr1    %r3
664          rlwinm    %r3,%r3,18,31,31    /* get PR-bit */
665          rlwnm.    %r1,%r1,%r3,1,1               /* get the key */
666          bne-      9b                            /* protection violation */
6678:        /* found, set reference/change bits */
668          ldreg     %r1,4(%r2)                    /* reload tlb entry */
669          ori       %r1,%r1,(PTE_REF|PTE_CHG)
670          sth       %r1,6(%r2)
671          b         5b
6725:        /* not found anywhere */
673          mfsrr1    %r3
674          lis       %r1,(DSISR_NOTFOUND|DSISR_STORE)@h
675                                                  /* set dsisr<1> to flag pte not found */
676                                                  /* dsisr<6> to flag store */
6771:
678          mtctr     %r0                           /* restore counter */
679          andi.     %r2,%r3,0xffff                /* clean upper srr1 */
680          mtsrr1    %r2
681          mtdsisr   %r1                           /* load the dsisr */
682          mfspr     %r1,SPR_DMISS                 /* get the miss address */
683          mtdar     %r1                           /* put in dar */
684          mfmsr     %r0
685          xoris     %r0,%r0,PSL_TGPR@h  /* flip the msr<tgpr> bit */
686          mtcrf     0x80,%r3            /* restore cr0 */
687          mtmsr     %r0                           /* now with native gprs */
688          isync
689#if defined(PPC_HIGH_VEC)
690          ba        EXC_HIGHVEC+EXC_DSI
691#else
692          ba        EXC_DSI
693#endif
694_C_LABEL(tlbdsmsize) = .-_C_LABEL(tlbdsmiss)
695#endif /* !PPC_OEA64 && !PPC_MPC8XX */
696
697#if defined(DDB) || defined(KGDB)
698/*
699 * In case of DDB we want a separate trap catcher for it
700 */
701          .local    ddbstk
702          .comm     ddbstk,INTSTK,8               /* ddb stack */
703
704/* LINTSTUB: Var: int ddblow[1], ddbsize[1]; */
705          .globl    _C_LABEL(ddblow),_C_LABEL(ddbsize)
706_C_LABEL(ddblow):
707          mtsprg1   %r1                           /* save SP */
708          ENABLE_64BIT_BRIDGE(%r1)
709          mtsprg2 %r29                            /* save r29 */
710          mfcr      %r29                          /* save CR in r29 */
711          mfsrr1    %r1
712          mtcr      %r1
713          GET_CPUINFO(%r1)
714          bf        MSR_PR,1f           /* branch if privileged */
715          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)     /* free r28 */
716          mfsprg2   %r28
717          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)     /* free r29 */
718          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)     /* free r30 */
719          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)     /* free r31 */
720          mflr      %r28                          /* save LR */
721#if defined(DISTANT_KERNEL)
722          lis       %r31,u_trap@ha
723          addi      %r31,%r31,u_trap@l
724          mtlr      %r31
725          blrl
726#else
727          bla       u_trap
728#endif
7291:
730          streg     %r28,(CI_DDBSAVE+CPUSAVE_R28)(%r1) /* save r28 */
731          mfsprg2   %r28
732          streg     %r28,(CI_DDBSAVE+CPUSAVE_R29)(%r1) /* save r29 */
733          streg     %r30,(CI_DDBSAVE+CPUSAVE_R30)(%r1) /* save r30 */
734          streg     %r31,(CI_DDBSAVE+CPUSAVE_R31)(%r1) /* save r31 */
735          mflr      %r28                          /* save LR */
736          lis       %r1,ddbstk+INTSTK@ha          /* get new SP */
737          addi      %r1,%r1,ddbstk+INTSTK@l
738#if defined(DISTANT_KERNEL)
739          lis       %r31,ddbtrap@ha
740          addi      %r31,%r31,ddbtrap@l
741          mtlr      %r31
742          blrl
743#else
744          bla       ddbtrap
745#endif
746_C_LABEL(ddbsize) = .-_C_LABEL(ddblow)
747#endif    /* DDB || KGDB */
748
749/*
750 * FRAME_SETUP assumes:
751 *        SPRG1               SP (%r1)
752 *        savearea  r28-r31,DAR,DSISR   (DAR & DSISR only for DSI traps)
753 *        28                  LR
754 *        29                  CR
755 *        30                  scratch
756 *        31                  scratch
757 *        1                   kernel stack
758 *        LR                  trap type
759 *        SRR0/1              as at start of trap
760 */
761#define   FRAME_SETUP(savearea)                                                           \
762/* Have to enable translation to allow access of kernel stack: */     \
763          GET_CPUINFO(%r31);                                                    \
764          mfsrr0    %r30;                                                                 \
765          streg     %r30,(savearea+CPUSAVE_SRR0)(%r31);     /* save SRR0 */     \
766          mfsrr1    %r30;                                                                 \
767          streg     %r30,(savearea+CPUSAVE_SRR1)(%r31);     /* save SRR1 */     \
768          mfmsr     %r30;                                                                 \
769          ori       %r30,%r30,(PSL_DR|PSL_IR);    /* turn on relocation */ \
770          mtmsr     %r30;                         /* stack can be accessed now */         \
771          isync;                                                                          \
772          mfsprg1   %r31;                         /* get saved SP */            \
773          stregu    %r31,-FRAMELEN(%r1);          /* save it in the callframe */          \
774          streg     %r0,FRAME_R0(%r1);  /* save R0 in the trapframe */ \
775          streg     %r31,FRAME_R1(%r1); /* save SP in the trapframe */ \
776          streg     %r2,FRAME_R2(%r1);  /* save R2 in the trapframe */ \
777          streg     %r28,FRAME_LR(%r1);                               \
778          stint     %r29,FRAME_CR(%r1);                               \
779          GET_CPUINFO(%r2);                                                     \
780          ldreg     %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */       \
781          ldreg     %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */       \
782          ldreg     %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */       \
783          ldreg     %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */       \
784          streg     %r3,FRAME_R3(%r1);  /* save r3 */                 \
785          streg     %r4,FRAME_R4(%r1);  /* save r4 */                 \
786          streg     %r5,FRAME_R5(%r1);  /* save r5 */                 \
787          streg     %r6,FRAME_R6(%r1);  /* save r6 */                 \
788          streg     %r7,FRAME_R7(%r1);  /* save r7 */                 \
789          streg     %r8,FRAME_R8(%r1);  /* save r8 */                 \
790          streg     %r9,FRAME_R9(%r1);  /* save r9 */                 \
791          streg     %r10,FRAME_R10(%r1);          /* save r10 */                \
792          streg     %r11,FRAME_R11(%r1);          /* save r11 */                \
793          streg     %r12,FRAME_R12(%r1);          /* save r12 */                \
794          streg     %r13,FRAME_R13(%r1);          /* save r13 */                \
795          streg     %r14,FRAME_R14(%r1);          /* save r14 */                \
796          streg     %r15,FRAME_R15(%r1);          /* save r15 */                \
797          streg     %r16,FRAME_R16(%r1);          /* save r16 */                \
798          streg     %r17,FRAME_R17(%r1);          /* save r17 */                \
799          streg     %r18,FRAME_R18(%r1);          /* save r18 */                \
800          streg     %r19,FRAME_R19(%r1);          /* save r19 */                \
801          streg     %r20,FRAME_R20(%r1);          /* save r20 */                \
802          streg     %r21,FRAME_R21(%r1);          /* save r21 */                \
803          streg     %r22,FRAME_R22(%r1);          /* save r22 */                \
804          streg     %r23,FRAME_R23(%r1);          /* save r23 */                \
805          streg     %r24,FRAME_R24(%r1);          /* save r24 */                \
806          streg     %r25,FRAME_R25(%r1);          /* save r25 */                \
807          streg     %r26,FRAME_R26(%r1);          /* save r26 */                \
808          streg     %r27,FRAME_R27(%r1);          /* save r27 */                \
809          streg     %r28,FRAME_R28(%r1);          /* save r28 */                \
810          streg     %r29,FRAME_R29(%r1);          /* save r29 */                \
811          streg     %r30,FRAME_R30(%r1);          /* save r30 */                \
812          streg     %r31,FRAME_R31(%r1);          /* save r31 */                \
813          ldreg     %r28,(savearea+CPUSAVE_DAR)(%r2); /* get saved DAR */       \
814          ldreg     %r29,(savearea+CPUSAVE_DSISR)(%r2); /* get saved DSISR */ \
815          ldreg     %r30,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */     \
816          ldreg     %r31,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */     \
817          ldptr     %r13,CI_CURLWP(%r2);          /* get curlwp */    \
818          mfxer     %r3;                                                        \
819          mfctr     %r4;                                                        \
820          mflr      %r5;                                                        \
821          andi.     %r5,%r5,0xff00;                                             \
822          stint     %r3,FRAME_XER(%r1);                               \
823          streg     %r4,FRAME_CTR(%r1);                               \
824          streg     %r30,FRAME_SRR0(%r1);                             \
825          streg     %r31,FRAME_SRR1(%r1);                             \
826          streg     %r28,FRAME_DAR(%r1);                              \
827          stint     %r29,FRAME_DSISR(%r1);                            \
828          stint     %r5,FRAME_EXC(%r1);                     \
829          SAVE_VRSAVE(%r1,%r6);                                       \
830          SAVE_MQ(%r1,%r7)
831
832#define   FRAME_RESTORE_CALLEE                                                  \
833          ldreg     %r31,FRAME_R31(%r1);          /* restore r31 */   \
834          ldreg     %r30,FRAME_R30(%r1);          /* restore r30 */   \
835          ldreg     %r29,FRAME_R29(%r1);          /* restore r29 */   \
836          ldreg     %r28,FRAME_R28(%r1);          /* restore r28 */   \
837          ldreg     %r27,FRAME_R27(%r1);          /* restore r27 */   \
838          ldreg     %r26,FRAME_R26(%r1);          /* restore r26 */   \
839          ldreg     %r25,FRAME_R25(%r1);          /* restore r25 */   \
840          ldreg     %r24,FRAME_R24(%r1);          /* restore r24 */   \
841          ldreg     %r23,FRAME_R23(%r1);          /* restore r23 */   \
842          ldreg     %r22,FRAME_R22(%r1);          /* restore r22 */   \
843          ldreg     %r21,FRAME_R21(%r1);          /* restore r21 */   \
844          ldreg     %r20,FRAME_R20(%r1);          /* restore r20 */   \
845          ldreg     %r19,FRAME_R19(%r1);          /* restore r19 */   \
846          ldreg     %r18,FRAME_R18(%r1);          /* restore r18 */   \
847          ldreg     %r17,FRAME_R17(%r1);          /* restore r17 */   \
848          ldreg     %r16,FRAME_R16(%r1);          /* restore r16 */   \
849          ldreg     %r15,FRAME_R15(%r1);          /* restore r15 */   \
850          ldreg     %r14,FRAME_R14(%r1);          /* restore r14 */
851
852#define   FRAME_LEAVE(savearea)                                                 \
853/* Now restore regs: */                                                         \
854          ldreg     %r2,FRAME_SRR0(%r1);                                        \
855          ldreg     %r3,FRAME_SRR1(%r1);                                        \
856          ldreg     %r4,FRAME_CTR(%r1);                               \
857          ldint     %r5,FRAME_XER(%r1);                               \
858          ldreg     %r6,FRAME_LR(%r1);                                \
859          RESTORE_MQ(%r1,%r8);                                                            \
860          RESTORE_VRSAVE(%r1,%r9);                                              \
861          GET_CPUINFO(%r7);                                                     \
862          streg     %r2,(savearea+CPUSAVE_SRR0)(%r7); /* save SRR0 */ \
863          streg     %r3,(savearea+CPUSAVE_SRR1)(%r7); /* save SRR1 */ \
864          ldint     %r7,FRAME_CR(%r1);                                \
865          mtctr     %r4;                                                                  \
866          mtxer     %r5;                                                                  \
867          mtlr      %r6;                                                                  \
868          mtsprg1   %r7;                          /* save cr */                           \
869          ldreg     %r13,FRAME_R13(%r1);          /* restore r13 */   \
870          ldreg     %r12,FRAME_R12(%r1);          /* restore r12 */   \
871          ldreg     %r11,FRAME_R11(%r1);          /* restore r11 */   \
872          ldreg     %r10,FRAME_R10(%r1);          /* restore r10 */   \
873          ldreg     %r9,FRAME_R9(%r1);  /* restore r9 */    \
874          ldreg     %r8,FRAME_R8(%r1);  /* restore r8 */    \
875          ldreg     %r7,FRAME_R7(%r1);  /* restore r7 */    \
876          ldreg     %r6,FRAME_R6(%r1);  /* restore r6 */    \
877          ldreg     %r5,FRAME_R5(%r1);  /* restore r5 */    \
878          ldreg     %r4,FRAME_R4(%r1);  /* restore r4 */    \
879          ldreg     %r3,FRAME_R3(%r1);  /* restore r3 */    \
880          ldreg     %r2,FRAME_R2(%r1);  /* restore r2 */    \
881          ldreg     %r0,FRAME_R0(%r1);  /* restore r0 */    \
882          ldreg     %r1,FRAME_R1(%r1);  /* restore old sp in r1 */ \
883/* Can't touch %r1 from here on */                                              \
884          mtsprg2   %r2;                          /* save r2 & r3 */            \
885          mtsprg3   %r3;                                                                  \
886/* Disable translation, machine check and recoverability: */                    \
887          mfmsr     %r2;                                                                  \
888          andi.     %r2,%r2,~(PSL_DR|PSL_IR|PSL_ME|PSL_RI)@l;                   \
889          mtmsr     %r2;                                                                  \
890          isync;                                                                          \
891/* Decide whether we return to user mode: */                                    \
892          GET_CPUINFO(%r2);                                                     \
893          ldreg     %r3,(savearea+CPUSAVE_SRR1)(%r2);                           \
894          mtcr      %r3;                                                                  \
895          bf        MSR_PR,1f;                    /* branch if PSL_PR is false */         \
896/* Restore user SRs */                                                                    \
897          RESTORE_USER_SRS(%r2,%r3);                                            \
8981:        mfsprg1   %r2;                          /* restore cr */              \
899          mtcr      %r2;                                                                  \
900          GET_CPUINFO(%r2);                                                     \
901          ldreg     %r3,(savearea+CPUSAVE_SRR0)(%r2);                           \
902          mtsrr0    %r3;                                                                  \
903          ldreg     %r3,(savearea+CPUSAVE_SRR1)(%r2);                           \
904          mtsrr1    %r3;                                                                  \
905          mfsprg2   %r2;                          /* restore r2 & r3 */                   \
906          mfsprg3   %r3
907
908/*
909 * Preamble code for DSI/ISI traps
910 */
911disitrap:
912          GET_CPUINFO(%r1)
913          ldreg     %r30,(CI_DISISAVE+CPUSAVE_R28)(%r1)
914          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R28)(%r1)
915          ldreg     %r31,(CI_DISISAVE+CPUSAVE_R29)(%r1)
916          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R29)(%r1)
917          ldreg     %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1)
918          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1)
919          ldreg     %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1)
920          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1)
921          mfdar     %r30
922          mfdsisr   %r31
923          streg     %r30,(CI_TEMPSAVE+CPUSAVE_DAR)(%r1)
924          streg     %r31,(CI_TEMPSAVE+CPUSAVE_DSISR)(%r1)
925
926#ifdef DDB
927          mfsrr1    %r31
928          mtcr      %r31
929          bt        MSR_PR,trapstart    /* branch is user mode */
930          mfsprg1   %r31                          /* get old SP */
931#if 0
932          subf      %r30,%r30,%r31                /* subtract DAR from it */
933          addi      %r30,%r30,2048                /* offset result 1/2 page */
934          cmplwi    %cr0,%r30,4096                /* is DAR +- 1/2 page of SP? */
935#else
936          xor.      %r30,%r30,%r31                /* try xor most significant bits */
937          cmplwi    %cr0,%r30,4096                /* is DAR on same page as SP? */
938#endif
939          bge       %cr0,trapstart                /* no, too far away. */
940          /* Now convert this DSI into a DDB trap.  */
941          GET_CPUINFO(%r1)
942          ldreg     %r30,(CI_DISISAVE+CPUSAVE_R28)(%r1) /* get  r28 */
943          streg     %r30,(CI_DDBSAVE +CPUSAVE_R28)(%r1) /* save r28 */
944          ldreg     %r31,(CI_DISISAVE+CPUSAVE_R29)(%r1) /* get  r29 */
945          streg     %r31,(CI_DDBSAVE +CPUSAVE_R29)(%r1) /* save r29 */
946          ldreg     %r30,(CI_DISISAVE+CPUSAVE_R30)(%r1) /* get  r30 */
947          streg     %r30,(CI_DDBSAVE +CPUSAVE_R30)(%r1) /* save r30 */
948          ldreg     %r31,(CI_DISISAVE+CPUSAVE_R31)(%r1) /* get  r31 */
949          streg     %r31,(CI_DDBSAVE +CPUSAVE_R31)(%r1) /* save r31 */
950          lis       %r1,ddbstk+INTSTK@ha          /* get new SP */
951          addi      %r1,%r1,ddbstk+INTSTK@l
952          b         ddbtrap
953#endif
954
955          .globl    _C_LABEL(trapstart)
956          .type     _C_LABEL(trapstart),@function
957_C_LABEL(trapstart):
958realtrap:
959/* Test whether we already had PR set */
960          mfsrr1    %r1
961          mtcr      %r1
962          mfsprg1   %r1                           /* restore SP (might have been
963                                                     overwritten) */
964s_trap:
965          bf        MSR_PR,k_trap                 /* branch if PSL_PR is false */
966          GET_CPUINFO(%r1)              /* get cpu_info for this cpu */
967u_trap:
968          ldptr     %r1,CI_CURPCB(%r1)
969          addi      %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
970
971/*
972 * Now the common trap catching code.
973 */
974
975          RESTORE_KERN_SRS(%r30,%r31)   /* First enable KERNEL mapping */
976
977k_trap:
978          FRAME_SETUP(CI_TEMPSAVE)
979trapagain:
980/* Now we can recover interrupts again: */
981          mfmsr     %r7
982          ldreg     %r6, FRAME_SRR1(%r1)
983          andi.     %r6,%r6,(PSL_EE|PSL_ME|PSL_RI)@l
984          or        %r7,%r7,%r6
985          mtmsr     %r7
986          isync
987/* Call C trap code: */
988          addi      %r3,%r1,FRAME_TF
989          bl        _C_LABEL(trap)
990/* LINTSTUB: Var: int trapexit[1]; */
991          .globl    trapexit
992trapexit:
993/* Disable interrupts: */
994          mfmsr     %r3
995          andi.     %r3,%r3,~PSL_EE@l
996          mtmsr     %r3
997/* Test AST pending: */
998          mtcr      %r31
999          bf        MSR_PR,trapleave    /* branch if PSL_PR is false */
1000          ldint     %r4,L_MD_ASTPENDING(%r13)
1001          andi.     %r4,%r4,1
1002          beq       trapleave
1003
1004          li        %r6,EXC_AST
1005          stint     %r6,FRAME_EXC(%r1)
1006          b         trapagain
1007
1008trapleave:
1009          FRAME_RESTORE_CALLEE
1010intrleave:
1011          FRAME_LEAVE(CI_TEMPSAVE)
1012          RFI
1013
1014/*
1015 * Trap handler for syscalls (EXC_SC)
1016 */
1017/* LINTSTUB: Var: int sctrap[1], scsize[1]; */
1018          .globl    _C_LABEL(sctrap),_C_LABEL(scsize),_C_LABEL(sctrapexit)
1019_C_LABEL(sctrap):
1020          mtsprg1   %r1                           /* save SP */
1021          ENABLE_64BIT_BRIDGE(%r1)
1022          GET_CPUINFO(%r1)
1023          streg     %r28,(CI_TEMPSAVE+CPUSAVE_R28)(%r1) /* save r28 */
1024          streg     %r29,(CI_TEMPSAVE+CPUSAVE_R29)(%r1) /* save r20 */
1025          streg     %r30,(CI_TEMPSAVE+CPUSAVE_R30)(%r1) /* save r30 */
1026          streg     %r31,(CI_TEMPSAVE+CPUSAVE_R31)(%r1) /* save r31 */
1027          mflr      %r28                          /* save LR */
1028          mfcr      %r29                          /* save CR */
1029#if defined(DISTANT_KERNEL)
1030          lis       %r31,s_sctrap@ha
1031          addi      %r31,%r31,s_sctrap@l
1032          mtlr      %r31
1033          blrl
1034#else
1035          bla       s_sctrap
1036#endif
1037          _C_LABEL(scsize) = .-_C_LABEL(sctrap)
1038
1039s_sctrap:
1040          GET_CPUINFO(%r1)
1041          ldptr     %r1,CI_CURPCB(%r1)
1042          addi      %r1,%r1,USPACE-CALLFRAMELEN /* stack is top of user struct */
1043          RESTORE_KERN_SRS(%r30,%r31)   /* First enable KERNEL mapping */
1044          FRAME_SETUP(CI_TEMPSAVE)
1045/* Now we can recover interrupts again: */
1046          mfmsr     %r7
1047          ori       %r7,%r7,(PSL_EE|PSL_ME|PSL_RI)@l
1048          mtmsr     %r7
1049          isync
1050          addi      %r3,%r1,FRAME_TF
1051/* Call the appropriate syscall handler: */
1052          ldptr     %r4,L_PROC(%r13)
1053          ldptr     %r4,P_MD_SYSCALL(%r4)
1054          mtctr     %r4
1055          bctrl
1056_C_LABEL(sctrapexit):
1057          b         trapexit
1058
1059/*
1060 * External interrupt second level handler
1061 */
1062/*
1063 * INTR_SETUP assumes:
1064 *        SPRG1               SP (%r1)
1065 *        savearea  r28-r31
1066 *        28                  LR
1067 *        29                  CR
1068 *        30                  scratch
1069 *        31                  scratch
1070 *        1                   kernel stack
1071 *        SRR0/1              as at start of exception
1072 */
1073#define   INTR_SETUP(savearea,exc)                                              \
1074/* Have to enable translation to allow access of kernel stack: */     \
1075          GET_CPUINFO(%r31);                                                    \
1076          mfsrr0    %r30;                                                                 \
1077          streg     %r30,(savearea+CPUSAVE_SRR0)(%r31);     /* save SRR0 */     \
1078          mfsrr1    %r30;                                                                 \
1079          streg     %r30,(savearea+CPUSAVE_SRR1)(%r31);     /* save SRR1 */     \
1080          mfmsr     %r30;                                                                 \
1081          ori       %r30,%r30,(PSL_DR|PSL_IR);    /* turn on relocation */ \
1082          mtmsr     %r30;                         /* stack can be accessed now */         \
1083          isync;                                                                          \
1084          mfsprg1   %r31;                         /* get saved SP */            \
1085          stregu    %r31,-FRAMELEN(%r1);          /* save it in the callframe */          \
1086          streg     %r0,FRAME_R0(%r1);  /* save R0 in the trapframe */ \
1087          streg     %r31,FRAME_R1(%r1); /* save SP in the trapframe */ \
1088          streg     %r2,FRAME_R2(%r1);  /* save R2 in the trapframe */ \
1089          streg     %r28,FRAME_LR(%r1);                               \
1090          stint     %r29,FRAME_CR(%r1);                               \
1091          GET_CPUINFO(%r2);                                                     \
1092          ldreg     %r31,(savearea+CPUSAVE_R31)(%r2); /* get saved r31 */       \
1093          ldreg     %r30,(savearea+CPUSAVE_R30)(%r2); /* get saved r30 */       \
1094          ldreg     %r29,(savearea+CPUSAVE_R29)(%r2); /* get saved r29 */       \
1095          ldreg     %r28,(savearea+CPUSAVE_R28)(%r2); /* get saved r28 */       \
1096          streg     %r3,FRAME_R3(%r1);  /* save r3 */                 \
1097          streg     %r4,FRAME_R4(%r1);  /* save r4 */                 \
1098          streg     %r5,FRAME_R5(%r1);  /* save r5 */                 \
1099          streg     %r6,FRAME_R6(%r1);  /* save r6 */                 \
1100          streg     %r7,FRAME_R7(%r1);  /* save r7 */                 \
1101          streg     %r8,FRAME_R8(%r1);  /* save r8 */                 \
1102          streg     %r9,FRAME_R9(%r1);  /* save r9 */                 \
1103          streg     %r10,FRAME_R10(%r1);          /* save r10 */                \
1104          streg     %r11,FRAME_R11(%r1);          /* save r11 */                \
1105          streg     %r12,FRAME_R12(%r1);          /* save r12 */                \
1106          streg     %r13,FRAME_R13(%r1);          /* save r13 */                \
1107          ldreg     %r11,(savearea+CPUSAVE_SRR0)(%r2); /* get saved SRR0 */     \
1108          ldreg     %r12,(savearea+CPUSAVE_SRR1)(%r2); /* get saved SRR1 */     \
1109          ldptr     %r13,CI_CURLWP(%r2);          /* get curlwp */    \
1110          ldint     %r3,CI_IDEPTH(%r2);                                         \
1111          stint     %r3,FRAME_IDEPTH(%r1);                                                \
1112          mfxer     %r3;                                                                  \
1113          mfctr     %r4;                                                                  \
1114          li        %r5,exc;                                                    \
1115          stint     %r5,FRAME_EXC(%r1);                                         \
1116          stint     %r3,FRAME_XER(%r1);                                         \
1117          streg     %r4,FRAME_CTR(%r1);                                         \
1118          streg     %r11,FRAME_SRR0(%r1);                                                 \
1119          streg     %r12,FRAME_SRR1(%r1);                                                 \
1120          mfmsr     %r6;                                                                  \
1121          ori       %r6,%r6,PSL_RI;               /* turn on recovery interrupt */\
1122          mtmsr     %r6;                                                                  \
1123          SAVE_VRSAVE(%r1,%r6);                                                           \
1124          SAVE_MQ(%r1,%r7)
1125
1126/* LINTSTUB: Var: int extint_call[1]; */
1127/*
1128 * R1=sp, R28=LR, R29=CR, R30=scratch, R31=scratch
1129 */
1130          .globl    _C_LABEL(extint_call)
1131extintr:
1132          INTR_SETUP(CI_TEMPSAVE, EXC_EXI)
1133                                                  /* make trapframe available */
1134          addi      %r3,%r1,FRAME_TF    /* kern frame -> trap frame */
1135_C_LABEL(extint_call):
1136          bl        _C_LABEL(extint_call)         /* to be filled in later */
1137
1138intr_exit:
1139/* Disable interrupts (should already be disabled) but not MMU here: */
1140          mfmsr     %r3
1141          andi.     %r3,%r3,~(PSL_EE|PSL_ME|PSL_RI)@l
1142          mtmsr     %r3
1143          isync
1144
1145/* Returning to user mode? */
1146          ldreg     %r4,FRAME_SRR1(%r1)
1147          mtcr      %r4                           /* saved SRR1 */
1148          bf        MSR_PR,intrleave    /* branch if PSL_PR is false */
1149
1150          ldint     %r3,L_MD_ASTPENDING(%r13) /* Test AST pending */
1151          andi.     %r3,%r3,1
1152          beq       intrleave           /* common frame exit */
1153
1154/*
1155 * Since interrupts save their state in a std trapframe, all we need to do to
1156 * process the AST is finish filling the trapframe with the rest of the fixed
1157 * registers and let trap deal with it.
1158 */
1159          streg     %r14,FRAME_R14(%r1)
1160          streg     %r15,FRAME_R15(%r1)
1161          streg     %r16,FRAME_R16(%r1)
1162          streg     %r17,FRAME_R17(%r1)
1163          streg     %r18,FRAME_R18(%r1)
1164          streg     %r19,FRAME_R19(%r1)
1165          streg     %r20,FRAME_R20(%r1)
1166          streg     %r21,FRAME_R21(%r1)
1167          streg     %r22,FRAME_R22(%r1)
1168          streg     %r23,FRAME_R23(%r1)
1169          streg     %r24,FRAME_R24(%r1)
1170          streg     %r25,FRAME_R25(%r1)
1171          streg     %r26,FRAME_R26(%r1)
1172          streg     %r27,FRAME_R27(%r1)
1173          streg     %r28,FRAME_R28(%r1)
1174          streg     %r29,FRAME_R29(%r1)
1175          streg     %r30,FRAME_R30(%r1)
1176          streg     %r31,FRAME_R31(%r1)
1177
1178          /*
1179           * Tell trap we are doing an AST.
1180           */
1181          li        %r6,EXC_AST
1182          stint     %r6,FRAME_EXC(%r1)
1183
1184          mr        %r31, %r4           /* trapagain wants SRR1 in %r31 */
1185          b         trapagain
1186
1187/*
1188 * Decrementer interrupt second level handler
1189 */
1190decrintr:
1191          INTR_SETUP(CI_TEMPSAVE, EXC_DECR)
1192
1193          addi      %r3,%r1,FRAME_CF    /* intr frame -> clock frame */
1194          bl        _C_LABEL(decr_intr)
1195          b         intr_exit
1196
1197#ifdef DDB
1198/*
1199 * Deliberate entry to ddbtrap
1200 */
1201          .globl    _C_LABEL(ddb_trap)
1202_C_LABEL(ddb_trap):
1203          mtsprg1   %r1
1204          mfmsr     %r3
1205          mtsrr1    %r3
1206          andi.     %r3,%r3,~(PSL_EE|PSL_ME)@l
1207          mtmsr     %r3                           /* disable interrupts */
1208          isync
1209          ENABLE_64BIT_BRIDGE(%r3)
1210          GET_CPUINFO(%r3)
1211          streg     %r28,(CI_DDBSAVE+CPUSAVE_R28)(%r3)
1212          streg     %r29,(CI_DDBSAVE+CPUSAVE_R29)(%r3)
1213          streg     %r30,(CI_DDBSAVE+CPUSAVE_R30)(%r3)
1214          streg     %r31,(CI_DDBSAVE+CPUSAVE_R31)(%r3)
1215          mflr      %r28
1216          li        %r29,EXC_BPT
1217          mtlr      %r29
1218          mfcr      %r29
1219          mtsrr0    %r28
1220#endif /* DDB */
1221
1222#if defined(DDB) || defined(KGDB)
1223/*
1224 * Now the ddb trap catching code.
1225 */
1226ddbtrap:
1227          FRAME_SETUP(CI_DDBSAVE)
1228/* Call C trap code: */
1229          addi      %r3,%r1,FRAME_TF
1230          bl        _C_LABEL(ddb_trap_glue)
1231          or.       %r3,%r3,%r3
1232          beq       trapagain
1233          FRAME_RESTORE_CALLEE
1234          FRAME_LEAVE(CI_DDBSAVE)
1235          RFI
1236#endif /* DDB || KGDB */
1237
1238          .globl    _C_LABEL(trapend)
1239_C_LABEL(trapend):
1240
1241/*
1242 * All OEA have FPUs so include this too.  Some OEA have AltiVec so include
1243 * that too.
1244 */
1245#if !defined(PPC_MPC8XX)
1246#include <powerpc/powerpc/fpu_subr.S>
1247#include <powerpc/oea/altivec_subr.S>
1248#endif
1249