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