📄 kn230.c
字号:
kn230_trans_errcnt.trans_last = 0; currtime = 0; } log_kn230mem(ep, EL_PRIHIGH, pa, memreg); kn230_trans_errcnt.trans_prev = kn230_trans_errcnt.trans_last; kn230_trans_errcnt.trans_last = currtime; } return(0); } pagetype = cmap[pgtocm(btop(pa))].c_type; if (SHAREDPG(pagetype)) { log_kn230mem(ep, EL_PRISEVERE, pa,memreg); kn230consprint(MEMPKT, ep, pa); panic("memory parity error in shared page"); } else { log_kn230mem(ep, EL_PRIHIGH, pa,memreg); printf("pid %d (%s) was killed on memory parity error\n",p->p_pid, u.u_comm); uprintf("pid %d (%s) was killed on memory parity error\n",p->p_pid, u.u_comm); } } else { uprintf("pid %d (%s) was killed on bus read error\n", p->p_pid, u.u_comm); } } else { /* * Kernel mode errors. * They all panic, its just a matter of what we log * and what panic message we issue. */ switch (code) { case EXC_DBE: case EXC_IBE: /* * Figure out if its a memory parity error * or a read bus timeout error */ pa = vatophys(ep[EF_BADVADDR]); if ( (int)pa != -1 && (btop((int)pa) < kn230_physmem)) { /* * Note: must save anything "interesting" * from the exception frame, since * kn230_isolatepar() may cause * additional bus errors which will * stomp on the exception frame in locore. */ vaddr = ep[EF_BADVADDR]; epc = ep[EF_EPC]; memreg = kn230_isolatepar(pa, vaddr); ep[EF_BADVADDR] = vaddr; ep[EF_EPC] = epc; log_kn230mem(ep, EL_PRISEVERE, pa,memreg); kn230consprint(MEMPKT, ep, pa); panic("memory parity error in kernel mode"); } else { log_kn230esr(ep, EL_PRISEVERE); kn230consprint(ESRPKT, ep, 0); panic("bus timeout"); } break; case EXC_CPU: log_kn230esr(ep, EL_PRISEVERE); kn230consprint(ESRPKT, ep, 0); panic("coprocessor unusable"); break; case EXC_RADE: case EXC_WADE: log_kn230esr(ep, EL_PRISEVERE); kn230consprint(ESRPKT, ep, 0); panic("unaligned access"); break; default: log_kn230esr(ep, EL_PRISEVERE); kn230consprint(ESRPKT, ep, 0); panic("trap"); break; } } /* * Default user-mode action is to terminate the process */ *signo = SIGBUS; return(0);}/***************************************************************************** * * kn230_memintr: Entry for WMERR interupt -- write to a non-existent address * * This does not happen synchronously (buffered write), * therefore we are not in process context and cannot terminate * a user process. We must crash the system. * *****************************************************************************/kn230_memintr(ep) u_int *ep; /* exception frame ptr */{ volatile unsigned int icsr; /* * read icsr and clear error */ icsr = *(int *)ICSR_ADDR; *(int *)ICSR_ADDR |= KN230_WMERR ; /* * save the state of the system registers for * error logging. * */ kn230_esr_icsr = icsr; kn230_esr_leds = *(int *)LED_ADDR; kn230_esr_wear = *(int *)WEAR_ADDR; kn230_esr_oid = *(int *)OID_ADDR; if ( icsr & KN230_WMERR) { log_kn230esr(ep, EL_PRISEVERE); kn230consprint(ESRPKT, ep, 0); panic("NXM - write to non-existant memory"); } else { log_kn230esr(ep, EL_PRISEVERE); kn230consprint(ESRPKT, ep, 0); panic("stray memory error interrupt"); } }/***************************************************************************** * * kn230consprint: print error information to console * *****************************************************************************/kn230consprint(packet_type, ep, pa)int packet_type; /* ESR or MEM type error */register u_int *ep; /* exception frame pointer */unsigned pa; /* phys addr of MEM error */{ switch (packet_type) { case ESRPKT: cprintf("\nException condition\n"); break; case MEMPKT: cprintf("\nMemory Error\n"); break; default: cprintf("bad consprint - no packet_type given\n"); break; } cprintf("\tCause reg\t\t= 0x%x\n", ep[EF_CAUSE]); cprintf("\tException PC\t\t= 0x%x\n", ep[EF_EPC]); cprintf("\tStatus reg\t\t= 0x%x\n", ep[EF_SR]); cprintf("\tBad virt addr\t\t= 0x%x\n", ep[EF_BADVADDR]); cprintf("\tInterupt CSR reg\t= 0x%x\n", *(int *)ICSR_ADDR); cprintf("\tWrite Error Add reg\t= 0x%x\n", *(int *)WEAR_ADDR); cprintf("\tLED reg\t\t\t= 0x%x\n", *(int *)LED_ADDR); cprintf("\tOption ID reg\t\t= 0x%x\n", *(int *)OID_ADDR); if (pa) cprintf("\tPhysical address of error: 0x%x\n",pa);}/***************************************************************************** * * log_kn230esr: Log Error & Status Registers to the error log buffer * *****************************************************************************/log_kn230esr(ep, priority) register u_int *ep; /* exception frame ptr */ int priority; /* for pkt priority */{ struct el_rec *elrp; elrp = ealloc(sizeof(struct el_esr5100), priority); if (elrp != NULL) { LSUBID(elrp,ELCT_ESR,ELESR_5100,EL_UNDEF,EL_UNDEF,EL_UNDEF,EL_UNDEF); elrp->el_body.elesr.elesr.el_esr5100.esr_cause = ep[EF_CAUSE]; elrp->el_body.elesr.elesr.el_esr5100.esr_epc = ep[EF_EPC]; elrp->el_body.elesr.elesr.el_esr5100.esr_status = ep[EF_SR]; elrp->el_body.elesr.elesr.el_esr5100.esr_badva = ep[EF_BADVADDR]; elrp->el_body.elesr.elesr.el_esr5100.esr_sp = ep[EF_SP]; elrp->el_body.elesr.elesr.el_esr5100.esr_icsr = kn230_esr_icsr; elrp->el_body.elesr.elesr.el_esr5100.esr_leds = kn230_esr_leds; elrp->el_body.elesr.elesr.el_esr5100.esr_wear = kn230_esr_wear; elrp->el_body.elesr.elesr.el_esr5100.esr_oid = kn230_esr_oid; EVALID(elrp); }}/***************************************************************************** * * log_kn230mem: Log a memory error packet, so uerf can find it as a * main memory error. * *****************************************************************************/log_kn230mem(ep, priority, pa, memreg) register u_int *ep; /* exception frame ptr */ int priority; /* pkt priority: panic: severe; else: high */ int pa; /* physical addr where memory err occured */ unsigned memreg; /* parity error information */{ struct el_rec *elrp; register struct el_mem *mrp; elrp = ealloc(EL_MEMSIZE, priority); if (elrp != NULL) { LSUBID(elrp,ELCT_MEM,EL_UNDEF,ELMCNTR_5100,EL_UNDEF,EL_UNDEF,EL_UNDEF); mrp = &elrp->el_body.elmem; mrp->elmem_cnt = 1; mrp->elmemerr.cntl = 1; mrp->elmemerr.type = ELMETYP_PAR; mrp->elmemerr.numerr = 1; mrp->elmemerr.regs[0] = memreg; mrp->elmemerr.regs[1] = pa; mrp->elmemerr.regs[2] = ep[EF_EPC]; mrp->elmemerr.regs[3] = ep[EF_BADVADDR]; EVALID(elrp); }}/**************************************************************************** * * kn230_isolatepar: * * Overall goal here is to be able to recover a user process if the * parity error was a soft error, and to log additional information. * * Isolate a memory parity error to which SIMM is in error. * This routine is machine specific, in that it "knows" how the memory * is laid out, i.e. how to convert a physical address to a module number. * * Block faults from occuring while we isolate the parity error by using * "nofault" facility thru the bbadaddr routine. * ****************************************************************************/unsigned kn230_isolatepar(pa, va) register caddr_t pa; /* the phys addr to convert to a SIMM */ caddr_t va; /* the virtual addr of the error */ { register int i; /* loop index */ register char *addr; /* increment thru the word w/ parity error */ register char *k1_addr; /* kseg1 addr. for mem test writes */ unsigned memreg; /* collection of memory error info */ int odd; /* true if its the odd numbered SIMM */ int simm; /* which simm had the error */ register int allzeros; /* true if parity err occurs on all 0's write*/ register int allones; /* true if parity err occurs on all 1's write*/ register int oneone; /* true if parity err occurs on 1 1 write */ int dp; /* 0 for data bit, 1 for parity bit */ int type; /* error type: transient, soft, hard */ int byte; /* 0 for low byte; 1 for high byte in word */ /* * Round address down to long word, & clear flags. */ addr = (char *)((int)va & (~0x3)); type = 0; dp = 0; /* * Do badaddr probe on addr (a few times), * to see if it was only a transient. */ kn230_parityerr = 0; for (i = 0; i < 4; i++) { if (bbadaddr(addr, 4)) { kn230_parityerr = 1; break; } } if (!kn230_parityerr) { type = TRANSPAR; byte = 0; odd = 1; goto getsimm; } /* * Isolate the parity error to which SIMM is in error (which byte in * the word) and isolate the type of error: soft or hard, data bit * or parity bit. * * This is done by writing (& reading) each byte in the word first * with all 0's then with all 1's (0xff) then with one 1 (0x1). * * Use k1_addr in order not to get TLBMOD exception when writing * shared memory space * */ k1_addr = (char *)(PHYS_TO_K1(((int)pa & (~0x3)))); /*lw addr*/ for (i = 0; i < 4; i++, addr += 1) { allzeros = 0; *k1_addr = 0x00; if (bbadaddr(addr, 1)) allzeros = 1; allones = 0; *k1_addr = 0xff; if (bbadaddr(addr, 1)) allones = 1; oneone = 0; *k1_addr = 0x1; if (bbadaddr(addr, 1)) oneone = 1; /* * If all 3 reads caused the error then this is the wrong * byte, go on to the next byte */ if (allzeros && allones && oneone) continue; /* * If only one of the allones/allzeros patterns caused a * parity error, then we have a hard data bit stuck to * zero or one. */ if ((allzeros && !allones && !oneone) || (allones && !allzeros && !oneone)) { type = HARDPAR; break; } /* * If only the "oneone" (0x1) pattern caused a parity error, * then we have a parity bit stuck to zero. * If only the "oneone" (0x1) pattern did NOT cause a parity * error then we have a parity bit stuck to one. */ if ((oneone && !allzeros && !allones) || (allzeros && allones && !oneone)) { type = HARDPAR; dp = 1; break; } /* * If no parity error on all 3 patterns then we had a soft * parity error in one of the data bits or in the parity bit * of this byte. */ if (!allzeros && !allones && !oneone) { type = SOFTPAR; break; } } /* * If i is 0 or 1, parity error is on the odd SIMM. * If i is 2 or 3, parity error is on the even SIMM. * Also record high or low byte position in half-word. */ switch (i) { case 0: byte = 0; odd = 1; break; case 1: byte = 1; odd = 1; break; case 2: byte = 0; odd = 0; break; case 3: default: byte = 1; odd = 0; break; }getsimm: /* * Record which SIMM */ if ((int)pa < kn230_bank1*1024*1024) if (odd) simm = 1; else simm = 2; else if ((int)pa < (kn230_bank1+kn230_bank2)*1024*1024) if (odd) simm = 3; else simm = 4; else if ((int)pa < (kn230_bank1+kn230_bank2+kn230_bank3)*1024*1024) if (odd) simm = 5; else simm = 6; else if ((int)pa < (kn230_bank1+kn230_bank2+kn230_bank3+kn230_bank4)*1024*1024) if (odd) simm = 7; else simm = 8; /* * Increment error counts */ switch (type) { case TRANSPAR: default: tcount[simm]++; if (tcount[simm] > 255) { mprintf("Transient parity error count on simm # %d reached 255, reset to zero.\n", simm); tcount[simm] = 0; } break; case SOFTPAR: scount[simm]++; break; case HARDPAR: hcount[simm]++; break; } memreg = MEMREGFMT(simm, type, byte, dp, tcount[simm], scount[simm], hcount[simm]); return(memreg);}/**************************************************************************** * * kn230_getSIMMsizes: Function is to identify the size of each of the * four banks of the kn230 SIMM memory. This info * is necessary for kn230_isolatepar, which uses it * to report which SIMM the parity error occured on.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -