| plan 9 kernel history: overview | file list | diff list |
1991/0427/port/fault.c (diff list | history)
| port/fault.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "ureg.h" #include "errno.h" | |
| 1990/1212 | int fault(ulong addr, int read) | |
| 1990/0227 | { | |
| 1990/1212 | ulong mmuvirt, mmuphys, n; | |
| 1990/0227 | Seg *s; PTE *opte, *pte, *npte; Orig *o; char *l; Page *pg; int zeroed = 0, head = 1; | |
| 1991/0425 | int i, touched = 0; | |
| 1990/1212 | KMap *k, *k1; | |
| 1990/0227 | ||
| 1991/0427 | m->pfault++; | |
| 1990/0227 | s = seg(u->p, addr); if(s == 0){ | |
| 1991/0110 | if(addr > USTKTOP) | |
| 1990/1212 | return -1; | |
| 1990/0227 | s = &u->p->seg[SSEG]; | |
| 1990/0821 | if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva) | |
| 1990/1212 | return -1; | |
| 1990/0227 | /* grow stack */ o = s->o; n = o->npte; | |
| 1990/0802 | if(waserror()){ pprint("can't allocate stack page\n"); | |
| 1990/1212 | return -1; | |
| 1990/0802 | } | |
| 1990/0227 | growpte(o, (s->maxva-addr)>>PGSHIFT); | |
| 1990/0802 | poperror(); | |
| 1990/0227 | /* stacks grown down, sigh */ | |
| 1990/0814 | lock(o); | |
| 1991/0318 | memmove(o->pte+(o->npte-n), o->pte, n*sizeof(PTE)); | |
| 1990/0227 | memset(o->pte, 0, (o->npte-n)*sizeof(PTE)); unlock(o); s->minva = addr; o->va = addr; }else o = s->o; | |
| 1990/1212 | if(!read && (o->flag&OWRPERM)==0) return -1; | |
| 1990/0227 | 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){ | |
| 1991/0425 | touched = 1; | |
| 1990/0227 | 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); | |
| 1990/1212 | k = kmap(pg); | |
| 1991/0411 | qlock(&o->chan->rdl); | |
| 1990/0227 | if(waserror()){ | |
| 1990/1212 | kunmap(k); | |
| 1991/0411 | qunlock(&o->chan->rdl); | |
| 1990/0227 | pg->o = 0; pg->ref--; | |
| 1990/1113 | pexit("load i/o error", 0); | |
| 1990/0227 | } | |
| 1990/1212 | l = (char*)VA(k); | |
| 1991/0411 | if((*devtab[o->chan->type].read)(o->chan, l, n, (addr-o->va) + o->minca) != n) | |
| 1990/11211 | error(Eioload); | |
| 1991/0312 | flushpage(pg->pa); | |
| 1991/0411 | qunlock(&o->chan->rdl); | |
| 1990/0227 | if(n<BY2PG) memset(l+n, 0, BY2PG-n); lock(o); | |
| 1990/1212 | kunmap(k); poperror(); | |
| 1990/0227 | opte = &o->pte[(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--; } } } /* | |
| 1990/1212 | * Copy on reference (conf.copymode==1) or write (conf.copymode==0) | |
| 1990/0227 | */ | |
| 1990/1212 | if((o->flag & OWRPERM) && (conf.copymode || !read) | |
| 1990/0227 | && ((head && ((o->flag&OPURE) || o->nproc>1)) || (!head && pte->page->ref>1))){ | |
| 1991/0425 | touched = 1; | |
| 1990/0227 | /* * 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 */ | |
| 1990/1013 | pte = newmod(o); | |
| 1990/0227 | 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->va<addr) npte = npte->nextva; 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); | |
| 1990/1212 | k = kmap(pte->page); k1 = kmap(pg); | |
| 1991/0318 | memmove((void*)VA(k), (void*)VA(k1), BY2PG); | |
| 1990/1212 | kunmap(k); kunmap(k1); | |
| 1990/0227 | if(pg->ref <= 1) panic("pg->ref <= 1"); pg->ref--; } easy: mmuphys = PTEWRITE; }else{ | |
| 1990/1212 | mmuphys = PTERONLY; | |
| 1990/0227 | if(o->flag & OWRPERM) if(o->flag & OPURE){ if(!head && pte->page->ref==1) mmuphys = PTEWRITE; }else if((head && o->nproc==1) || (!head && pte->page->ref==1)) mmuphys = PTEWRITE; } mmuvirt = addr; | |
| 1990/1212 | mmuphys |= PPN(pte->page->pa) | PTEVALID; | |
| 1990/0227 | 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); | |
| 1991/0425 | if(touched == 0) m->tlbfault++; | |
| 1990/0227 | putmmu(mmuvirt, mmuphys); | |
| 1990/1212 | return 0; | |
| 1990/0227 | } /* * Called only in a system call */ void validaddr(ulong addr, ulong len, int write) { | |
| 1990/0617 | Seg *s, *ns; | |
| 1990/0227 | ||
| 1990/0617 | if((long)len < 0){ | |
| 1990/0312 | Err: | |
| 1991/0115 | pprint("invalid address %lux in sys call pc %lux sp %lux\n", addr, ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); | |
| 1990/1110 | postnote(u->p, 1, "sys: bad address", NDebug); | |
| 1990/11211 | error(Ebadarg); | |
| 1990/0617 | } Again: s = seg(u->p, addr); | |
| 1990/0821 | if(s==0){ s = &u->p->seg[SSEG]; if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva) goto Err; } | |
| 1990/0617 | if(write && (s->o->flag&OWRPERM)==0) goto Err; if(addr+len > s->maxva){ len -= s->maxva - addr; addr = s->maxva; goto Again; | |
| 1990/0227 | } } /* * &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; i<NSEG; i++,s++) if(s->o && s->minva<=addr && addr<s->maxva) return s; return 0; } | |