]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/mips/mips/exception.S
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / mips / mips / exception.S
1 /*      $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $        */
2 /*-
3  * Copyright (c) 1992, 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Digital Equipment Corporation and Ralph Campbell.
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  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Copyright (C) 1989 Digital Equipment Corporation.
34  * Permission to use, copy, modify, and distribute this software and
35  * its documentation for any purpose and without fee is hereby granted,
36  * provided that the above copyright notice appears in all copies.
37  * Digital Equipment Corporation makes no representations about the
38  * suitability of this software for any purpose.  It is provided "as is"
39  * without express or implied warranty.
40  *
41  * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
42  *      v 1.1 89/07/11 17:55:04 nelson Exp  SPRITE (DECWRL)
43  * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
44  *      v 9.2 90/01/29 18:00:39 shirriff Exp  SPRITE (DECWRL)
45  * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
46  *      v 1.1 89/07/10 14:27:41 nelson Exp  SPRITE (DECWRL)
47  *      from: @(#)locore.s      8.5 (Berkeley) 1/4/94
48  *      JNPR: exception.S,v 1.5 2007/01/08 04:58:37 katta
49  * $FreeBSD$
50  */
51
52 /*
53  *      Contains code that is the first executed at boot time plus
54  *      assembly language support routines.
55  */
56
57 #include "opt_cputype.h"
58 #include "opt_ddb.h"
59 #include <machine/asm.h>
60 #include <machine/cpu.h>
61 #include <machine/regnum.h>
62 #include <machine/cpuregs.h>
63 #include <machine/pte.h>
64
65 #include "opt_cputype.h"
66
67 #include "assym.s"
68
69         .set    noreorder               # Noreorder is default style!
70
71 /*
72  * Reasonable limit
73  */
74 #define INTRCNT_COUNT   128
75
76
77 /*
78  *----------------------------------------------------------------------------
79  *
80  * MipsTLBMiss --
81  *
82  *      Vector code for the TLB-miss exception vector 0x80000000.
83  *
84  * This code is copied to the TLB exception vector address to
85  * which the CPU jumps in response to an exception or a TLB miss.
86  * NOTE: This code must be position independent!!!
87  *
88  *
89  */
90 VECTOR(MipsTLBMiss, unknown)
91         .set push
92         .set noat
93         j       MipsDoTLBMiss
94         MFC0    k0, MIPS_COP_0_BAD_VADDR        # get the fault address
95         .set pop
96 VECTOR_END(MipsTLBMiss)
97
98 /*
99  *----------------------------------------------------------------------------
100  *
101  * MipsDoTLBMiss --
102  *
103  * This is the real TLB Miss Handler code.
104  * 'segbase' points to the base of the segment table for user processes.
105  *
106  * Don't check for invalid pte's here. We load them as well and
107  * let the processor trap to load the correct value after service.
108  *----------------------------------------------------------------------------
109  */
110         .set push
111         .set noat
112 MipsDoTLBMiss:
113         bltz            k0, 1f                          #02: k0<0 -> 1f (kernel fault)
114         PTR_SRL         k0, k0, SEGSHIFT - PTRSHIFT     #03: k0=seg offset (almost)
115
116         GET_CPU_PCPU(k1)
117         PTR_L           k1, PC_SEGBASE(k1)
118         beqz            k1, 2f                          #05: make sure segbase is not null
119         andi            k0, k0, PDEPTRMASK              #06: k0=seg offset
120         PTR_ADDU        k1, k0, k1                      #07: k1=seg entry address
121
122         PTR_L           k1, 0(k1)                       #08: k1=seg entry
123         MFC0            k0, MIPS_COP_0_BAD_VADDR        #09: k0=bad address (again)
124         beq             k1, zero, 2f                    #0a: ==0 -- no page table
125 #ifdef __mips_n64
126         PTR_SRL         k0, PDRSHIFT - PTRSHIFT         # k0=VPN
127         andi            k0, k0, PDEPTRMASK              # k0=pde offset
128         PTR_ADDU        k1, k0, k1                      # k1=pde entry address
129         PTR_L           k1, 0(k1)                       # k1=pde entry
130         MFC0            k0, MIPS_COP_0_BAD_VADDR        # k0=bad address (again)
131         beq             k1, zero, 2f                    # ==0 -- no page table
132 #endif
133         PTR_SRL         k0, PAGE_SHIFT - PTESHIFT       #0b: k0=VPN (aka va>>10)
134         andi            k0, k0, PTE2MASK                #0c: k0=page tab offset
135         PTR_ADDU        k1, k1, k0                      #0d: k1=pte address
136         PTE_L           k0, 0(k1)                       #0e: k0=lo0 pte
137         PTE_L           k1, PTESIZE(k1)                 #0f: k1=lo0 pte
138         CLEAR_PTE_SWBITS(k0)
139         PTE_MTC0        k0, MIPS_COP_0_TLB_LO0          #12: lo0 is loaded
140         COP0_SYNC
141         CLEAR_PTE_SWBITS(k1)
142         PTE_MTC0        k1, MIPS_COP_0_TLB_LO1          #15: lo1 is loaded
143         COP0_SYNC
144         tlbwr                                           #1a: write to tlb
145         HAZARD_DELAY
146         eret                                            #1f: retUrn from exception
147 1:      j               MipsTLBMissException            #20: kernel exception
148         nop                                             #21: branch delay slot
149 2:      j               SlowFault                       #22: no page table present
150         nop                                             #23: branch delay slot
151         .set pop
152
153 /*
154  * This code is copied to the general exception vector address to
155  * handle all execptions except RESET and TLBMiss.
156  * NOTE: This code must be position independent!!!
157  */
158 VECTOR(MipsException, unknown)
159 /*
160  * Find out what mode we came from and jump to the proper handler.
161  */
162         .set    noat
163         mfc0    k0, MIPS_COP_0_STATUS           # Get the status register
164         mfc0    k1, MIPS_COP_0_CAUSE            # Get the cause register value.
165         and     k0, k0, SR_KSU_USER             # test for user mode
166                                                 # sneaky but the bits are
167                                                 # with us........
168         sll     k0, k0, 3                       # shift user bit for cause index
169         and     k1, k1, MIPS3_CR_EXC_CODE       # Mask out the cause bits.
170         or      k1, k1, k0                      # change index to user table
171 #if defined(__mips_n64)
172         PTR_SLL k1, k1, 1                       # shift to get 8-byte offset
173 #endif
174 1:
175         PTR_LA  k0, _C_LABEL(machExceptionTable)  # get base of the jump table
176         PTR_ADDU k0, k0, k1                     # Get the address of the
177                                                 #  function entry.  Note that
178                                                 #  the cause is already
179                                                 #  shifted left by 2 bits so
180                                                 #  we dont have to shift.
181         PTR_L   k0, 0(k0)                       # Get the function address
182         nop
183         j       k0                              # Jump to the function.
184         nop
185         .set    at
186 VECTOR_END(MipsException)
187
188 /*
189  * We couldn't find a TLB entry.
190  * Find out what mode we came from and call the appropriate handler.
191  */
192 SlowFault:
193         .set    noat
194         mfc0    k0, MIPS_COP_0_STATUS
195         nop
196         and     k0, k0, SR_KSU_USER
197         bne     k0, zero, _C_LABEL(MipsUserGenException)
198         nop
199         .set    at
200 /*
201  * Fall though ...
202  */
203
204 /*----------------------------------------------------------------------------
205  *
206  * MipsKernGenException --
207  *
208  *      Handle an exception from kernel mode.
209  *
210  * Results:
211  *      None.
212  *
213  * Side effects:
214  *      None.
215  *
216  *----------------------------------------------------------------------------
217  */
218
219 #define SAVE_REG(reg, offs, base) \
220         REG_S   reg, CALLFRAME_SIZ + (SZREG * offs) (base)
221
222 #if defined(CPU_CNMIPS)
223 #define CLEAR_STATUS \
224         mfc0    a0, MIPS_COP_0_STATUS   ;\
225         li      a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \
226         or      a0, a0, a2              ; \
227         li      a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER)   ; \
228         and     a0, a0, a2              ; \
229         mtc0    a0, MIPS_COP_0_STATUS   ; \
230         ITLBNOPFIX
231 #elif defined(CPU_RMI) || defined(CPU_NLM)
232 #define CLEAR_STATUS \
233         mfc0    a0, MIPS_COP_0_STATUS   ;\
234         li      a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \
235         or      a0, a0, a2              ; \
236         li      a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER)   ; \
237         and     a0, a0, a2              ; \
238         mtc0    a0, MIPS_COP_0_STATUS   ; \
239         ITLBNOPFIX
240 #else
241 #define CLEAR_STATUS \
242         mfc0    a0, MIPS_COP_0_STATUS   ;\
243         li      a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER)   ; \
244         and     a0, a0, a2              ; \
245         mtc0    a0, MIPS_COP_0_STATUS   ; \
246         ITLBNOPFIX
247 #endif
248
249 /*
250  * Save CPU and CP0 register state.
251  *
252  * This is straightforward except for saving the exception program
253  * counter. The ddb backtrace code looks for the first instruction
254  * matching the form "sw ra, (off)sp" to figure out the address of the
255  * calling function. So we must make sure that we save the exception
256  * PC by staging it through 'ra' as opposed to any other register.
257  */
258 #define SAVE_CPU \
259         SAVE_REG(AT, AST, sp)           ;\
260         .set    at                      ; \
261         SAVE_REG(v0, V0, sp)            ;\
262         SAVE_REG(v1, V1, sp)            ;\
263         SAVE_REG(a0, A0, sp)            ;\
264         SAVE_REG(a1, A1, sp)            ;\
265         SAVE_REG(a2, A2, sp)            ;\
266         SAVE_REG(a3, A3, sp)            ;\
267         SAVE_REG(t0, T0, sp)            ;\
268         SAVE_REG(t1, T1, sp)            ;\
269         SAVE_REG(t2, T2, sp)            ;\
270         SAVE_REG(t3, T3, sp)            ;\
271         SAVE_REG(ta0, TA0, sp)          ;\
272         SAVE_REG(ta1, TA1, sp)          ;\
273         SAVE_REG(ta2, TA2, sp)          ;\
274         SAVE_REG(ta3, TA3, sp)          ;\
275         SAVE_REG(t8, T8, sp)            ;\
276         SAVE_REG(t9, T9, sp)            ;\
277         SAVE_REG(gp, GP, sp)            ;\
278         SAVE_REG(s0, S0, sp)            ;\
279         SAVE_REG(s1, S1, sp)            ;\
280         SAVE_REG(s2, S2, sp)            ;\
281         SAVE_REG(s3, S3, sp)            ;\
282         SAVE_REG(s4, S4, sp)            ;\
283         SAVE_REG(s5, S5, sp)            ;\
284         SAVE_REG(s6, S6, sp)            ;\
285         SAVE_REG(s7, S7, sp)            ;\
286         SAVE_REG(s8, S8, sp)            ;\
287         mflo    v0                      ;\
288         mfhi    v1                      ;\
289         mfc0    a0, MIPS_COP_0_STATUS   ;\
290         mfc0    a1, MIPS_COP_0_CAUSE    ;\
291         MFC0    a2, MIPS_COP_0_BAD_VADDR;\
292         MFC0    a3, MIPS_COP_0_EXC_PC   ;\
293         SAVE_REG(v0, MULLO, sp)         ;\
294         SAVE_REG(v1, MULHI, sp)         ;\
295         SAVE_REG(a0, SR, sp)            ;\
296         SAVE_REG(a1, CAUSE, sp)         ;\
297         SAVE_REG(a2, BADVADDR, sp)      ;\
298         move    t0, ra                  ;\
299         move    ra, a3                  ;\
300         SAVE_REG(ra, PC, sp)            ;\
301         move    ra, t0                  ;\
302         SAVE_REG(ra, RA, sp)            ;\
303         PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\
304         SAVE_REG(v0, SP, sp)            ;\
305         CLEAR_STATUS                    ;\
306         PTR_ADDU a0, sp, CALLFRAME_SIZ  ;\
307         ITLBNOPFIX
308
309 #define RESTORE_REG(reg, offs, base) \
310         REG_L   reg, CALLFRAME_SIZ + (SZREG * offs) (base)
311
312 #define RESTORE_CPU \
313         CLEAR_STATUS                    ;\
314         RESTORE_REG(k0, SR, sp)         ;\
315         RESTORE_REG(t0, MULLO, sp)      ;\
316         RESTORE_REG(t1, MULHI, sp)      ;\
317         mtlo    t0                      ;\
318         mthi    t1                      ;\
319         MTC0    v0, MIPS_COP_0_EXC_PC   ;\
320         .set noat                       ;\
321         RESTORE_REG(AT, AST, sp)        ;\
322         RESTORE_REG(v0, V0, sp)         ;\
323         RESTORE_REG(v1, V1, sp)         ;\
324         RESTORE_REG(a0, A0, sp)         ;\
325         RESTORE_REG(a1, A1, sp)         ;\
326         RESTORE_REG(a2, A2, sp)         ;\
327         RESTORE_REG(a3, A3, sp)         ;\
328         RESTORE_REG(t0, T0, sp)         ;\
329         RESTORE_REG(t1, T1, sp)         ;\
330         RESTORE_REG(t2, T2, sp)         ;\
331         RESTORE_REG(t3, T3, sp)         ;\
332         RESTORE_REG(ta0, TA0, sp)       ;\
333         RESTORE_REG(ta1, TA1, sp)       ;\
334         RESTORE_REG(ta2, TA2, sp)       ;\
335         RESTORE_REG(ta3, TA3, sp)       ;\
336         RESTORE_REG(t8, T8, sp)         ;\
337         RESTORE_REG(t9, T9, sp)         ;\
338         RESTORE_REG(s0, S0, sp)         ;\
339         RESTORE_REG(s1, S1, sp)         ;\
340         RESTORE_REG(s2, S2, sp)         ;\
341         RESTORE_REG(s3, S3, sp)         ;\
342         RESTORE_REG(s4, S4, sp)         ;\
343         RESTORE_REG(s5, S5, sp)         ;\
344         RESTORE_REG(s6, S6, sp)         ;\
345         RESTORE_REG(s7, S7, sp)         ;\
346         RESTORE_REG(s8, S8, sp)         ;\
347         RESTORE_REG(gp, GP, sp)         ;\
348         RESTORE_REG(ra, RA, sp)         ;\
349         PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\
350         mtc0    k0, MIPS_COP_0_STATUS
351
352
353 /*
354  * The kernel exception stack contains 18 saved general registers,
355  * the status register and the multiply lo and high registers.
356  * In addition, we set this up for linkage conventions.
357  */
358 #define KERN_REG_SIZE           (NUMSAVEREGS * SZREG)
359 #define KERN_EXC_FRAME_SIZE     (CALLFRAME_SIZ + KERN_REG_SIZE + 16)
360
361 NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
362         .set    noat
363         PTR_SUBU        sp, sp, KERN_EXC_FRAME_SIZE
364         .mask   0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
365 /*
366  *  Save CPU state, building 'frame'.
367  */
368         SAVE_CPU
369 /*
370  *  Call the exception handler. a0 points at the saved frame.
371  */
372         PTR_LA  gp, _C_LABEL(_gp)
373         PTR_LA  k0, _C_LABEL(trap)
374         jalr    k0
375         REG_S   a3, CALLFRAME_RA + KERN_REG_SIZE(sp)            # for debugging
376
377         /*
378          * Update interrupt mask in saved status register
379          * Some of interrupts could be disabled by
380          * intr filters if interrupts are enabled later
381          * in trap handler
382          */
383         mfc0    a0, MIPS_COP_0_STATUS
384         and     a0, a0, MIPS_SR_INT_MASK
385         RESTORE_REG(a1, SR, sp)
386         and     a1, a1, ~MIPS_SR_INT_MASK
387         or      a1, a1, a0
388         SAVE_REG(a1, SR, sp)
389         RESTORE_CPU                     # v0 contains the return address.
390         sync
391         eret
392         .set    at
393 END(MipsKernGenException)
394
395
396 #define SAVE_U_PCB_REG(reg, offs, base) \
397         REG_S   reg, U_PCB_REGS + (SZREG * offs) (base)
398
399 #define RESTORE_U_PCB_REG(reg, offs, base) \
400         REG_L   reg, U_PCB_REGS + (SZREG * offs) (base)
401
402 /*----------------------------------------------------------------------------
403  *
404  * MipsUserGenException --
405  *
406  *      Handle an exception from user mode.
407  *
408  * Results:
409  *      None.
410  *
411  * Side effects:
412  *      None.
413  *
414  *----------------------------------------------------------------------------
415  */
416 NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
417         .set    noat
418         .mask   0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
419 /*
420  * Save all of the registers except for the kernel temporaries in u.u_pcb.
421  */
422         GET_CPU_PCPU(k1)
423         PTR_L   k1, PC_CURPCB(k1)
424         SAVE_U_PCB_REG(AT, AST, k1)
425         .set    at
426         SAVE_U_PCB_REG(v0, V0, k1)
427         SAVE_U_PCB_REG(v1, V1, k1)
428         SAVE_U_PCB_REG(a0, A0, k1)
429         mflo    v0
430         SAVE_U_PCB_REG(a1, A1, k1)
431         SAVE_U_PCB_REG(a2, A2, k1)
432         SAVE_U_PCB_REG(a3, A3, k1)
433         SAVE_U_PCB_REG(t0, T0, k1)
434         mfhi    v1
435         SAVE_U_PCB_REG(t1, T1, k1)
436         SAVE_U_PCB_REG(t2, T2, k1)
437         SAVE_U_PCB_REG(t3, T3, k1)
438         SAVE_U_PCB_REG(ta0, TA0, k1)
439         mfc0    a0, MIPS_COP_0_STATUS           # First arg is the status reg.
440         SAVE_U_PCB_REG(ta1, TA1, k1)
441         SAVE_U_PCB_REG(ta2, TA2, k1)
442         SAVE_U_PCB_REG(ta3, TA3, k1)
443         SAVE_U_PCB_REG(s0, S0, k1)
444         mfc0    a1, MIPS_COP_0_CAUSE            # Second arg is the cause reg.
445         SAVE_U_PCB_REG(s1, S1, k1)
446         SAVE_U_PCB_REG(s2, S2, k1)
447         SAVE_U_PCB_REG(s3, S3, k1)
448         SAVE_U_PCB_REG(s4, S4, k1)
449         MFC0    a2, MIPS_COP_0_BAD_VADDR        # Third arg is the fault addr
450         SAVE_U_PCB_REG(s5, S5, k1)
451         SAVE_U_PCB_REG(s6, S6, k1)
452         SAVE_U_PCB_REG(s7, S7, k1)
453         SAVE_U_PCB_REG(t8, T8, k1)
454         MFC0    a3, MIPS_COP_0_EXC_PC           # Fourth arg is the pc.
455         SAVE_U_PCB_REG(t9, T9, k1)
456         SAVE_U_PCB_REG(gp, GP, k1)
457         SAVE_U_PCB_REG(sp, SP, k1)
458         SAVE_U_PCB_REG(s8, S8, k1)
459         PTR_SUBU        sp, k1, CALLFRAME_SIZ    # switch to kernel SP
460         SAVE_U_PCB_REG(ra, RA, k1)
461         SAVE_U_PCB_REG(v0, MULLO, k1)
462         SAVE_U_PCB_REG(v1, MULHI, k1)
463         SAVE_U_PCB_REG(a0, SR, k1)
464         SAVE_U_PCB_REG(a1, CAUSE, k1)
465         SAVE_U_PCB_REG(a2, BADVADDR, k1)
466         SAVE_U_PCB_REG(a3, PC, k1)
467         REG_S   a3, CALLFRAME_RA(sp)    # for debugging
468         PTR_LA  gp, _C_LABEL(_gp)       # switch to kernel GP
469 # Turn off fpu and enter kernel mode
470         and     t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS3_SR_KSU_MASK | MIPS_SR_INT_IE)
471 #if defined(CPU_CNMIPS)
472         or      t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
473 #elif defined(CPU_RMI)  || defined(CPU_NLM)
474         or      t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
475 #endif  
476         mtc0    t0, MIPS_COP_0_STATUS
477         PTR_ADDU a0, k1, U_PCB_REGS
478         ITLBNOPFIX
479
480 /*
481  * Call the exception handler.
482  */
483         PTR_LA  k0, _C_LABEL(trap)
484         jalr    k0
485         nop
486
487 /*
488  * Restore user registers and return.
489  * First disable interrupts and set exeption level.
490  */
491         DO_AST
492
493         CLEAR_STATUS
494
495 /*
496  * The use of k1 for storing the PCB pointer must be done only
497  * after interrupts are disabled.  Otherwise it will get overwritten
498  * by the interrupt code.
499  */
500         GET_CPU_PCPU(k1)
501         PTR_L   k1, PC_CURPCB(k1)
502
503         /*
504          * Update interrupt mask in saved status register
505          * Some of interrupts could be enabled by ithread
506          * scheduled by ast()
507          */
508         mfc0    a0, MIPS_COP_0_STATUS
509         and     a0, a0, MIPS_SR_INT_MASK
510         RESTORE_U_PCB_REG(a1, SR, k1)
511         and     a1, a1, ~MIPS_SR_INT_MASK
512         or      a1, a1, a0
513         SAVE_U_PCB_REG(a1, SR, k1)
514
515         RESTORE_U_PCB_REG(t0, MULLO, k1)
516         RESTORE_U_PCB_REG(t1, MULHI, k1)
517         mtlo    t0
518         mthi    t1
519         RESTORE_U_PCB_REG(a0, PC, k1)
520         RESTORE_U_PCB_REG(v0, V0, k1)
521         MTC0    a0, MIPS_COP_0_EXC_PC   # set return address
522         RESTORE_U_PCB_REG(v1, V1, k1)
523         RESTORE_U_PCB_REG(a0, A0, k1)
524         RESTORE_U_PCB_REG(a1, A1, k1)
525         RESTORE_U_PCB_REG(a2, A2, k1)
526         RESTORE_U_PCB_REG(a3, A3, k1)
527         RESTORE_U_PCB_REG(t0, T0, k1)
528         RESTORE_U_PCB_REG(t1, T1, k1)
529         RESTORE_U_PCB_REG(t2, T2, k1)
530         RESTORE_U_PCB_REG(t3, T3, k1)
531         RESTORE_U_PCB_REG(ta0, TA0, k1)
532         RESTORE_U_PCB_REG(ta1, TA1, k1)
533         RESTORE_U_PCB_REG(ta2, TA2, k1)
534         RESTORE_U_PCB_REG(ta3, TA3, k1)
535         RESTORE_U_PCB_REG(s0, S0, k1)
536         RESTORE_U_PCB_REG(s1, S1, k1)
537         RESTORE_U_PCB_REG(s2, S2, k1)
538         RESTORE_U_PCB_REG(s3, S3, k1)
539         RESTORE_U_PCB_REG(s4, S4, k1)
540         RESTORE_U_PCB_REG(s5, S5, k1)
541         RESTORE_U_PCB_REG(s6, S6, k1)
542         RESTORE_U_PCB_REG(s7, S7, k1)
543         RESTORE_U_PCB_REG(t8, T8, k1)
544         RESTORE_U_PCB_REG(t9, T9, k1)
545         RESTORE_U_PCB_REG(gp, GP, k1)
546         RESTORE_U_PCB_REG(sp, SP, k1)
547         RESTORE_U_PCB_REG(k0, SR, k1)
548         RESTORE_U_PCB_REG(s8, S8, k1)
549         RESTORE_U_PCB_REG(ra, RA, k1)
550         .set noat
551         RESTORE_U_PCB_REG(AT, AST, k1)
552
553         mtc0    k0, MIPS_COP_0_STATUS   # still exception level
554         ITLBNOPFIX
555         sync
556         eret
557         .set    at
558 END(MipsUserGenException)
559
560 /*----------------------------------------------------------------------------
561  *
562  * MipsKernIntr --
563  *
564  *      Handle an interrupt from kernel mode.
565  *      Interrupts use the standard kernel stack.
566  *      switch_exit sets up a kernel stack after exit so interrupts won't fail.
567  *
568  * Results:
569  *      None.
570  *
571  * Side effects:
572  *      None.
573  *
574  *----------------------------------------------------------------------------
575  */
576
577 NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
578         .set    noat
579         PTR_SUBU        sp, sp, KERN_EXC_FRAME_SIZE
580         .mask   0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
581 /*
582  *  Save CPU state, building 'frame'.
583  */
584         SAVE_CPU
585 /*
586  *  Call the interrupt handler. a0 points at the saved frame.
587  */
588         PTR_LA  gp, _C_LABEL(_gp)
589         PTR_LA  k0, _C_LABEL(cpu_intr)
590         jalr    k0
591         REG_S   a3, CALLFRAME_RA + KERN_REG_SIZE(sp)            # for debugging
592
593         /*
594          * Update interrupt mask in saved status register
595          * Some of interrupts could be disabled by
596          * intr filters if interrupts are enabled later
597          * in trap handler
598          */
599         mfc0    a0, MIPS_COP_0_STATUS
600         and     a0, a0, MIPS_SR_INT_MASK
601         RESTORE_REG(a1, SR, sp)
602         and     a1, a1, ~MIPS_SR_INT_MASK
603         or      a1, a1, a0
604         SAVE_REG(a1, SR, sp)
605         REG_L   v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
606         RESTORE_CPU                     # v0 contains the return address.
607         sync
608         eret
609         .set    at
610 END(MipsKernIntr)
611
612 /*----------------------------------------------------------------------------
613  *
614  * MipsUserIntr --
615  *
616  *      Handle an interrupt from user mode.
617  *      Note: we save minimal state in the u.u_pcb struct and use the standard
618  *      kernel stack since there has to be a u page if we came from user mode.
619  *      If there is a pending software interrupt, then save the remaining state
620  *      and call softintr(). This is all because if we call switch() inside
621  *      interrupt(), not all the user registers have been saved in u.u_pcb.
622  *
623  * Results:
624  *      None.
625  *
626  * Side effects:
627  *      None.
628  *
629  *----------------------------------------------------------------------------
630  */
631 NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra)
632         .set    noat
633         .mask   0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
634 /*
635  * Save the relevant user registers into the u.u_pcb struct.
636  * We don't need to save s0 - s8 because the compiler does it for us.
637  */
638         GET_CPU_PCPU(k1)
639         PTR_L   k1, PC_CURPCB(k1)
640         SAVE_U_PCB_REG(AT, AST, k1)
641         .set    at
642         SAVE_U_PCB_REG(v0, V0, k1)
643         SAVE_U_PCB_REG(v1, V1, k1)
644         SAVE_U_PCB_REG(a0, A0, k1)
645         SAVE_U_PCB_REG(a1, A1, k1)
646         SAVE_U_PCB_REG(a2, A2, k1)
647         SAVE_U_PCB_REG(a3, A3, k1)
648         SAVE_U_PCB_REG(t0, T0, k1)
649         SAVE_U_PCB_REG(t1, T1, k1)
650         SAVE_U_PCB_REG(t2, T2, k1)
651         SAVE_U_PCB_REG(t3, T3, k1)
652         SAVE_U_PCB_REG(ta0, TA0, k1)
653         SAVE_U_PCB_REG(ta1, TA1, k1)
654         SAVE_U_PCB_REG(ta2, TA2, k1)
655         SAVE_U_PCB_REG(ta3, TA3, k1)
656         SAVE_U_PCB_REG(t8, T8, k1)
657         SAVE_U_PCB_REG(t9, T9, k1)
658         SAVE_U_PCB_REG(gp, GP, k1)
659         SAVE_U_PCB_REG(sp, SP, k1)
660         SAVE_U_PCB_REG(ra, RA, k1)
661 /*
662  *  save remaining user state in u.u_pcb.
663  */
664         SAVE_U_PCB_REG(s0, S0, k1)
665         SAVE_U_PCB_REG(s1, S1, k1)
666         SAVE_U_PCB_REG(s2, S2, k1)
667         SAVE_U_PCB_REG(s3, S3, k1)
668         SAVE_U_PCB_REG(s4, S4, k1)
669         SAVE_U_PCB_REG(s5, S5, k1)
670         SAVE_U_PCB_REG(s6, S6, k1)
671         SAVE_U_PCB_REG(s7, S7, k1)
672         SAVE_U_PCB_REG(s8, S8, k1)
673
674         mflo    v0                      # get lo/hi late to avoid stall
675         mfhi    v1
676         mfc0    a0, MIPS_COP_0_STATUS
677         mfc0    a1, MIPS_COP_0_CAUSE
678         MFC0    a3, MIPS_COP_0_EXC_PC
679         SAVE_U_PCB_REG(v0, MULLO, k1)
680         SAVE_U_PCB_REG(v1, MULHI, k1)
681         SAVE_U_PCB_REG(a0, SR, k1)
682         SAVE_U_PCB_REG(a1, CAUSE, k1)
683         SAVE_U_PCB_REG(a3, PC, k1)      # PC in a3, note used later!
684         PTR_SUBU        sp, k1, CALLFRAME_SIZ  # switch to kernel SP
685         PTR_LA  gp, _C_LABEL(_gp)       # switch to kernel GP
686
687 # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
688         and     t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS3_SR_KSU_MASK)
689 #ifdef CPU_CNMIPS
690         or      t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
691 #elif defined(CPU_RMI)  || defined(CPU_NLM)
692         or      t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
693 #endif  
694         mtc0    t0, MIPS_COP_0_STATUS
695         ITLBNOPFIX
696         PTR_ADDU a0, k1, U_PCB_REGS
697 /*
698  * Call the interrupt handler.
699  */
700         PTR_LA  k0, _C_LABEL(cpu_intr)
701         jalr    k0
702         REG_S   a3, CALLFRAME_RA(sp)    # for debugging
703
704 /*
705  * Enable interrupts before doing ast().
706  *
707  * On SMP kernels the AST processing might trigger IPI to other processors.
708  * If that processor is also doing AST processing with interrupts disabled
709  * then we may deadlock.
710  */
711         mfc0    a0, MIPS_COP_0_STATUS
712         or      a0, a0, MIPS_SR_INT_IE
713         mtc0    a0, MIPS_COP_0_STATUS
714         ITLBNOPFIX
715
716 /*
717  * DO_AST enabled interrupts
718  */
719         DO_AST
720         
721 /*
722  * Restore user registers and return. 
723  */
724         CLEAR_STATUS
725
726         GET_CPU_PCPU(k1)
727         PTR_L   k1, PC_CURPCB(k1)
728
729         /*
730          * Update interrupt mask in saved status register
731          * Some of interrupts could be disabled by
732          * intr filters
733          */
734         mfc0    a0, MIPS_COP_0_STATUS
735         and     a0, a0, MIPS_SR_INT_MASK
736         RESTORE_U_PCB_REG(a1, SR, k1)
737         and     a1, a1, ~MIPS_SR_INT_MASK
738         or      a1, a1, a0
739         SAVE_U_PCB_REG(a1, SR, k1)
740
741         RESTORE_U_PCB_REG(s0, S0, k1)
742         RESTORE_U_PCB_REG(s1, S1, k1)
743         RESTORE_U_PCB_REG(s2, S2, k1)
744         RESTORE_U_PCB_REG(s3, S3, k1)
745         RESTORE_U_PCB_REG(s4, S4, k1)
746         RESTORE_U_PCB_REG(s5, S5, k1)
747         RESTORE_U_PCB_REG(s6, S6, k1)
748         RESTORE_U_PCB_REG(s7, S7, k1)
749         RESTORE_U_PCB_REG(s8, S8, k1)
750         RESTORE_U_PCB_REG(t0, MULLO, k1)
751         RESTORE_U_PCB_REG(t1, MULHI, k1)
752         RESTORE_U_PCB_REG(t2, PC, k1)
753         mtlo    t0
754         mthi    t1
755         MTC0    t2, MIPS_COP_0_EXC_PC   # set return address
756         RESTORE_U_PCB_REG(v0, V0, k1)
757         RESTORE_U_PCB_REG(v1, V1, k1)
758         RESTORE_U_PCB_REG(a0, A0, k1)
759         RESTORE_U_PCB_REG(a1, A1, k1)
760         RESTORE_U_PCB_REG(a2, A2, k1)
761         RESTORE_U_PCB_REG(a3, A3, k1)
762         RESTORE_U_PCB_REG(t0, T0, k1)
763         RESTORE_U_PCB_REG(t1, T1, k1)
764         RESTORE_U_PCB_REG(t2, T2, k1)
765         RESTORE_U_PCB_REG(t3, T3, k1)
766         RESTORE_U_PCB_REG(ta0, TA0, k1)
767         RESTORE_U_PCB_REG(ta1, TA1, k1)
768         RESTORE_U_PCB_REG(ta2, TA2, k1)
769         RESTORE_U_PCB_REG(ta3, TA3, k1)
770         RESTORE_U_PCB_REG(t8, T8, k1)
771         RESTORE_U_PCB_REG(t9, T9, k1)
772         RESTORE_U_PCB_REG(gp, GP, k1)
773         RESTORE_U_PCB_REG(k0, SR, k1)
774         RESTORE_U_PCB_REG(sp, SP, k1)
775         RESTORE_U_PCB_REG(ra, RA, k1)
776         .set    noat
777         RESTORE_U_PCB_REG(AT, AST, k1)
778
779         mtc0    k0, MIPS_COP_0_STATUS   # SR with EXL set. 
780         ITLBNOPFIX
781         sync
782         eret
783         .set    at
784 END(MipsUserIntr)
785
786 NLEAF(MipsTLBInvalidException)
787         .set push
788         .set noat
789         .set noreorder
790
791         MFC0            k0, MIPS_COP_0_BAD_VADDR
792         PTR_LI          k1, VM_MAXUSER_ADDRESS
793         sltu            k1, k0, k1
794         bnez            k1, 1f
795         nop
796
797         /* Kernel address.  */
798         lui             k1, %hi(kernel_segmap)          # k1=hi of segbase
799         b               2f
800         PTR_L           k1, %lo(kernel_segmap)(k1)      # k1=segment tab base
801
802 1:      /* User address.  */
803         GET_CPU_PCPU(k1)
804         PTR_L           k1, PC_SEGBASE(k1)
805
806 2:      /* Validate page directory pointer.  */
807         beqz            k1, 3f
808         nop
809
810         PTR_SRL         k0, SEGSHIFT - PTRSHIFT         # k0=seg offset (almost)
811         beq             k1, zero, MipsKernGenException  # ==0 -- no seg tab
812         andi            k0, k0, PDEPTRMASK              #06: k0=seg offset
813         PTR_ADDU        k1, k0, k1                      # k1=seg entry address
814         PTR_L           k1, 0(k1)                       # k1=seg entry
815
816         /* Validate page table pointer.  */
817         beqz            k1, 3f
818         nop
819
820 #ifdef __mips_n64
821         MFC0            k0, MIPS_COP_0_BAD_VADDR
822         PTR_SRL         k0, PDRSHIFT - PTRSHIFT         # k0=pde offset (almost)
823         beq             k1, zero, MipsKernGenException  # ==0 -- no pde tab
824         andi            k0, k0, PDEPTRMASK              # k0=pde offset
825         PTR_ADDU        k1, k0, k1                      # k1=pde entry address
826         PTR_L           k1, 0(k1)                       # k1=pde entry
827
828         /* Validate pde table pointer.  */
829         beqz            k1, 3f
830         nop
831 #endif
832         MFC0            k0, MIPS_COP_0_BAD_VADDR        # k0=bad address (again)
833         PTR_SRL         k0, PAGE_SHIFT - PTESHIFT       # k0=VPN
834         andi            k0, k0, PTEMASK                 # k0=page tab offset
835         PTR_ADDU        k1, k1, k0                      # k1=pte address
836         PTE_L           k0, 0(k1)                       # k0=this PTE
837
838         /* Validate page table entry.  */
839         andi            k0, PTE_V
840         beqz            k0, 3f
841         nop
842
843         /* Check whether this is an even or odd entry.  */
844         andi            k0, k1, PTESIZE
845         bnez            k0, odd_page
846         nop
847
848         PTE_L           k0, 0(k1)
849         PTE_L           k1, PTESIZE(k1)
850         CLEAR_PTE_SWBITS(k0)
851         PTE_MTC0        k0, MIPS_COP_0_TLB_LO0
852         COP0_SYNC
853         CLEAR_PTE_SWBITS(k1)
854         PTE_MTC0        k1, MIPS_COP_0_TLB_LO1
855         COP0_SYNC
856
857         b               tlb_insert_entry
858         nop
859
860 odd_page:
861         PTE_L           k0, -PTESIZE(k1)
862         PTE_L           k1, 0(k1)
863         CLEAR_PTE_SWBITS(k0)
864         PTE_MTC0        k0, MIPS_COP_0_TLB_LO0
865         COP0_SYNC
866         CLEAR_PTE_SWBITS(k1)
867         PTE_MTC0        k1, MIPS_COP_0_TLB_LO1
868         COP0_SYNC
869
870 tlb_insert_entry:
871         tlbp
872         HAZARD_DELAY
873         mfc0            k0, MIPS_COP_0_TLB_INDEX
874         bltz            k0, tlb_insert_random
875         nop
876         tlbwi
877         eret
878         ssnop
879
880 tlb_insert_random:
881         tlbwr
882         eret
883         ssnop
884
885 3:
886         /*
887          * Branch to the comprehensive exception processing.
888          */
889         mfc0    k1, MIPS_COP_0_STATUS
890         andi    k1, k1, SR_KSU_USER
891         bnez    k1, _C_LABEL(MipsUserGenException)
892         nop
893
894         /*
895          * Check for kernel stack overflow.
896          */
897         GET_CPU_PCPU(k1)
898         PTR_L   k0, PC_CURTHREAD(k1)
899         PTR_L   k0, TD_KSTACK(k0)
900         sltu    k0, k0, sp
901         bnez    k0, _C_LABEL(MipsKernGenException)
902         nop
903
904         /*
905          * Kernel stack overflow.
906          *
907          * Move to a valid stack before we call panic. We use the boot stack
908          * for this purpose.
909          */
910         GET_CPU_PCPU(k1)
911         lw      k1, PC_CPUID(k1)
912         sll     k1, k1, PAGE_SHIFT + 1
913
914         PTR_LA  k0, _C_LABEL(pcpu_space)
915         PTR_ADDU        k0, PAGE_SIZE * 2
916         PTR_ADDU        k0, k0, k1
917
918         /*
919          * Stash the original value of 'sp' so we can update trapframe later.
920          * We assume that SAVE_CPU does not trash 'k1'.
921          */
922         move    k1, sp
923
924         move    sp, k0
925         PTR_SUBU        sp, sp, KERN_EXC_FRAME_SIZE
926
927         move    k0, ra
928         move    ra, zero
929         REG_S   ra, CALLFRAME_RA(sp)    /* stop the ddb backtrace right here */
930         REG_S   zero, CALLFRAME_SP(sp)
931         move    ra, k0
932
933         SAVE_CPU
934
935         /*
936          * Now restore the value of 'sp' at the time of the tlb exception in
937          * the trapframe.
938          */
939         SAVE_REG(k1, SP, sp)
940
941         /*
942          * Squelch any more overflow checks by setting the stack base to 0.
943          */
944         GET_CPU_PCPU(k1)
945         PTR_L   k0, PC_CURTHREAD(k1)
946         PTR_S   zero, TD_KSTACK(k0)
947
948         move    a1, a0
949         PANIC("kernel stack overflow - trapframe at %p")
950
951         /*
952          * This nop is necessary so that the 'ra' remains within the bounds
953          * of this handler. Otherwise the ddb backtrace code will think that
954          * the panic() was called from MipsTLBMissException.
955          */
956         nop
957
958         .set pop
959 END(MipsTLBInvalidException)
960
961 /*----------------------------------------------------------------------------
962  *
963  * MipsTLBMissException --
964  *
965  *      Handle a TLB miss exception from kernel mode in kernel space.
966  *      The BaddVAddr, Context, and EntryHi registers contain the failed
967  *      virtual address.
968  *
969  * Results:
970  *      None.
971  *
972  * Side effects:
973  *      None.
974  *
975  *----------------------------------------------------------------------------
976  */
977 NLEAF(MipsTLBMissException)
978         .set    noat
979         MFC0            k0, MIPS_COP_0_BAD_VADDR        # k0=bad address
980         PTR_LI          k1, VM_MAX_KERNEL_ADDRESS       # check fault address against
981         sltu            k1, k1, k0                      # upper bound of kernel_segmap
982         bnez            k1, MipsKernGenException        # out of bound
983         lui             k1, %hi(kernel_segmap)          # k1=hi of segbase
984         PTR_SRL         k0, SEGSHIFT - PTRSHIFT         # k0=seg offset (almost)
985         PTR_L           k1, %lo(kernel_segmap)(k1)      # k1=segment tab base
986         beq             k1, zero, MipsKernGenException  # ==0 -- no seg tab
987         andi            k0, k0, PDEPTRMASK              #06: k0=seg offset
988         PTR_ADDU        k1, k0, k1                      # k1=seg entry address
989         PTR_L           k1, 0(k1)                       # k1=seg entry
990         MFC0            k0, MIPS_COP_0_BAD_VADDR        # k0=bad address (again)
991         beq             k1, zero, MipsKernGenException  # ==0 -- no page table
992 #ifdef __mips_n64
993         PTR_SRL         k0, PDRSHIFT - PTRSHIFT         # k0=VPN
994         andi            k0, k0, PDEPTRMASK              # k0=pde offset
995         PTR_ADDU        k1, k0, k1                      # k1=pde entry address
996         PTR_L           k1, 0(k1)                       # k1=pde entry
997         MFC0            k0, MIPS_COP_0_BAD_VADDR        # k0=bad address (again)
998         beq             k1, zero, MipsKernGenException  # ==0 -- no page table
999 #endif
1000         PTR_SRL         k0, PAGE_SHIFT - PTESHIFT       # k0=VPN
1001         andi            k0, k0, PTE2MASK                # k0=page tab offset
1002         PTR_ADDU        k1, k1, k0                      # k1=pte address
1003         PTE_L           k0, 0(k1)                       # k0=lo0 pte
1004         PTE_L           k1, PTESIZE(k1)                 # k1=lo1 pte
1005         CLEAR_PTE_SWBITS(k0)
1006         PTE_MTC0        k0, MIPS_COP_0_TLB_LO0          # lo0 is loaded
1007         COP0_SYNC
1008         CLEAR_PTE_SWBITS(k1)
1009         PTE_MTC0        k1, MIPS_COP_0_TLB_LO1          # lo1 is loaded
1010         COP0_SYNC
1011         tlbwr                                   # write to tlb
1012         HAZARD_DELAY
1013         eret                                    # return from exception
1014         .set    at
1015 END(MipsTLBMissException)
1016
1017 /*----------------------------------------------------------------------------
1018  *
1019  * MipsFPTrap --
1020  *
1021  *      Handle a floating point Trap.
1022  *
1023  *      MipsFPTrap(statusReg, causeReg, pc)
1024  *              unsigned statusReg;
1025  *              unsigned causeReg;
1026  *              unsigned pc;
1027  *
1028  * Results:
1029  *      None.
1030  *
1031  * Side effects:
1032  *      None.
1033  *
1034  *----------------------------------------------------------------------------
1035  */
1036 NON_LEAF(MipsFPTrap, CALLFRAME_SIZ, ra)
1037         PTR_SUBU        sp, sp, CALLFRAME_SIZ
1038         mfc0    t0, MIPS_COP_0_STATUS
1039         REG_S   ra, CALLFRAME_RA(sp)
1040         .mask   0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
1041
1042         or      t1, t0, MIPS_SR_COP_1_BIT
1043         mtc0    t1, MIPS_COP_0_STATUS
1044         ITLBNOPFIX
1045         cfc1    t1, MIPS_FPU_CSR                # stall til FP done
1046         cfc1    t1, MIPS_FPU_CSR                # now get status
1047         nop
1048         sll     t2, t1, (31 - 17)               # unimplemented operation?
1049         bgez    t2, 3f                          # no, normal trap
1050         nop
1051 /*
1052  * We got an unimplemented operation trap so
1053  * fetch the instruction, compute the next PC and emulate the instruction.
1054  */
1055         bgez    a1, 1f                          # Check the branch delay bit.
1056         nop
1057 /*
1058  * The instruction is in the branch delay slot so the branch will have to
1059  * be emulated to get the resulting PC.
1060  */
1061         PTR_S   a2, CALLFRAME_SIZ + 8(sp)
1062         GET_CPU_PCPU(a0)
1063 #mips64 unsafe?
1064         PTR_L   a0, PC_CURPCB(a0)
1065         PTR_ADDU a0, a0, U_PCB_REGS             # first arg is ptr to CPU registers
1066         move    a1, a2                          # second arg is instruction PC
1067         move    a2, t1                          # third arg is floating point CSR
1068         PTR_LA  t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch
1069         jalr    t3                              # compute PC after branch
1070         move    a3, zero                        # fourth arg is FALSE
1071 /*
1072  * Now load the floating-point instruction in the branch delay slot
1073  * to be emulated.
1074  */
1075         PTR_L   a2, CALLFRAME_SIZ + 8(sp)       # restore EXC pc
1076         b       2f
1077         lw      a0, 4(a2)                       # a0 = coproc instruction
1078 /*
1079  * This is not in the branch delay slot so calculate the resulting
1080  * PC (epc + 4) into v0 and continue to MipsEmulateFP().
1081  */
1082 1:
1083         lw      a0, 0(a2)                       # a0 = coproc instruction
1084 #xxx mips64 unsafe?
1085         PTR_ADDU        v0, a2, 4                       # v0 = next pc
1086 2:
1087         GET_CPU_PCPU(t2)
1088         PTR_L   t2, PC_CURPCB(t2)
1089         SAVE_U_PCB_REG(v0, PC, t2)              # save new pc
1090 /*
1091  * Check to see if the instruction to be emulated is a floating-point
1092  * instruction.
1093  */
1094         srl     a3, a0, MIPS_OPCODE_SHIFT
1095         beq     a3, MIPS_OPCODE_C1, 4f          # this should never fail
1096         nop
1097 /*
1098  * Send a floating point exception signal to the current process.
1099  */
1100 3:
1101         GET_CPU_PCPU(a0)
1102         PTR_L   a0, PC_CURTHREAD(a0)            # get current thread
1103         cfc1    a2, MIPS_FPU_CSR                # code = FP execptions
1104         ctc1    zero, MIPS_FPU_CSR              # Clear exceptions
1105         PTR_LA  t3, _C_LABEL(trapsignal)
1106         jalr    t3
1107         li      a1, SIGFPE
1108         b       FPReturn
1109         nop
1110
1111 /*
1112  * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
1113  */
1114 4:
1115         PTR_LA  t3, _C_LABEL(MipsEmulateFP)
1116         jalr    t3
1117         nop
1118
1119 /*
1120  * Turn off the floating point coprocessor and return.
1121  */
1122 FPReturn:
1123         mfc0    t0, MIPS_COP_0_STATUS
1124         PTR_L   ra, CALLFRAME_RA(sp)
1125         and     t0, t0, ~MIPS_SR_COP_1_BIT
1126         mtc0    t0, MIPS_COP_0_STATUS
1127         ITLBNOPFIX
1128         j       ra
1129         PTR_ADDU sp, sp, CALLFRAME_SIZ
1130 END(MipsFPTrap)
1131
1132 /*
1133  * Interrupt counters for vmstat.
1134  */
1135         .data
1136         .globl intrcnt
1137         .globl sintrcnt
1138         .globl intrnames
1139         .globl sintrnames
1140 intrnames:
1141         .space  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1142 sintrnames:
1143 #ifdef __mips_n64
1144         .quad  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1145 #else
1146         .int  INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
1147 #endif
1148
1149         .align  4
1150 intrcnt:
1151         .space  INTRCNT_COUNT * 4 * 2
1152 sintrcnt:
1153 #ifdef __mips_n64
1154         .quad  INTRCNT_COUNT * 4 * 2
1155 #else
1156         .int  INTRCNT_COUNT * 4 * 2
1157 #endif
1158
1159
1160 /*
1161  * Vector to real handler in KSEG1.
1162  */
1163         .text
1164 VECTOR(MipsCache, unknown)
1165         PTR_LA  k0, _C_LABEL(MipsCacheException)
1166         li      k1, MIPS_KSEG0_PHYS_MASK
1167         and     k0, k1
1168         PTR_LI  k1, MIPS_KSEG1_START
1169         or      k0, k1
1170         j       k0
1171         nop
1172 VECTOR_END(MipsCache)
1173
1174         .set    at
1175
1176
1177 /*
1178  * Panic on cache errors.  A lot more could be done to recover
1179  * from some types of errors but it is tricky.
1180  */
1181 NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
1182         .set    noat
1183         .mask   0x80000000, -4
1184         PTR_LA  k0, _C_LABEL(panic)             # return to panic
1185         PTR_LA  a0, 9f                          # panicstr
1186         MFC0    a1, MIPS_COP_0_ERROR_PC
1187         mfc0    a2, MIPS_COP_0_CACHE_ERR        # 3rd arg cache error
1188
1189         MTC0    k0, MIPS_COP_0_ERROR_PC         # set return address
1190
1191         mfc0    k0, MIPS_COP_0_STATUS           # restore status
1192         li      k1, MIPS_SR_DIAG_PE             # ignore further errors
1193         or      k0, k1
1194         mtc0    k0, MIPS_COP_0_STATUS           # restore status
1195         COP0_SYNC
1196
1197         eret
1198
1199         MSG("cache error @ EPC 0x%x CachErr 0x%x");
1200         .set    at
1201 END(MipsCacheException)