//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/cacherr.s,v 1.2 1996/02/23 17:55:12 pierre Exp $") // TITLE("Cache Error Handling") //++ // // Copyright (c) 1993 Microsoft Corporation // // Module Name: // // cacherr.s // // Abstract: // // This module implements cache error handling. It is entered in KSEG1 // directly from the cache error vector wiht ERL set in the processor // state. // // No correction is done. We only try to get the physical address // that causes this exception // // Environment: // // Kernel mode only. // // Revision History: // //-- #include "halmips.h" .globl HalpCacheErrFirst .globl HalpErrCacheMsg // cache error .globl HalpParityErrMsg // parity error .globl HalpAddrErrMsg // no addr found .globl HalpComputeNum // compute memory sip number .globl HalpKeBugCheck0 .globl HalpKeBugCheck1 .globl HalpKeBugCheck2 .globl HalpKeBugCheck3 .globl HalpKeBugCheck4 .globl HalpBugCheckNumber #define CACHE_ERR_ER 0x80000000 #define CACHE_ERR_EC 0x40000000 #define CACHE_ERR_ED 0x20000000 #define CACHE_ERR_ET 0x10000000 #define CACHE_ERR_ES 0x08000000 #define CACHE_ERR_EE 0x04000000 #define CACHE_ERR_EB 0x02000000 #define CACHE_ERR_EI 0x01000000 #define CACHE_ERR_SIDX 0x003ffff8 #define CACHE_ERR_PIDX 0x00000007 #define PIDX_PD_MASK 0x00001000 // cache size 8k #define HALP_OPCODE_MASK 0xfc000000 #define HALP_OPCODE_SHIFT 24 // because we test opcode number on 8 bits #define HALP_RT1_REG 0x001f0000 #define HALP_RT1_SHIFT 16 #define HALP_RT2_REG 0x03e00000 #define HALP_RT2_SHIFT 21 #define HALP_SWC1 0xe4 // #define HALP_SDC1 0xf4 // #define HALP_LWC1 0xc4 // #define HALP_LDC1 0xd4 // #define HALP_LB 0x80 // #define HALP_LH 0x82 // #define HALP_LW 0x8c // #define HALP_LD 0xdc // #define HALP_LBU 0x90 // #define HALP_LHU 0x94 // #define HALP_SB 0xa0 // #define HALP_SH 0xa4 // #define HALP_SW 0xac // #define HALP_SD 0xfc // #define HALP_LWL 0x88 // #define HALP_LWR 0x98 // #define HALP_LDL 0x68 // #define HALP_LDR 0x6c // #define HALP_LWU 0x9c // #define HALP_SDL 0xb0 // #define HALP_SDR 0xb4 // #define HALP_LL 0xc0 // #define HALP_LLD 0xd0 // #define HALP_SC 0xe0 // #define HALP_SCD 0xf0 // // // Define local save area for register state. // .data SavedAt:.space 4 // saved registers SavedV0:.space 4 // SavedV1:.space 4 // SavedA0:.space 4 // SavedA1:.space 4 // SavedA2:.space 4 // SavedA3:.space 4 // SavedT0:.space 4 // SavedT1:.space 4 // SavedT2:.space 4 // SavedT3:.space 4 // SavedT4:.space 4 // SavedT5:.space 4 // SavedT6:.space 4 // SavedT7:.space 4 // SavedS0:.space 4 // SavedS1:.space 4 // SavedS2:.space 4 // SavedS3:.space 4 // SavedS4:.space 4 // SavedS5:.space 4 // SavedS6:.space 4 // SavedS7:.space 4 // SavedT8:.space 4 // SavedT9:.space 4 // SavedK0:.space 4 // SavedK1:.space 4 // SavedGP:.space 4 // SavedSP:.space 4 // SavedS8:.space 4 // SavedRA:.space 4 // SavedErrorEpc:.space 4 // SavedCacheError:.space 4 // //++ // // VOID // HalpCacheErrorRoutine ( // VOID // ) // // Routine Description: // // This function is entered from the cache error vector executing // in KSEG1 and with finished with a fatal system error : // // Msg Hal : CACHE ERROR - PARITY ERROR - ADDR IN ERROR NOT FOUND // KeBugCheckEx : // a0 = 0x80 Hardware malfunction // a1 = 18 (parity pb) or 19 (cache error) // a2 = physical address in error (or 0x00) // a3 = sim number // a4 = cacheerror register contents // // // N.B. No state has been saved when this routine is entered. // // Arguments: // // None. // // Return Value: // // None. // //-- .struct 0 .struct 0 CiArgs0:.space 4 // saved arguments CiArgs1:.space 4 // saved arguments CiArgs2:.space 4 // saved arguments CiRa: .space 4 // saved return address CiFrameLength: // NESTED_ENTRY(HalpCacheErrorRoutine, CiFrameLength, zero) subu sp,sp,CiFrameLength // allocate stack frame sw ra,CiRa(sp) // save return address PROLOGUE_END // // Save volatile registers needed to fix cache error. // .set noreorder // // Protection to avoid to execute twice in multipro // (modif of psr doesn't seem very effective) // la k0,HalpCacheErrFirst li k1,KSEG1_BASE // convert address of KSEG1 address or k1,k0,k1 // lw k0,0(k1) nop beq k0,zero,1f nop // cache error during cache error routine lw ra,CiRa(sp) // save return address addu sp,sp,CiFrameLength // allocate stack frame eret // hope we don't need k0 and k1... nop 1: add k0,k0,0x01 sw k0,0(k1) // // Save all the registers // la k0,SavedAt // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // .set noat sw AT,0(k0) // save registers AT - a3 .set at sw v0,4(k0) // sw v1,8(k0) // sw a0,12(k0) // sw a1,16(k0) // sw a2,20(k0) // sw a3,24(k0) // sw t0,28(k0) // sw t1,32(k0) // sw t2,36(k0) // sw t3,40(k0) // sw t4,44(k0) // sw t5,48(k0) // sw t6,52(k0) // sw t7,56(k0) // sw s0,60(k0) // sw s1,64(k0) // sw s2,68(k0) // sw s3,72(k0) // sw s4,76(k0) // sw s5,80(k0) // sw s6,84(k0) // sw s7,88(k0) // sw t8,92(k0) // sw t9,96(k0) // sw s8,100(k0) // sw k0,104(k0) // sw k1,108(k0) // sw gp,112(k0) // sw sp,116(k0) // sw s8,120(k0) // sw ra,124(k0) // mfc0 a1,cacheerr // get cache error state nop nop nop nop nop nop mfc0 a0,errorepc // get error address nop nop nop nop nop nop la k0,SavedErrorEpc // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // sw a0,0(k0) // save errorepc register sw a1,4(k0) // save cache error register // // Disable ECC and parity detection (HalpCacheFirstErr will help...) // mfc0 k0,psr // get current processor state nop nop nop nop nop or k0,k0,0x00010000 // disable ECC and Parity detection and k0,k0,0xfffffffe // disable interrupt mtc0 k0,psr and k0,k0,0xffff00e0 mtc0 k0,psr // Analysis of cacheerror register la k0,SavedCacheError // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // lw t0,0(k0) // restore cache error register in t0 and t1,t0,CACHE_ERR_EE // parity error bne t1,zero,ParityError nop // // Cache error message // la a0,HalpErrCacheMsg and a0,a0,0x1fffffff or a0,a0,0xa0000000 la t0,HalDisplayString li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // nop la k0,SavedCacheError // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // lw t0,0(k0) // restore cache error register in t0 and t1,t0,CACHE_ERR_SIDX // grab low bits of PAddr lw t2,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size subu t2,t2,1 not t2 and t1,t2 // t1=PAddre(21..scache_block_size); SCache index // lw t2,KiPcr + PcSecondLevelDcacheSize(zero) // get 2nd size // subu t2,t2,1 // and t1,t2 // t1=PAddre(21..scache_block_size); SCache index and t5,t0,CACHE_ERR_PIDX sll t5,t5,0xc // align PIDX (bits 15:13) and t2,t1,~(PIDX_PD_MASK) // suppress PIDX bits for VAddr or t2,t5 // t2=VAddr(15..scache_block_size);PCache base index or t1,0x80000000 // SCache index with K0SEG address or t2,0x80000000 // PCache base index with K0SEG address and t5,t0,CACHE_ERR_EC // Cache level of the error (0=primary, 1=secondary) bne zero,t5,3f // if EC=0, Primary Cache Parity Error nop 1: // primary cache // int error and t5,t0,CACHE_ERR_ER // data or instruction flag bne zero,t5,2f // if ER=1 Data error nop move a2,t2 // primary cache - inst cache INDEX_LOAD_TAG_I,0(t2) nop mfc0 a3,taglo b 5f nop 2: // primary cache - data move a2,t2 cache INDEX_LOAD_TAG_D,0(t2) nop mfc0 a3,taglo b 5f nop 3: // secondary cache - inst/data move a2,t1 cache INDEX_LOAD_TAG_SD,0(t1) nop mfc0 a3,taglo 5: // maybe a3 will be the erroneous physical address... li a0,0x80 // harware error la k0,SavedErrorEpc // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // li a1,19 // restore error epc register lw a2,4(k0) // restore cache error register la t1,HalpKeBugCheck0 sw a0,0(t1) la t1,HalpKeBugCheck1 sw a1,0(t1) la t1,HalpKeBugCheck2 sw a2,0(t1) la t1,HalpKeBugCheck3 sw a3,0(t1) la t1,HalpKeBugCheck4 sw zero,0(t1) la t1,HalpBugCheckNumber sw a1,0(t1) la t0,KeBugCheckEx li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // sw zero,0x10(sp) lw ra,CiRa(sp) // save return address addu sp,sp,CiFrameLength // allocate stack frame eret nop ParityError: // // cacheerr contents are not usable if parity error. // Then we must disassemble the errorepc code, get the used register // and get the contents of this register which must cause the error. // // // Parity Error Msg // la a0,HalpParityErrMsg and a0,a0,0x1fffffff or a0,a0,0xa0000000 la t0,HalDisplayString li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // nop // // disasm // la k0,SavedErrorEpc // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // lw a0,0(k0) li a2,0x00 // init for one loop move t0,a0 10: lw a0,0(a0) // instruction move a1,a0 // instruction saved in a1 li a3,HALP_OPCODE_MASK and a0,a0,a3 srl a0,a0,HALP_OPCODE_SHIFT li a2,0x00 beq a0,HALP_SWC1,8f nop beq a0,HALP_SDC1,8f nop beq a0,HALP_LWC1,8f nop beq a0,HALP_LDC1,8f nop beq a0,HALP_LB,8f nop beq a0,HALP_LH,8f nop beq a0,HALP_LW,8f nop beq a0,HALP_LD,8f nop beq a0,HALP_LBU,8f nop beq a0,HALP_LHU,8f nop beq a0,HALP_SB,8f nop beq a0,HALP_SH,8f nop beq a0,HALP_SW,8f nop beq a0,HALP_SD,8f nop beq a0,HALP_LWL,8f nop beq a0,HALP_LWR,8f nop beq a0,HALP_LDL,8f nop beq a0,HALP_LDR,8f nop beq a0,HALP_LWU,8f nop beq a0,HALP_SDL,8f nop beq a0,HALP_SDR,8f nop beq a0,HALP_LWU,8f nop beq a0,HALP_SDL,8f nop beq a0,HALP_SDR,8f nop beq a0,HALP_LL,8f nop beq a0,HALP_SC,8f nop beq a0,HALP_SCD,8f nop move a0,t0 addu a0,a0,4 beq a2,zero,10b // try the next instruction (case of branch...) addu a2,a2,1 beq zero,zero,NotFoundAddr 8: // a1 = inst en erreur move a2,a1 li a3,HALP_RT2_REG and a2,a2,a3 srl a3,a2,HALP_RT2_SHIFT subu a3,1 // reg at has 1 as number sll a3,a3,0x2 // *4 la k0,SavedAt // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // addu k0,k0,a3 lw a3,0(k0) // contents of the register // // Try To find the physical address // a3 = virtual address // move a0,a3 srl a0,a0,30 // two upper bits li a2,0x2 // binary 10 beq a0,a2,FoundAddr // KSEG0 or KSEG1 addr nop // mapped address => try to find it in the TLB move a0,a3 mfc0 t1,entryhi // get current PID and VPN2 srl t2,a0,ENTRYHI_VPN2 // isolate VPN2 of virtual address sll t2,t2,ENTRYHI_VPN2 // and t1,t1,PID_MASK << ENTRYHI_PID // isolate current PID or t2,t2,t1 // merge PID with VPN2 of virtual address mtc0 t2,entryhi // set VPN2 and PID for probe nop // 3 cycle hazzard nop // nop // tlbp // probe for entry in TB nop // 2 cycle hazzard nop // mfc0 t3,index // read result of probe nop bltz t3,NotFoundAddr // if ltz, entry is not in TB sll a0,a0,0x1f - (ENTRYHI_VPN2 - 1) // shift VPN<12> into sign tlbr // read entry from TB nop // 3 cycle hazzard nop // nop // bltz a0,11f // if ltz, check second PTE mfc0 t2,entrylo1 // get second PTE for probe mfc0 t2,entrylo0 // get first PTE for probe 11: mtc0 t1,entryhi // restore current PID mtc0 zero,pagemask // restore page mask register // t2 = entrylo srl t2,t2,ENTRYLO_PFN sll t2,t2,PAGE_SHIFT li a2,PAGE_SIZE subu a2,a2,1 and a3,a3,a2 or a3,a3,t2 FoundAddr: // a3 = Physical addr li a2,0x1fffffff and a3,a3,a2 // 3 upper bits deleted la k0,SavedErrorEpc // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // lw a1,0(k0) // load error epc register lw a2,4(k0) // load cache error register // compute sip num sw a3,CiArgs0(sp) sw a1,CiArgs1(sp) sw a2,CiArgs2(sp) move a0,a3 la t0,HalpComputeNum li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // compute sip num nop lw a3,CiArgs2(sp) sw a3,0x10(sp) li a1,18 lw a2,CiArgs0(sp) ShowMsg: li a0,0x80 la t1,HalpKeBugCheck0 sw a0,0(t1) la t1,HalpKeBugCheck1 sw a1,0(t1) la t1,HalpKeBugCheck2 sw a2,0(t1) la t1,HalpKeBugCheck3 sw v0,0(t1) la t1,HalpKeBugCheck4 sw a3,0(t1) la t1,HalpBugCheckNumber sw a1,0(t1) la t0,KeBugCheckEx li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // move a3,v0 // sip num lw ra,CiRa(sp) // save return address addu sp,sp,CiFrameLength // allocate stack frame eret // NotFoundAddr: la a0,HalpAddrErrMsg and a0,a0,0x1fffffff or a0,a0,0xa0000000 la t0,HalDisplayString li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // nop move a3,a1 li a0,0x80 la k0,SavedErrorEpc // get address of register save area li k1,KSEG1_BASE // convert address of KSEG1 address or k0,k0,k1 // li a1,18 li a2,0x00 lw a3,4(k0) sw a3,0x10(sp) la t1,HalpKeBugCheck0 sw a0,0(t1) la t1,HalpKeBugCheck1 sw a1,0(t1) la t1,HalpKeBugCheck2 sw a2,0(t1) la t1,HalpKeBugCheck3 sw v0,0(t1) la t1,HalpKeBugCheck4 sw a3,0(t1) la t1,HalpBugCheckNumber sw a1,0(t1) la t0,KeBugCheckEx li k1,KSEG1_BASE // convert address of KSEG1 address or t0,t0,k1 // jal t0 // li a3,0xff lw ra,CiRa(sp) // save return address addu sp,sp,CiFrameLength // allocate stack frame eret // .set reorder .end HalpCacheErrorRoutine