/src/freebsd/sys/mips/mips/exception.S
Assembly | 1243 lines | 1226 code | 17 blank | 0 comment | 11 complexity | 42def7474b53285a2ee3da7608b3f05e MD5 | raw file
Possible License(s): CC0-1.0, MIT, LGPL-2.0, LGPL-3.0, WTFPL, GPL-2.0, BSD-2-Clause, AGPL-3.0, CC-BY-SA-3.0, MPL-2.0, JSON, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.1, CPL-1.0, AGPL-1.0, 0BSD, ISC, Apache-2.0, GPL-3.0, IPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
- /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */
- /*-
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Digital Equipment Corporation and Ralph Campbell.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Copyright (C) 1989 Digital Equipment Corporation.
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appears in all copies.
- * Digital Equipment Corporation makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
- * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL)
- * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
- * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL)
- * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
- * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL)
- * from: @(#)locore.s 8.5 (Berkeley) 1/4/94
- * JNPR: exception.S,v 1.5 2007/01/08 04:58:37 katta
- * $FreeBSD$
- */
- /*
- * Contains code that is the first executed at boot time plus
- * assembly language support routines.
- */
- #include "opt_cputype.h"
- #include "opt_ddb.h"
- #include <machine/asm.h>
- #include <machine/cpu.h>
- #include <machine/regnum.h>
- #include <machine/cpuregs.h>
- #include <machine/pte.h>
- #include "opt_cputype.h"
- #include "assym.s"
- .set noreorder # Noreorder is default style!
- /*
- * Reasonable limit
- */
- #define INTRCNT_COUNT 128
- /*
- *----------------------------------------------------------------------------
- *
- * MipsTLBMiss --
- *
- * Vector code for the TLB-miss exception vector 0x80000000.
- *
- * This code is copied to the TLB exception vector address to
- * which the CPU jumps in response to an exception or a TLB miss.
- * NOTE: This code must be position independent!!!
- *
- *
- */
- VECTOR(MipsTLBMiss, unknown)
- .set push
- .set noat
- j MipsDoTLBMiss
- MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address
- .set pop
- VECTOR_END(MipsTLBMiss)
- /*
- *----------------------------------------------------------------------------
- *
- * MipsDoTLBMiss --
- *
- * This is the real TLB Miss Handler code.
- * 'segbase' points to the base of the segment table for user processes.
- *
- * Don't check for invalid pte's here. We load them as well and
- * let the processor trap to load the correct value after service.
- *----------------------------------------------------------------------------
- */
- .set push
- .set noat
- MipsDoTLBMiss:
- bltz k0, 1f #02: k0<0 -> 1f (kernel fault)
- PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost)
- GET_CPU_PCPU(k1)
- PTR_L k1, PC_SEGBASE(k1)
- beqz k1, 2f #05: make sure segbase is not null
- andi k0, k0, PDEPTRMASK #06: k0=seg offset
- PTR_ADDU k1, k0, k1 #07: k1=seg entry address
- PTR_L k1, 0(k1) #08: k1=seg entry
- MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again)
- beq k1, zero, 2f #0a: ==0 -- no page table
- #ifdef __mips_n64
- PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN
- andi k0, k0, PDEPTRMASK # k0=pde offset
- PTR_ADDU k1, k0, k1 # k1=pde entry address
- PTR_L k1, 0(k1) # k1=pde entry
- MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
- beq k1, zero, 2f # ==0 -- no page table
- #endif
- PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10)
- andi k0, k0, PTE2MASK #0c: k0=page tab offset
- PTR_ADDU k1, k1, k0 #0d: k1=pte address
- PTE_L k0, 0(k1) #0e: k0=lo0 pte
- PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte
- CLEAR_PTE_SWBITS(k0)
- PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded
- COP0_SYNC
- CLEAR_PTE_SWBITS(k1)
- PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded
- COP0_SYNC
- tlbwr #1a: write to tlb
- HAZARD_DELAY
- eret #1f: retUrn from exception
- 1: j MipsTLBMissException #20: kernel exception
- nop #21: branch delay slot
- 2: j SlowFault #22: no page table present
- nop #23: branch delay slot
- .set pop
- /*
- * This code is copied to the general exception vector address to
- * handle all execptions except RESET and TLBMiss.
- * NOTE: This code must be position independent!!!
- */
- VECTOR(MipsException, unknown)
- /*
- * Find out what mode we came from and jump to the proper handler.
- */
- .set noat
- mfc0 k0, MIPS_COP_0_STATUS # Get the status register
- mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value.
- and k0, k0, SR_KSU_USER # test for user mode
- # sneaky but the bits are
- # with us........
- sll k0, k0, 3 # shift user bit for cause index
- and k1, k1, MIPS3_CR_EXC_CODE # Mask out the cause bits.
- or k1, k1, k0 # change index to user table
- #if defined(__mips_n64)
- PTR_SLL k1, k1, 1 # shift to get 8-byte offset
- #endif
- 1:
- PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table
- PTR_ADDU k0, k0, k1 # Get the address of the
- # function entry. Note that
- # the cause is already
- # shifted left by 2 bits so
- # we dont have to shift.
- PTR_L k0, 0(k0) # Get the function address
- nop
- j k0 # Jump to the function.
- nop
- .set at
- VECTOR_END(MipsException)
- /*
- * We couldn't find a TLB entry.
- * Find out what mode we came from and call the appropriate handler.
- */
- SlowFault:
- .set noat
- mfc0 k0, MIPS_COP_0_STATUS
- nop
- and k0, k0, SR_KSU_USER
- bne k0, zero, _C_LABEL(MipsUserGenException)
- nop
- .set at
- /*
- * Fall though ...
- */
- /*----------------------------------------------------------------------------
- *
- * MipsKernGenException --
- *
- * Handle an exception from kernel mode.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
- #define SAVE_REG(reg, offs, base) \
- REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base)
- #if defined(CPU_CNMIPS)
- #define CLEAR_STATUS \
- mfc0 a0, MIPS_COP_0_STATUS ;\
- li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \
- or a0, a0, a2 ; \
- li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
- and a0, a0, a2 ; \
- mtc0 a0, MIPS_COP_0_STATUS ; \
- ITLBNOPFIX
- #elif defined(CPU_RMI) || defined(CPU_NLM)
- #define CLEAR_STATUS \
- mfc0 a0, MIPS_COP_0_STATUS ;\
- li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \
- or a0, a0, a2 ; \
- li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
- and a0, a0, a2 ; \
- mtc0 a0, MIPS_COP_0_STATUS ; \
- ITLBNOPFIX
- #else
- #define CLEAR_STATUS \
- mfc0 a0, MIPS_COP_0_STATUS ;\
- li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | SR_KSU_USER) ; \
- and a0, a0, a2 ; \
- mtc0 a0, MIPS_COP_0_STATUS ; \
- ITLBNOPFIX
- #endif
- /*
- * Save CPU and CP0 register state.
- *
- * This is straightforward except for saving the exception program
- * counter. The ddb backtrace code looks for the first instruction
- * matching the form "sw ra, (off)sp" to figure out the address of the
- * calling function. So we must make sure that we save the exception
- * PC by staging it through 'ra' as opposed to any other register.
- */
- #define SAVE_CPU \
- SAVE_REG(AT, AST, sp) ;\
- .set at ; \
- SAVE_REG(v0, V0, sp) ;\
- SAVE_REG(v1, V1, sp) ;\
- SAVE_REG(a0, A0, sp) ;\
- SAVE_REG(a1, A1, sp) ;\
- SAVE_REG(a2, A2, sp) ;\
- SAVE_REG(a3, A3, sp) ;\
- SAVE_REG(t0, T0, sp) ;\
- SAVE_REG(t1, T1, sp) ;\
- SAVE_REG(t2, T2, sp) ;\
- SAVE_REG(t3, T3, sp) ;\
- SAVE_REG(ta0, TA0, sp) ;\
- SAVE_REG(ta1, TA1, sp) ;\
- SAVE_REG(ta2, TA2, sp) ;\
- SAVE_REG(ta3, TA3, sp) ;\
- SAVE_REG(t8, T8, sp) ;\
- SAVE_REG(t9, T9, sp) ;\
- SAVE_REG(gp, GP, sp) ;\
- SAVE_REG(s0, S0, sp) ;\
- SAVE_REG(s1, S1, sp) ;\
- SAVE_REG(s2, S2, sp) ;\
- SAVE_REG(s3, S3, sp) ;\
- SAVE_REG(s4, S4, sp) ;\
- SAVE_REG(s5, S5, sp) ;\
- SAVE_REG(s6, S6, sp) ;\
- SAVE_REG(s7, S7, sp) ;\
- SAVE_REG(s8, S8, sp) ;\
- mflo v0 ;\
- mfhi v1 ;\
- mfc0 a0, MIPS_COP_0_STATUS ;\
- mfc0 a1, MIPS_COP_0_CAUSE ;\
- MFC0 a2, MIPS_COP_0_BAD_VADDR;\
- MFC0 a3, MIPS_COP_0_EXC_PC ;\
- SAVE_REG(v0, MULLO, sp) ;\
- SAVE_REG(v1, MULHI, sp) ;\
- SAVE_REG(a0, SR, sp) ;\
- SAVE_REG(a1, CAUSE, sp) ;\
- SAVE_REG(a2, BADVADDR, sp) ;\
- move t0, ra ;\
- move ra, a3 ;\
- SAVE_REG(ra, PC, sp) ;\
- move ra, t0 ;\
- SAVE_REG(ra, RA, sp) ;\
- PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\
- SAVE_REG(v0, SP, sp) ;\
- CLEAR_STATUS ;\
- PTR_ADDU a0, sp, CALLFRAME_SIZ ;\
- ITLBNOPFIX
- #define RESTORE_REG(reg, offs, base) \
- REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base)
- #define RESTORE_CPU \
- CLEAR_STATUS ;\
- RESTORE_REG(k0, SR, sp) ;\
- RESTORE_REG(t0, MULLO, sp) ;\
- RESTORE_REG(t1, MULHI, sp) ;\
- mtlo t0 ;\
- mthi t1 ;\
- MTC0 v0, MIPS_COP_0_EXC_PC ;\
- .set noat ;\
- RESTORE_REG(AT, AST, sp) ;\
- RESTORE_REG(v0, V0, sp) ;\
- RESTORE_REG(v1, V1, sp) ;\
- RESTORE_REG(a0, A0, sp) ;\
- RESTORE_REG(a1, A1, sp) ;\
- RESTORE_REG(a2, A2, sp) ;\
- RESTORE_REG(a3, A3, sp) ;\
- RESTORE_REG(t0, T0, sp) ;\
- RESTORE_REG(t1, T1, sp) ;\
- RESTORE_REG(t2, T2, sp) ;\
- RESTORE_REG(t3, T3, sp) ;\
- RESTORE_REG(ta0, TA0, sp) ;\
- RESTORE_REG(ta1, TA1, sp) ;\
- RESTORE_REG(ta2, TA2, sp) ;\
- RESTORE_REG(ta3, TA3, sp) ;\
- RESTORE_REG(t8, T8, sp) ;\
- RESTORE_REG(t9, T9, sp) ;\
- RESTORE_REG(s0, S0, sp) ;\
- RESTORE_REG(s1, S1, sp) ;\
- RESTORE_REG(s2, S2, sp) ;\
- RESTORE_REG(s3, S3, sp) ;\
- RESTORE_REG(s4, S4, sp) ;\
- RESTORE_REG(s5, S5, sp) ;\
- RESTORE_REG(s6, S6, sp) ;\
- RESTORE_REG(s7, S7, sp) ;\
- RESTORE_REG(s8, S8, sp) ;\
- RESTORE_REG(gp, GP, sp) ;\
- RESTORE_REG(ra, RA, sp) ;\
- PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\
- mtc0 k0, MIPS_COP_0_STATUS
- /*
- * The kernel exception stack contains 18 saved general registers,
- * the status register and the multiply lo and high registers.
- * In addition, we set this up for linkage conventions.
- */
- #define KERN_REG_SIZE (NUMSAVEREGS * SZREG)
- #define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16)
- NNON_LEAF(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra)
- .set noat
- PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
- .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
- /*
- * Save CPU state, building 'frame'.
- */
- SAVE_CPU
- /*
- * Call the exception handler. a0 points at the saved frame.
- */
- PTR_LA gp, _C_LABEL(_gp)
- PTR_LA k0, _C_LABEL(trap)
- jalr k0
- REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
- /*
- * Update interrupt and CPU mask in saved status register
- * Some of interrupts could be disabled by
- * intr filters if interrupts are enabled later
- * in trap handler
- */
- mfc0 a0, MIPS_COP_0_STATUS
- and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
- RESTORE_REG(a1, SR, sp)
- and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
- or a1, a1, a0
- SAVE_REG(a1, SR, sp)
- RESTORE_CPU # v0 contains the return address.
- sync
- eret
- .set at
- END(MipsKernGenException)
- #define SAVE_U_PCB_REG(reg, offs, base) \
- REG_S reg, U_PCB_REGS + (SZREG * offs) (base)
- #define RESTORE_U_PCB_REG(reg, offs, base) \
- REG_L reg, U_PCB_REGS + (SZREG * offs) (base)
- /*----------------------------------------------------------------------------
- *
- * MipsUserGenException --
- *
- * Handle an exception from user mode.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
- NNON_LEAF(MipsUserGenException, CALLFRAME_SIZ, ra)
- .set noat
- .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
- /*
- * Save all of the registers except for the kernel temporaries in u.u_pcb.
- */
- GET_CPU_PCPU(k1)
- PTR_L k1, PC_CURPCB(k1)
- SAVE_U_PCB_REG(AT, AST, k1)
- .set at
- SAVE_U_PCB_REG(v0, V0, k1)
- SAVE_U_PCB_REG(v1, V1, k1)
- SAVE_U_PCB_REG(a0, A0, k1)
- mflo v0
- SAVE_U_PCB_REG(a1, A1, k1)
- SAVE_U_PCB_REG(a2, A2, k1)
- SAVE_U_PCB_REG(a3, A3, k1)
- SAVE_U_PCB_REG(t0, T0, k1)
- mfhi v1
- SAVE_U_PCB_REG(t1, T1, k1)
- SAVE_U_PCB_REG(t2, T2, k1)
- SAVE_U_PCB_REG(t3, T3, k1)
- SAVE_U_PCB_REG(ta0, TA0, k1)
- mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg.
- SAVE_U_PCB_REG(ta1, TA1, k1)
- SAVE_U_PCB_REG(ta2, TA2, k1)
- SAVE_U_PCB_REG(ta3, TA3, k1)
- SAVE_U_PCB_REG(s0, S0, k1)
- mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg.
- SAVE_U_PCB_REG(s1, S1, k1)
- SAVE_U_PCB_REG(s2, S2, k1)
- SAVE_U_PCB_REG(s3, S3, k1)
- SAVE_U_PCB_REG(s4, S4, k1)
- MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr
- SAVE_U_PCB_REG(s5, S5, k1)
- SAVE_U_PCB_REG(s6, S6, k1)
- SAVE_U_PCB_REG(s7, S7, k1)
- SAVE_U_PCB_REG(t8, T8, k1)
- MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc.
- SAVE_U_PCB_REG(t9, T9, k1)
- SAVE_U_PCB_REG(gp, GP, k1)
- SAVE_U_PCB_REG(sp, SP, k1)
- SAVE_U_PCB_REG(s8, S8, k1)
- PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP
- SAVE_U_PCB_REG(ra, RA, k1)
- SAVE_U_PCB_REG(v0, MULLO, k1)
- SAVE_U_PCB_REG(v1, MULHI, k1)
- SAVE_U_PCB_REG(a0, SR, k1)
- SAVE_U_PCB_REG(a1, CAUSE, k1)
- SAVE_U_PCB_REG(a2, BADVADDR, k1)
- SAVE_U_PCB_REG(a3, PC, k1)
- REG_S a3, CALLFRAME_RA(sp) # for debugging
- PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP
- # Turn off fpu and enter kernel mode
- and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS3_SR_KSU_MASK | MIPS_SR_INT_IE)
- #if defined(CPU_CNMIPS)
- and t0, t0, ~(MIPS_SR_COP_2_BIT)
- or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
- #elif defined(CPU_RMI) || defined(CPU_NLM)
- or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
- #endif
- mtc0 t0, MIPS_COP_0_STATUS
- PTR_ADDU a0, k1, U_PCB_REGS
- ITLBNOPFIX
- /*
- * Call the exception handler.
- */
- PTR_LA k0, _C_LABEL(trap)
- jalr k0
- nop
- /*
- * Restore user registers and return.
- * First disable interrupts and set exeption level.
- */
- DO_AST
- CLEAR_STATUS
- /*
- * The use of k1 for storing the PCB pointer must be done only
- * after interrupts are disabled. Otherwise it will get overwritten
- * by the interrupt code.
- */
- GET_CPU_PCPU(k1)
- PTR_L k1, PC_CURPCB(k1)
- /*
- * Update interrupt mask in saved status register
- * Some of interrupts could be enabled by ithread
- * scheduled by ast()
- */
- mfc0 a0, MIPS_COP_0_STATUS
- and a0, a0, MIPS_SR_INT_MASK
- RESTORE_U_PCB_REG(a1, SR, k1)
- and a1, a1, ~MIPS_SR_INT_MASK
- or a1, a1, a0
- SAVE_U_PCB_REG(a1, SR, k1)
- RESTORE_U_PCB_REG(t0, MULLO, k1)
- RESTORE_U_PCB_REG(t1, MULHI, k1)
- mtlo t0
- mthi t1
- RESTORE_U_PCB_REG(a0, PC, k1)
- RESTORE_U_PCB_REG(v0, V0, k1)
- MTC0 a0, MIPS_COP_0_EXC_PC # set return address
- RESTORE_U_PCB_REG(v1, V1, k1)
- RESTORE_U_PCB_REG(a0, A0, k1)
- RESTORE_U_PCB_REG(a1, A1, k1)
- RESTORE_U_PCB_REG(a2, A2, k1)
- RESTORE_U_PCB_REG(a3, A3, k1)
- RESTORE_U_PCB_REG(t0, T0, k1)
- RESTORE_U_PCB_REG(t1, T1, k1)
- RESTORE_U_PCB_REG(t2, T2, k1)
- RESTORE_U_PCB_REG(t3, T3, k1)
- RESTORE_U_PCB_REG(ta0, TA0, k1)
- RESTORE_U_PCB_REG(ta1, TA1, k1)
- RESTORE_U_PCB_REG(ta2, TA2, k1)
- RESTORE_U_PCB_REG(ta3, TA3, k1)
- RESTORE_U_PCB_REG(s0, S0, k1)
- RESTORE_U_PCB_REG(s1, S1, k1)
- RESTORE_U_PCB_REG(s2, S2, k1)
- RESTORE_U_PCB_REG(s3, S3, k1)
- RESTORE_U_PCB_REG(s4, S4, k1)
- RESTORE_U_PCB_REG(s5, S5, k1)
- RESTORE_U_PCB_REG(s6, S6, k1)
- RESTORE_U_PCB_REG(s7, S7, k1)
- RESTORE_U_PCB_REG(t8, T8, k1)
- RESTORE_U_PCB_REG(t9, T9, k1)
- RESTORE_U_PCB_REG(gp, GP, k1)
- RESTORE_U_PCB_REG(sp, SP, k1)
- RESTORE_U_PCB_REG(k0, SR, k1)
- RESTORE_U_PCB_REG(s8, S8, k1)
- RESTORE_U_PCB_REG(ra, RA, k1)
- .set noat
- RESTORE_U_PCB_REG(AT, AST, k1)
- mtc0 k0, MIPS_COP_0_STATUS # still exception level
- ITLBNOPFIX
- sync
- eret
- .set at
- END(MipsUserGenException)
- .set push
- .set noat
- NON_LEAF(mips_wait, CALLFRAME_SIZ, ra)
- PTR_SUBU sp, sp, CALLFRAME_SIZ
- .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
- REG_S ra, CALLFRAME_RA(sp) # save RA
- mfc0 t0, MIPS_COP_0_STATUS
- xori t1, t0, MIPS_SR_INT_IE
- mtc0 t1, MIPS_COP_0_STATUS
- COP0_SYNC
- jal sched_runnable
- nop
- REG_L ra, CALLFRAME_RA(sp)
- mfc0 t0, MIPS_COP_0_STATUS
- ori t1, t0, MIPS_SR_INT_IE
- .align 4
- GLOBAL(MipsWaitStart) # this is 16 byte aligned
- mtc0 t1, MIPS_COP_0_STATUS
- bnez v0, MipsWaitEnd
- nop
- wait
- GLOBAL(MipsWaitEnd) # MipsWaitStart + 16
- jr ra
- PTR_ADDU sp, sp, CALLFRAME_SIZ
- END(mips_wait)
- .set pop
- /*----------------------------------------------------------------------------
- *
- * MipsKernIntr --
- *
- * Handle an interrupt from kernel mode.
- * Interrupts use the standard kernel stack.
- * switch_exit sets up a kernel stack after exit so interrupts won't fail.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
- NNON_LEAF(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra)
- .set noat
- PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
- .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE)
- /*
- * Check for getting interrupts just before wait
- */
- MFC0 k0, MIPS_COP_0_EXC_PC
- ori k0, 0xf
- xori k0, 0xf # 16 byte align
- PTR_LA k1, MipsWaitStart
- bne k0, k1, 1f
- nop
- PTR_ADDU k1, 16 # skip over wait
- MTC0 k1, MIPS_COP_0_EXC_PC
- 1:
- /*
- * Save CPU state, building 'frame'.
- */
- SAVE_CPU
- /*
- * Call the interrupt handler. a0 points at the saved frame.
- */
- PTR_LA gp, _C_LABEL(_gp)
- PTR_LA k0, _C_LABEL(cpu_intr)
- jalr k0
- REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging
- /*
- * Update interrupt and CPU mask in saved status register
- * Some of interrupts could be disabled by
- * intr filters if interrupts are enabled later
- * in trap handler
- */
- mfc0 a0, MIPS_COP_0_STATUS
- and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
- RESTORE_REG(a1, SR, sp)
- and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY)
- or a1, a1, a0
- SAVE_REG(a1, SR, sp)
- REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp)
- RESTORE_CPU # v0 contains the return address.
- sync
- eret
- .set at
- END(MipsKernIntr)
- /*----------------------------------------------------------------------------
- *
- * MipsUserIntr --
- *
- * Handle an interrupt from user mode.
- * Note: we save minimal state in the u.u_pcb struct and use the standard
- * kernel stack since there has to be a u page if we came from user mode.
- * If there is a pending software interrupt, then save the remaining state
- * and call softintr(). This is all because if we call switch() inside
- * interrupt(), not all the user registers have been saved in u.u_pcb.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
- NNON_LEAF(MipsUserIntr, CALLFRAME_SIZ, ra)
- .set noat
- .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
- /*
- * Save the relevant user registers into the u.u_pcb struct.
- * We don't need to save s0 - s8 because the compiler does it for us.
- */
- GET_CPU_PCPU(k1)
- PTR_L k1, PC_CURPCB(k1)
- SAVE_U_PCB_REG(AT, AST, k1)
- .set at
- SAVE_U_PCB_REG(v0, V0, k1)
- SAVE_U_PCB_REG(v1, V1, k1)
- SAVE_U_PCB_REG(a0, A0, k1)
- SAVE_U_PCB_REG(a1, A1, k1)
- SAVE_U_PCB_REG(a2, A2, k1)
- SAVE_U_PCB_REG(a3, A3, k1)
- SAVE_U_PCB_REG(t0, T0, k1)
- SAVE_U_PCB_REG(t1, T1, k1)
- SAVE_U_PCB_REG(t2, T2, k1)
- SAVE_U_PCB_REG(t3, T3, k1)
- SAVE_U_PCB_REG(ta0, TA0, k1)
- SAVE_U_PCB_REG(ta1, TA1, k1)
- SAVE_U_PCB_REG(ta2, TA2, k1)
- SAVE_U_PCB_REG(ta3, TA3, k1)
- SAVE_U_PCB_REG(t8, T8, k1)
- SAVE_U_PCB_REG(t9, T9, k1)
- SAVE_U_PCB_REG(gp, GP, k1)
- SAVE_U_PCB_REG(sp, SP, k1)
- SAVE_U_PCB_REG(ra, RA, k1)
- /*
- * save remaining user state in u.u_pcb.
- */
- SAVE_U_PCB_REG(s0, S0, k1)
- SAVE_U_PCB_REG(s1, S1, k1)
- SAVE_U_PCB_REG(s2, S2, k1)
- SAVE_U_PCB_REG(s3, S3, k1)
- SAVE_U_PCB_REG(s4, S4, k1)
- SAVE_U_PCB_REG(s5, S5, k1)
- SAVE_U_PCB_REG(s6, S6, k1)
- SAVE_U_PCB_REG(s7, S7, k1)
- SAVE_U_PCB_REG(s8, S8, k1)
- mflo v0 # get lo/hi late to avoid stall
- mfhi v1
- mfc0 a0, MIPS_COP_0_STATUS
- mfc0 a1, MIPS_COP_0_CAUSE
- MFC0 a3, MIPS_COP_0_EXC_PC
- SAVE_U_PCB_REG(v0, MULLO, k1)
- SAVE_U_PCB_REG(v1, MULHI, k1)
- SAVE_U_PCB_REG(a0, SR, k1)
- SAVE_U_PCB_REG(a1, CAUSE, k1)
- SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later!
- PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP
- PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP
- # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level.
- and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS3_SR_KSU_MASK)
- #ifdef CPU_CNMIPS
- and t0, t0, ~(MIPS_SR_COP_2_BIT)
- or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX)
- #elif defined(CPU_RMI) || defined(CPU_NLM)
- or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT)
- #endif
- mtc0 t0, MIPS_COP_0_STATUS
- ITLBNOPFIX
- PTR_ADDU a0, k1, U_PCB_REGS
- /*
- * Call the interrupt handler.
- */
- PTR_LA k0, _C_LABEL(cpu_intr)
- jalr k0
- REG_S a3, CALLFRAME_RA(sp) # for debugging
- /*
- * Enable interrupts before doing ast().
- *
- * On SMP kernels the AST processing might trigger IPI to other processors.
- * If that processor is also doing AST processing with interrupts disabled
- * then we may deadlock.
- */
- mfc0 a0, MIPS_COP_0_STATUS
- or a0, a0, MIPS_SR_INT_IE
- mtc0 a0, MIPS_COP_0_STATUS
- ITLBNOPFIX
- /*
- * DO_AST enabled interrupts
- */
- DO_AST
-
- /*
- * Restore user registers and return.
- */
- CLEAR_STATUS
- GET_CPU_PCPU(k1)
- PTR_L k1, PC_CURPCB(k1)
- /*
- * Update interrupt mask in saved status register
- * Some of interrupts could be disabled by
- * intr filters
- */
- mfc0 a0, MIPS_COP_0_STATUS
- and a0, a0, MIPS_SR_INT_MASK
- RESTORE_U_PCB_REG(a1, SR, k1)
- and a1, a1, ~MIPS_SR_INT_MASK
- or a1, a1, a0
- SAVE_U_PCB_REG(a1, SR, k1)
- RESTORE_U_PCB_REG(s0, S0, k1)
- RESTORE_U_PCB_REG(s1, S1, k1)
- RESTORE_U_PCB_REG(s2, S2, k1)
- RESTORE_U_PCB_REG(s3, S3, k1)
- RESTORE_U_PCB_REG(s4, S4, k1)
- RESTORE_U_PCB_REG(s5, S5, k1)
- RESTORE_U_PCB_REG(s6, S6, k1)
- RESTORE_U_PCB_REG(s7, S7, k1)
- RESTORE_U_PCB_REG(s8, S8, k1)
- RESTORE_U_PCB_REG(t0, MULLO, k1)
- RESTORE_U_PCB_REG(t1, MULHI, k1)
- RESTORE_U_PCB_REG(t2, PC, k1)
- mtlo t0
- mthi t1
- MTC0 t2, MIPS_COP_0_EXC_PC # set return address
- RESTORE_U_PCB_REG(v0, V0, k1)
- RESTORE_U_PCB_REG(v1, V1, k1)
- RESTORE_U_PCB_REG(a0, A0, k1)
- RESTORE_U_PCB_REG(a1, A1, k1)
- RESTORE_U_PCB_REG(a2, A2, k1)
- RESTORE_U_PCB_REG(a3, A3, k1)
- RESTORE_U_PCB_REG(t0, T0, k1)
- RESTORE_U_PCB_REG(t1, T1, k1)
- RESTORE_U_PCB_REG(t2, T2, k1)
- RESTORE_U_PCB_REG(t3, T3, k1)
- RESTORE_U_PCB_REG(ta0, TA0, k1)
- RESTORE_U_PCB_REG(ta1, TA1, k1)
- RESTORE_U_PCB_REG(ta2, TA2, k1)
- RESTORE_U_PCB_REG(ta3, TA3, k1)
- RESTORE_U_PCB_REG(t8, T8, k1)
- RESTORE_U_PCB_REG(t9, T9, k1)
- RESTORE_U_PCB_REG(gp, GP, k1)
- RESTORE_U_PCB_REG(k0, SR, k1)
- RESTORE_U_PCB_REG(sp, SP, k1)
- RESTORE_U_PCB_REG(ra, RA, k1)
- .set noat
- RESTORE_U_PCB_REG(AT, AST, k1)
- mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set.
- ITLBNOPFIX
- sync
- eret
- .set at
- END(MipsUserIntr)
- NLEAF(MipsTLBInvalidException)
- .set push
- .set noat
- .set noreorder
- MFC0 k0, MIPS_COP_0_BAD_VADDR
- PTR_LI k1, VM_MAXUSER_ADDRESS
- sltu k1, k0, k1
- bnez k1, 1f
- nop
- /* Kernel address. */
- lui k1, %hi(kernel_segmap) # k1=hi of segbase
- b 2f
- PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
- 1: /* User address. */
- GET_CPU_PCPU(k1)
- PTR_L k1, PC_SEGBASE(k1)
- 2: /* Validate page directory pointer. */
- beqz k1, 3f
- nop
- PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost)
- beq k1, zero, MipsKernGenException # ==0 -- no seg tab
- andi k0, k0, PDEPTRMASK #06: k0=seg offset
- PTR_ADDU k1, k0, k1 # k1=seg entry address
- PTR_L k1, 0(k1) # k1=seg entry
- /* Validate page table pointer. */
- beqz k1, 3f
- nop
- #ifdef __mips_n64
- MFC0 k0, MIPS_COP_0_BAD_VADDR
- PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost)
- beq k1, zero, MipsKernGenException # ==0 -- no pde tab
- andi k0, k0, PDEPTRMASK # k0=pde offset
- PTR_ADDU k1, k0, k1 # k1=pde entry address
- PTR_L k1, 0(k1) # k1=pde entry
- /* Validate pde table pointer. */
- beqz k1, 3f
- nop
- #endif
- MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
- PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN
- andi k0, k0, PTEMASK # k0=page tab offset
- PTR_ADDU k1, k1, k0 # k1=pte address
- PTE_L k0, 0(k1) # k0=this PTE
- /* Validate page table entry. */
- andi k0, PTE_V
- beqz k0, 3f
- nop
- /* Check whether this is an even or odd entry. */
- andi k0, k1, PTESIZE
- bnez k0, odd_page
- nop
- PTE_L k0, 0(k1)
- PTE_L k1, PTESIZE(k1)
- CLEAR_PTE_SWBITS(k0)
- PTE_MTC0 k0, MIPS_COP_0_TLB_LO0
- COP0_SYNC
- CLEAR_PTE_SWBITS(k1)
- PTE_MTC0 k1, MIPS_COP_0_TLB_LO1
- COP0_SYNC
- b tlb_insert_entry
- nop
- odd_page:
- PTE_L k0, -PTESIZE(k1)
- PTE_L k1, 0(k1)
- CLEAR_PTE_SWBITS(k0)
- PTE_MTC0 k0, MIPS_COP_0_TLB_LO0
- COP0_SYNC
- CLEAR_PTE_SWBITS(k1)
- PTE_MTC0 k1, MIPS_COP_0_TLB_LO1
- COP0_SYNC
- tlb_insert_entry:
- tlbp
- HAZARD_DELAY
- mfc0 k0, MIPS_COP_0_TLB_INDEX
- bltz k0, tlb_insert_random
- nop
- tlbwi
- eret
- ssnop
- tlb_insert_random:
- tlbwr
- eret
- ssnop
- 3:
- /*
- * Branch to the comprehensive exception processing.
- */
- mfc0 k1, MIPS_COP_0_STATUS
- andi k1, k1, SR_KSU_USER
- bnez k1, _C_LABEL(MipsUserGenException)
- nop
- /*
- * Check for kernel stack overflow.
- */
- GET_CPU_PCPU(k1)
- PTR_L k0, PC_CURTHREAD(k1)
- PTR_L k0, TD_KSTACK(k0)
- sltu k0, k0, sp
- bnez k0, _C_LABEL(MipsKernGenException)
- nop
- /*
- * Kernel stack overflow.
- *
- * Move to a valid stack before we call panic. We use the boot stack
- * for this purpose.
- */
- GET_CPU_PCPU(k1)
- lw k1, PC_CPUID(k1)
- sll k1, k1, PAGE_SHIFT + 1
- PTR_LA k0, _C_LABEL(pcpu_space)
- PTR_ADDU k0, PAGE_SIZE * 2
- PTR_ADDU k0, k0, k1
- /*
- * Stash the original value of 'sp' so we can update trapframe later.
- * We assume that SAVE_CPU does not trash 'k1'.
- */
- move k1, sp
- move sp, k0
- PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE
- move k0, ra
- move ra, zero
- REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */
- REG_S zero, CALLFRAME_SP(sp)
- move ra, k0
- SAVE_CPU
- /*
- * Now restore the value of 'sp' at the time of the tlb exception in
- * the trapframe.
- */
- SAVE_REG(k1, SP, sp)
- /*
- * Squelch any more overflow checks by setting the stack base to 0.
- */
- GET_CPU_PCPU(k1)
- PTR_L k0, PC_CURTHREAD(k1)
- PTR_S zero, TD_KSTACK(k0)
- move a1, a0
- PANIC("kernel stack overflow - trapframe at %p")
- /*
- * This nop is necessary so that the 'ra' remains within the bounds
- * of this handler. Otherwise the ddb backtrace code will think that
- * the panic() was called from MipsTLBMissException.
- */
- nop
- .set pop
- END(MipsTLBInvalidException)
- /*----------------------------------------------------------------------------
- *
- * MipsTLBMissException --
- *
- * Handle a TLB miss exception from kernel mode in kernel space.
- * The BaddVAddr, Context, and EntryHi registers contain the failed
- * virtual address.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
- NLEAF(MipsTLBMissException)
- .set noat
- MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address
- PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against
- sltu k1, k1, k0 # upper bound of kernel_segmap
- bnez k1, MipsKernGenException # out of bound
- lui k1, %hi(kernel_segmap) # k1=hi of segbase
- PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost)
- PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base
- beq k1, zero, MipsKernGenException # ==0 -- no seg tab
- andi k0, k0, PDEPTRMASK #06: k0=seg offset
- PTR_ADDU k1, k0, k1 # k1=seg entry address
- PTR_L k1, 0(k1) # k1=seg entry
- MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
- beq k1, zero, MipsKernGenException # ==0 -- no page table
- #ifdef __mips_n64
- PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN
- andi k0, k0, PDEPTRMASK # k0=pde offset
- PTR_ADDU k1, k0, k1 # k1=pde entry address
- PTR_L k1, 0(k1) # k1=pde entry
- MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again)
- beq k1, zero, MipsKernGenException # ==0 -- no page table
- #endif
- PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN
- andi k0, k0, PTE2MASK # k0=page tab offset
- PTR_ADDU k1, k1, k0 # k1=pte address
- PTE_L k0, 0(k1) # k0=lo0 pte
- PTE_L k1, PTESIZE(k1) # k1=lo1 pte
- CLEAR_PTE_SWBITS(k0)
- PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded
- COP0_SYNC
- CLEAR_PTE_SWBITS(k1)
- PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded
- COP0_SYNC
- tlbwr # write to tlb
- HAZARD_DELAY
- eret # return from exception
- .set at
- END(MipsTLBMissException)
- /*----------------------------------------------------------------------------
- *
- * MipsFPTrap --
- *
- * Handle a floating point Trap.
- *
- * MipsFPTrap(statusReg, causeReg, pc)
- * unsigned statusReg;
- * unsigned causeReg;
- * unsigned pc;
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------------
- */
- NON_LEAF(MipsFPTrap, CALLFRAME_SIZ, ra)
- PTR_SUBU sp, sp, CALLFRAME_SIZ
- mfc0 t0, MIPS_COP_0_STATUS
- REG_S ra, CALLFRAME_RA(sp)
- .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
- or t1, t0, MIPS_SR_COP_1_BIT
- mtc0 t1, MIPS_COP_0_STATUS
- ITLBNOPFIX
- cfc1 t1, MIPS_FPU_CSR # stall til FP done
- cfc1 t1, MIPS_FPU_CSR # now get status
- nop
- sll t2, t1, (31 - 17) # unimplemented operation?
- bgez t2, 3f # no, normal trap
- nop
- /*
- * We got an unimplemented operation trap so
- * fetch the instruction, compute the next PC and emulate the instruction.
- */
- bgez a1, 1f # Check the branch delay bit.
- nop
- /*
- * The instruction is in the branch delay slot so the branch will have to
- * be emulated to get the resulting PC.
- */
- PTR_S a2, CALLFRAME_SIZ + 8(sp)
- GET_CPU_PCPU(a0)
- #mips64 unsafe?
- PTR_L a0, PC_CURPCB(a0)
- PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers
- move a1, a2 # second arg is instruction PC
- move a2, t1 # third arg is floating point CSR
- PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch
- jalr t3 # compute PC after branch
- move a3, zero # fourth arg is FALSE
- /*
- * Now load the floating-point instruction in the branch delay slot
- * to be emulated.
- */
- PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc
- b 2f
- lw a0, 4(a2) # a0 = coproc instruction
- /*
- * This is not in the branch delay slot so calculate the resulting
- * PC (epc + 4) into v0 and continue to MipsEmulateFP().
- */
- 1:
- lw a0, 0(a2) # a0 = coproc instruction
- #xxx mips64 unsafe?
- PTR_ADDU v0, a2, 4 # v0 = next pc
- 2:
- GET_CPU_PCPU(t2)
- PTR_L t2, PC_CURPCB(t2)
- SAVE_U_PCB_REG(v0, PC, t2) # save new pc
- /*
- * Check to see if the instruction to be emulated is a floating-point
- * instruction.
- */
- srl a3, a0, MIPS_OPCODE_SHIFT
- beq a3, MIPS_OPCODE_C1, 4f # this should never fail
- nop
- /*
- * Send a floating point exception signal to the current process.
- */
- 3:
- GET_CPU_PCPU(a0)
- PTR_L a0, PC_CURTHREAD(a0) # get current thread
- cfc1 a2, MIPS_FPU_CSR # code = FP execptions
- ctc1 zero, MIPS_FPU_CSR # Clear exceptions
- PTR_LA t3, _C_LABEL(trapsignal)
- jalr t3
- li a1, SIGFPE
- b FPReturn
- nop
- /*
- * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate.
- */
- 4:
- PTR_LA t3, _C_LABEL(MipsEmulateFP)
- jalr t3
- nop
- /*
- * Turn off the floating point coprocessor and return.
- */
- FPReturn:
- mfc0 t0, MIPS_COP_0_STATUS
- PTR_L ra, CALLFRAME_RA(sp)
- and t0, t0, ~MIPS_SR_COP_1_BIT
- mtc0 t0, MIPS_COP_0_STATUS
- ITLBNOPFIX
- j ra
- PTR_ADDU sp, sp, CALLFRAME_SIZ
- END(MipsFPTrap)
- /*
- * Interrupt counters for vmstat.
- */
- .data
- .globl intrcnt
- .globl sintrcnt
- .globl intrnames
- .globl sintrnames
- intrnames:
- .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
- sintrnames:
- #ifdef __mips_n64
- .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
- #else
- .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2
- #endif
- .align 4
- intrcnt:
- .space INTRCNT_COUNT * 4 * 2
- sintrcnt:
- #ifdef __mips_n64
- .quad INTRCNT_COUNT * 4 * 2
- #else
- .int INTRCNT_COUNT * 4 * 2
- #endif
- /*
- * Vector to real handler in KSEG1.
- */
- .text
- VECTOR(MipsCache, unknown)
- PTR_LA k0, _C_LABEL(MipsCacheException)
- li k1, MIPS_KSEG0_PHYS_MASK
- and k0, k1
- PTR_LI k1, MIPS_KSEG1_START
- or k0, k1
- j k0
- nop
- VECTOR_END(MipsCache)
- .set at
- /*
- * Panic on cache errors. A lot more could be done to recover
- * from some types of errors but it is tricky.
- */
- NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra)
- .set noat
- .mask 0x80000000, -4
- PTR_LA k0, _C_LABEL(panic) # return to panic
- PTR_LA a0, 9f # panicstr
- MFC0 a1, MIPS_COP_0_ERROR_PC
- mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error
- MTC0 k0, MIPS_COP_0_ERROR_PC # set return address
- mfc0 k0, MIPS_COP_0_STATUS # restore status
- li k1, MIPS_SR_DIAG_PE # ignore further errors
- or k0, k1
- mtc0 k0, MIPS_COP_0_STATUS # restore status
- COP0_SYNC
- eret
- MSG("cache error @ EPC 0x%x CachErr 0x%x");
- .set at
- END(MipsCacheException)