## diffname gnot/fault.c 1990/03091 ## diff -e /dev/null /n/bootesdump/1990/03091/sys/src/9/68020/fault.c 0a #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "ureg.h" #include "errno.h" #define FORMAT(ur) ((((ur)->vo)>>12)&0xF) #define OFFSET(ur) (((ur)->vo)&0xFFF) struct FFrame { ushort ireg0; /* internal register */ ushort ssw; /* special status word */ ushort ipsc; /* instr. pipe stage c */ ushort ipsb; /* instr. pipe stage b */ ulong addr; /* data cycle fault address */ ushort ireg1; /* internal register */ ushort ireg2; /* internal register */ ulong dob; /* data output buffer */ ushort ireg3[4]; /* more stuff */ ulong baddr; /* stage b address */ ushort ireg4[26]; /* more more stuff */ }; /* * SSW bits */ #define RW 0x0040 /* read/write for data cycle */ #define FC 0x8000 /* fault on stage C of instruction pipe */ #define FB 0x4000 /* fault on stage B of instruction pipe */ #define RC 0x2000 /* rerun flag for stage C of instruction pipe */ #define RB 0x1000 /* rerun flag for stage B of instruction pipe */ #define DF 0x0100 /* fault/rerun flag for data cycle */ #define RM 0x0080 /* read-modify-write on data cycle */ #define READ 0x0040 #define WRITE 0x0000 #define SIZ 0x0030 /* size code for data cycle */ #define FC2 0x0004 /* address space for data cycle */ #define FC1 0x0002 #define FC0 0x0001 void fault(Ureg *ur, FFrame *f) { ulong addr, mmuvirt, mmuphys, n, badvaddr; Seg *s; PTE *opte, *pte, *npte; Orig *o; char *l; Page *pg; int zeroed = 0, head = 1; int i, user, read, insyscall; if(u == 0) panic("fault"); insyscall = u->p->insyscall; u->p->insyscall = 1; if(f->ssw & DF) addr = f->addr; else if(FORMAT(ur) == 0xA){ if(f->ssw & FC) addr = ur->pc+2; else if(f->ssw & FB) addr = ur->pc+4; else panic("prefetch pagefault"); }else if(FORMAT(ur) == 0xB){ if(f->ssw & FC) addr = f->baddr-2; else if(f->ssw & FB) addr = f->baddr; else panic("prefetch pagefault"); }else panic("prefetch format"); badvaddr = addr; addr &= ~(BY2PG-1); user = !(ur->sr&SUPER); if(f->ssw & DF) read = (f->ssw&READ) && !(f->ssw&RM); else read = f->ssw&(FB|FC); s = seg(u->p, addr); if(s == 0){ if(addr>USTKTOP){ cant: u->p->state = MMUing; if(user){ pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr); pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->sr, ur->pc, ur->sp); pexit("Suicide", 0); } dumpregs(ur); panic("fault"); exit(); } s = &u->p->seg[SSEG]; if(s->o==0 || addrmaxva-4*1024*1024 || addr>=s->maxva) goto cant; /* grow stack */ o = s->o; n = o->npte; growpte(o, (s->maxva-addr)>>PGSHIFT); /* stacks grown down, sigh */ lock(o); memcpy(o->pte+(o->npte-n), o->pte, n*sizeof(PTE)); memset(o->pte, 0, (o->npte-n)*sizeof(PTE)); unlock(o); s->minva = addr; o->va = addr; }else o = s->o; if(!read && (o->flag&OWRPERM)==0) goto cant; lock(o); opte = &o->pte[(addr-o->va)>>PGSHIFT]; pte = opte; if(s->mod){ while(pte = pte->nextmod) /* assign = */ if(pte->proc == u->p){ if(pte->page==0 || pte->page->va!=addr) panic("bad page %lux", pte->page); head = 0; break; } if(pte == 0) pte = opte; } if(pte->page == 0){ if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){ /* * Zero fill page. If we are really doing a copy-on-write * (e.g. into shared bss) we'll move the page later. */ pte->page = newpage(0, o, addr); o->npage++; zeroed = 1; }else{ /* * Demand load. Release o because it could take a while. */ unlock(o); n = (o->va+(o->maxca-o->minca)) - addr; if(n > BY2PG) n = BY2PG; pg = newpage(1, o, addr); qlock(o->chan); if(waserror()){ print("demand load i/o error %d\n", u->error.code); qunlock(o->chan); pg->o = 0; pg->ref--; goto cant; } o->chan->offset = (addr-o->va) + o->minca; l = (char*)(pg->pa|KZERO); if((*devtab[o->chan->type].read)(o->chan, l, n) != n) error(0, Eioload); qunlock(o->chan); poperror(); /* BUG: if was first page of bss, move to data */ if(npte[(addr-s->minva)>>PGSHIFT]; /* could move */ pte = opte; if(pte->page == 0){ pte->page = pg; o->npage++; }else{ /* someone beat us to it */ pg->o = 0; pg->ref--; } } } /* * Copy on reference */ if((o->flag & OWRPERM) && ((head && ((o->flag&OPURE) || o->nproc>1)) || (!head && pte->page->ref>1))){ /* * Look for the easy way out: are we the last non-modified? */ if(head && !(o->flag&OPURE)){ npte = opte; for(i=0; npte; i++) npte = npte->nextmod; if(i == o->nproc) goto easy; } if(head){ /* * Add to mod list */ pte = newmod(); pte->proc = u->p; pte->page = opte->page; pte->page->ref++; o->npage++; /* * Link into opte mod list (same va) */ pte->nextmod = opte->nextmod; opte->nextmod = pte; /* * Link into proc mod list (increasing va) */ npte = s->mod; if(npte == 0){ s->mod = pte; pte->nextva = 0; }else{ while(npte->nextva && npte->nextva->page->vanextva; pte->nextva = npte->nextva; npte->nextva = pte; } head = 0; } pg = pte->page; if(zeroed){ /* move page */ pg->ref--; o->npage--; opte->page = 0; }else{ /* copy page */ pte->page = newpage(1, o, addr); memcpy((void*)(pte->page->pa|KZERO), (void*)(pg->pa|KZERO), BY2PG); if(pg->ref <= 1) panic("pg->ref <= 1"); pg->ref--; } easy: mmuphys = 0; }else{ mmuphys = PTERONLY; if(o->flag & OWRPERM) if(o->flag & OPURE){ if(!head && pte->page->ref==1) mmuphys = 0; }else if((head && o->nproc==1) || (!head && pte->page->ref==1)) mmuphys = 0; } mmuvirt = addr; mmuphys |= PPN(pte->page->pa) | PTEVALID; usepage(pte->page, 1); if(pte->page->va != addr) panic("wrong addr in tail %lux %lux", pte->page->va, addr); if(pte->proc && pte->proc != u->p){ print("wrong proc in tail %d %s\n", head, u->p->text); print("u->p %lux pte->proc %lux\n", u->p, pte->proc); panic("addr %lux seg %d wrong proc in tail", addr, s-u->p->seg); } unlock(o); putmmu(mmuvirt, mmuphys); u->p->insyscall = insyscall; } /* * Called only in a system call */ void validaddr(ulong addr, ulong len, int write) { Seg *s; if((long)len < 0) panic("validaddr len %lux\n", len); s = seg(u->p, addr); if(s==0 || addr+len>s->maxva || (write && (s->o->flag&OWRPERM)==0)){ pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); postnote(u->p, 1, "bad address", NDebug); error(0, Ebadarg); } } /* * &s[0] is known to be a valid address. */ void* vmemchr(void *s, int c, int n) { int m; char *t; ulong a; a = (ulong)s; m = BY2PG - (a & (BY2PG-1)); if(m < n){ t = vmemchr(s, c, m); if(t) return t; if(!(a & KZERO)) validaddr(a+m, 1, 0); return vmemchr((void*)(a+m), c, n-m); } /* * All in one page */ return memchr(s, c, n); } Seg* seg(Proc *p, ulong addr) { int i; Seg *s; for(i=0,s=p->seg; io && s->minva<=addr && addrmaxva) return s; return 0; } . ## diffname gnot/fault.c 1990/0312 ## diff -e /n/bootesdump/1990/03091/sys/src/9/68020/fault.c /n/bootesdump/1990/0312/sys/src/9/68020/fault.c 277a Err: . 275c goto Err; . 85a /* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/ . ## diffname gnot/fault.c 1990/0315 ## diff -e /n/bootesdump/1990/0312/sys/src/9/68020/fault.c /n/bootesdump/1990/0315/sys/src/9/68020/fault.c 97a u->p->state = MMUing; . 92d ## diffname gnot/fault.c 1990/06021 ## diff -e /n/bootesdump/1990/0315/sys/src/9/68020/fault.c /n/bootesdump/1990/06021/sys/src/9/68020/fault.c 234c k = kmap(pte->page); k1 = kmap(pg); memcpy((void*)k->va, (void*)k1->va, BY2PG); kunmap(k); kunmap(k1); . 169a kunmap(k); poperror(); . 165d 161c l = (char*)k->va; . 154a kunmap(k); . 151a k = kmap(pg); . 58c panic("fault u==0 pc=%lux", ur->pc); . 53a KMap *k, *k1; . ## diffname gnot/fault.c 1990/0603 ## diff -e /n/bootesdump/1990/06021/sys/src/9/68020/fault.c /n/bootesdump/1990/0603/sys/src/9/68020/fault.c 59a } . 58c if(u == 0){ dumpregs(ur); . ## diffname gnot/fault.c 1990/0614 ## diff -e /n/bootesdump/1990/0603/sys/src/9/68020/fault.c /n/bootesdump/1990/0614/sys/src/9/68020/fault.c 242c memcpy((void*)VA(k), (void*)VA(k1), BY2PG); . 166c l = (char*)VA(k); . ## diffname gnot/fault.c 1990/0617 ## diff -e /n/bootesdump/1990/0614/sys/src/9/68020/fault.c /n/bootesdump/1990/0617/sys/src/9/68020/fault.c 295d 293a Again: s = seg(u->p, addr); if(s==0) goto Err; if(write && (s->o->flag&OWRPERM)==0) goto Err; if(addr+len > s->maxva){ len -= s->maxva - addr; addr = s->maxva; goto Again; } . 285,288c if((long)len < 0){ . 283c Seg *s, *ns; . ## diffname gnot/fault.c 1990/0724 ## diff -e /n/bootesdump/1990/0617/sys/src/9/68020/fault.c /n/bootesdump/1990/0724/sys/src/9/68020/fault.c 190c if((o->flag & OWRPERM) && !read . 188c * Copy on write . ## diffname gnot/fault.c 1990/0802 ## diff -e /n/bootesdump/1990/0724/sys/src/9/68020/fault.c /n/bootesdump/1990/0802/sys/src/9/68020/fault.c 113d 111a poperror(); . 110a lock(o); if(waserror()){ unlock(o); pprint("can't allocate stack page\n"); goto cant; } . ## diffname gnot/fault.c 1990/08101 ## diff -e /n/bootesdump/1990/0802/sys/src/9/68020/fault.c /n/bootesdump/1990/08101/sys/src/9/68020/fault.c 102c panic("fault: 0x%lux", badvaddr); . 81a addr &= VAMASK; . ## diffname gnot/fault.c 1990/0814 ## diff -e /n/bootesdump/1990/08101/sys/src/9/68020/fault.c /n/bootesdump/1990/0814/sys/src/9/68020/fault.c 120a lock(o); . 114d 112d ## diffname gnot/fault.c 1990/0821 ## diff -e /n/bootesdump/1990/0814/sys/src/9/68020/fault.c /n/bootesdump/1990/0821/sys/src/9/68020/fault.c 299,300c if(s==0){ s = &u->p->seg[SSEG]; if(s->o==0 || addrmaxva-USTACKSIZE || addr>=s->maxva) goto Err; } . 107c if(s->o==0 || addrmaxva-USTACKSIZE || addr>=s->maxva) . ## diffname gnot/fault.c 1990/0918 ## diff -e /n/bootesdump/1990/0821/sys/src/9/68020/fault.c /n/bootesdump/1990/0918/sys/src/9/68020/fault.c 176d ## diffname gnot/fault.c 1990/1110 ## diff -e /n/bootesdump/1990/0918/sys/src/9/68020/fault.c /n/bootesdump/1990/1110/sys/src/9/68020/fault.c 293c postnote(u->p, 1, "sys: bad address", NDebug); . 168a if(user) pexit("Interrupt", 0); . ## diffname gnot/fault.c 1990/1113 ## diff -e /n/bootesdump/1990/1110/sys/src/9/68020/fault.c /n/bootesdump/1990/1113/sys/src/9/68020/fault.c 169,171c pexit("load i/o error", 0); . ## diffname gnot/fault.c 1990/11211 ## diff -e /n/bootesdump/1990/1113/sys/src/9/68020/fault.c /n/bootesdump/1990/11211/sys/src/9/68020/fault.c 294c error(Ebadarg); . 174c error(Eioload); . 164c print("demand load i/o error %s\n", u->error); . ## diffname gnot/fault.c 1990/1126 ## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/fault.c /n/bootesdump/1990/1126/sys/src/9/68020/fault.c 63a addr = 0; /* set */ . ## diffname gnot/fault.c 1990/1202 ## diff -e /n/bootesdump/1990/1126/sys/src/9/68020/fault.c /n/bootesdump/1990/1202/sys/src/9/68020/fault.c 165d ## diffname gnot/fault.c 1990/1212 # deleted ## diff -e /n/bootesdump/1990/1202/sys/src/9/68020/fault.c /n/bootesdump/1990/1212/sys/src/9/68020/fault.c 1,347d