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