123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "ureg.h"
- #include "../port/error.h"
- #include "io.h"
- enum {
- Debug = 0,
- };
- typedef struct Fault Fault;
- struct Fault {
- uintptr va;
- ulong pid;
- uintptr pc;
- int cnt;
- char *prog;
- int code;
- };
- extern char *excname[];
- static Fault lflt, maxflt;
- /*
- * Ask if the instruction at EPC could have cause this badvaddr
- */
- int
- tstbadvaddr(Ureg *ur)
- {
- int rn;
- ulong iw, off, ea;
- iw = ur->pc;
- if(ur->cause & BD)
- iw += 4;
- if(seg(up, iw, 0) == 0)
- return 0;
- iw = *(ulong*)iw;
- /* print("iw: %#lux\n", iw); /**/
- switch((iw>>26) & 0x3f) {
- default:
- return 1;
- case 0x20: /* LB */
- case 0x24: /* LBU */
- /* LD */
- case 0x35:
- case 0x36:
- case 0x37: /* LDCz */
- case 0x1A: /* LDL */
- case 0x1B: /* LDR */
- case 0x21: /* LH */
- case 0x25: /* LHU */
- case 0x30: /* LL */
- case 0x34: /* LLD */
- case 0x23: /* LW */
- case 0x31:
- case 0x32: /* LWCz possible 0x33 */
- case 0x27: /* LWU */
- case 0x22: /* LWL */
- case 0x26: /* LWR */
- break;
- case 0x28: /* SB */
- case 0x38: /* SC */
- case 0x3C: /* SCD */
- case 0x3D:
- case 0x3E:
- case 0x3F: /* SDCz */
- case 0x2C: /* SDL */
- case 0x2D: /* SDR */
- case 0x29: /* SH */
- case 0x2B: /* SW */
- case 0x39:
- case 0x3A: /* SWCz */
- case 0x2A: /* SWL */
- case 0x2E: /* SWR */
- break;
- }
- off = iw & 0xffff;
- if(off & 0x8000)
- off |= ~0xffff;
- rn = (iw>>21) & 0x1f;
- ea = *reg(ur, rn);
- if(rn == 0)
- ea = 0;
- ea += off;
- /* print("ea %#lux %#lux(R%d) bv %#lux pc %#lux\n", ea, off, rn, ur->badvaddr, ur->pc); /**/
- if(ur->badvaddr == ea)
- return 0;
- return 1;
- }
- /*
- * we think we get consecutive page faults from unlucky combinations of
- * scheduling and stlb hashes, and they only happen with 16K pages.
- * however, we also get page faults while servicing the exact same fault.
- * more than 5 consecutive faults is unusual, now that we have a better
- * hash function.
- *
- * this can be helpful during mmu and cache debugging.
- */
- static int
- ckfaultstuck(Ureg *ur, int read, int code)
- {
- uintptr pc, va;
- va = ur->badvaddr;
- pc = ur->pc;
- if (va != lflt.va || up->pid != lflt.pid || pc != lflt.pc ||
- code != lflt.code) {
- /* at least one address or cause is different from last time */
- lflt.cnt = 1;
- lflt.va = va;
- lflt.pid = up->pid;
- lflt.pc = pc;
- lflt.code = code;
- return 0;
- }
- ++lflt.cnt;
- if (lflt.cnt >= 1000) /* fixfault() isn't fixing underlying cause? */
- panic("fault: %d consecutive faults for va %#p", lflt.cnt, va);
- if (lflt.cnt > maxflt.cnt) {
- maxflt.cnt = lflt.cnt;
- maxflt.va = va;
- maxflt.pid = up->pid;
- maxflt.pc = pc;
- kstrdup(&maxflt.prog, up->text);
- }
- /* we're servicing that fault now! */
- /* adjust the threshold and program name to suit */
- if (lflt.cnt < 5 || strncmp(up->text, "8l", 2) != 0)
- return 0;
- iprint("%d consecutive faults for va %#p at pc %#p in %s "
- "pid %ld\n", lflt.cnt, lflt.va, pc, up->text, lflt.pid);
- iprint("\t%s: %s%s r31 %#lux tlbvirt %#lux\n",
- excname[code], va == pc? "[instruction] ": "",
- (read? "read": "write"), ur->r31, tlbvirt());
- return 0;
- }
- char *
- faultsprint(char *p, char *ep)
- {
- if (Debug)
- p = seprint(p, ep,
- "max consecutive faults %d for va %#p in %s\n",
- maxflt.cnt, maxflt.va, maxflt.prog);
- return p;
- }
- /*
- * find out fault address and type of access.
- * Call common fault handler.
- */
- void
- faultmips(Ureg *ur, int user, int code)
- {
- int read;
- ulong addr;
- char *p, buf[ERRMAX];
- static int infault, printed;
- if (0 && infault && !printed) {
- printed = 1;
- print("fault: recursive fault (%d deep) pc %#p va %#p\n",
- infault+1, ur->pc, ur->badvaddr);
- }
- infault++;
- if(waserror()){
- infault--;
- nexterror();
- }
- addr = ur->badvaddr;
- addr &= ~(BY2PG-1);
- read = !(code==CTLBM || code==CTLBS);
- /* print("fault: %s code %d va %#p pc %#p r31 %#lux tlbvirt %#lux\n",
- up->text, code, ur->badvaddr, ur->pc, ur->r31, tlbvirt());/**/
- if (Debug && ckfaultstuck(ur, read, code) || fault(addr, read) == 0){
- infault--;
- poperror();
- return;
- }
- infault--;
- poperror();
- if(tstbadvaddr(ur)) {
- print("fault: spurious badvaddr %#lux in %s at pc %#lux\n",
- ur->badvaddr, up->text, ur->pc);/**/
- return;
- }
- if(user) {
- p = "store";
- if(read)
- p = "load";
- snprint(buf, sizeof buf, "sys: trap: fault %s addr=%#lux r31=%#lux",
- p, ur->badvaddr, ur->r31);
- postnote(up, 1, buf, NDebug);
- return;
- }
- print("kernel %s vaddr=%#lux\n", excname[code], ur->badvaddr);
- print("st=%#lux pc=%#lux r31=%#lux sp=%#lux\n",
- ur->status, ur->pc, ur->r31, ur->sp);
- dumpregs(ur);
- panic("fault");
- }
- /*
- * called in sysfile.c
- */
- void
- evenaddr(ulong addr)
- {
- if(addr & 3){
- postnote(up, 1, "sys: odd address", NDebug);
- error(Ebadarg);
- }
- }
|