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