| plan 9 kernel history: overview | file list | diff list |
1992/1001/port/fault.c (diff list | history)
| port/fault.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | ||
| 1992/0114 | void faulterror(char*); | |
| 1991/1105 | ||
| 1990/1212 | int fault(ulong addr, int read) | |
| 1990/0227 | { | |
| 1991/0705 | Segment *s; | |
| 1991/0926 | char *sps; | |
| 1990/0227 | ||
| 1991/0926 | sps = u->p->psstate; u->p->psstate = "Fault"; | |
| 1992/0602 | spllo(); | |
| 1991/0926 | ||
| 1991/0427 | m->pfault++; | |
| 1991/1109 | for(;;) { s = seg(u->p, addr, 1); if(s == 0) { u->p->psstate = sps; return -1; } | |
| 1991/0705 | ||
| 1991/1109 | if(!read && (s->type&SG_RONLY)) { qunlock(&s->lk); u->p->psstate = sps; return -1; } if(fixfault(s, addr, read, 1) == 0) break; | |
| 1990/0227 | } | |
| 1991/0705 | ||
| 1991/1109 | u->p->psstate = sps; return 0; } int fixfault(Segment *s, ulong addr, int read, int doputmmu) { ulong mmuphys=0, soff; | |
| 1992/0805 | Page **pg, *lkp, *new; | |
| 1991/1122 | Pte **p, *etp; | |
| 1991/1109 | int type; | |
| 1991/0705 | addr &= ~(BY2PG-1); soff = addr-s->base; p = &s->map[soff/PTEMAPMEM]; if(*p == 0) *p = ptealloc(); | |
| 1991/1122 | etp = *p; pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG]; | |
| 1991/0705 | type = s->type&SG_TYPE; | |
| 1991/1122 | if(pg < etp->first) etp->first = pg; if(pg > etp->last) etp->last = pg; | |
| 1991/0705 | switch(type) { | |
| 1992/0307 | default: panic("fault"); | |
| 1992/0319 | break; | |
| 1992/0307 | ||
| 1991/0705 | case SG_TEXT: | |
| 1992/0430 | if(pagedout(*pg)) /* Demand load */ | |
| 1991/0705 | pio(s, addr, soff, pg); mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; (*pg)->modref = PG_REF; break; | |
| 1992/0302 | ||
| 1992/0430 | case SG_SHDATA: /* Shared data */ | |
| 1992/0307 | if(pagedout(*pg)) pio(s, addr, soff, pg); goto done; | |
| 1991/0705 | case SG_BSS: | |
| 1992/0430 | case SG_SHARED: /* Zero fill on demand */ | |
| 1991/0705 | case SG_STACK: | |
| 1992/0103 | if(*pg == 0) { | |
| 1992/0805 | new = newpage(1, &s, addr); | |
| 1992/0302 | if(s == 0) | |
| 1991/1109 | return -1; | |
| 1992/0307 | ||
| 1991/0705 | *pg = new; | |
| 1990/0227 | } | |
| 1991/1113 | /* NO break */ | |
| 1992/0302 | ||
| 1992/0430 | case SG_DATA: /* Demand load/pagein/copy on write */ | |
| 1991/0705 | if(pagedout(*pg)) pio(s, addr, soff, pg); | |
| 1992/0307 | ||
| 1991/0705 | if(type == SG_SHARED) goto done; | |
| 1991/0607 | ||
| 1992/0629 | if(read && conf.copymode == 0) { | |
| 1991/0705 | mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; (*pg)->modref |= PG_REF; break; | |
| 1990/0227 | } | |
| 1991/0705 | lkp = *pg; | |
| 1992/0625 | lock(lkp); | |
| 1991/0705 | if(lkp->ref > 1) { | |
| 1992/0625 | unlock(lkp); | |
| 1992/0805 | new = newpage(0, &s, addr); | |
| 1992/0302 | if(s == 0) | |
| 1991/1109 | return -1; | |
| 1991/0705 | *pg = new; copypage(lkp, *pg); putpage(lkp); | |
| 1990/0227 | } | |
| 1991/0705 | else { /* put a duplicate of a text page back onto the free list */ if(lkp->image) duppage(lkp); | |
| 1992/0625 | unlock(lkp); | |
| 1990/0227 | } | |
| 1991/0705 | done: mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEVALID; (*pg)->modref = PG_MOD|PG_REF; break; | |
| 1992/0302 | ||
| 1991/0705 | case SG_PHYSICAL: if(*pg == 0) *pg = (*s->pgalloc)(addr); | |
| 1991/0606 | ||
| 1991/0705 | mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEUNCACHED|PTEVALID; (*pg)->modref = PG_MOD|PG_REF; break; | |
| 1990/0227 | } | |
| 1991/0608 | ||
| 1991/1110 | if(s->flushme) memset((*pg)->cachectl, PG_TXTFLUSH, sizeof(new->cachectl)); | |
| 1991/0705 | qunlock(&s->lk); | |
| 1991/0719 | ||
| 1991/1109 | if(doputmmu) putmmu(addr, mmuphys, *pg); | |
| 1991/0705 | return 0; } void pio(Segment *s, ulong addr, ulong soff, Page **p) { Page *new; KMap *k; Chan *c; int n, ask; char *kaddr; ulong daddr; Page *loadrec; loadrec = *p; if(loadrec == 0) { | |
| 1991/0709 | daddr = s->fstart+soff; /* Compute disc address */ | |
| 1991/0705 | new = lookpage(s->image, daddr); | |
| 1990/0227 | } | |
| 1991/0705 | else { daddr = swapaddr(loadrec); new = lookpage(&swapimage, daddr); if(new) putswap(loadrec); } | |
| 1991/0607 | ||
| 1991/0709 | if(new) { /* Page found from cache */ | |
| 1991/0705 | *p = new; return; } | |
| 1991/0607 | ||
| 1991/0705 | qunlock(&s->lk); new = newpage(0, 0, addr); k = kmap(new); kaddr = (char*)VA(k); if(loadrec == 0) { /* This is demand load */ c = s->image->c; | |
| 1991/0906 | while(waserror()) { | |
| 1992/0111 | if(strcmp(u->error, Eintr) == 0) | |
| 1991/0906 | continue; | |
| 1991/0705 | kunmap(k); putpage(new); | |
| 1992/0114 | faulterror("sys: demand load I/O error"); | |
| 1991/0705 | } ask = s->flen-soff; if(ask > BY2PG) ask = BY2PG; | |
| 1992/0319 | ||
| 1991/0705 | n = (*devtab[c->type].read)(c, kaddr, ask, daddr); if(n != ask) error(Eioload); if(ask < BY2PG) memset(kaddr+ask, 0, BY2PG-ask); poperror(); kunmap(k); qlock(&s->lk); if(*p == 0) { /* Someone may have got there first */ new->daddr = daddr; cachepage(new, s->image); *p = new; } else putpage(new); } else { /* This is paged out */ c = swapimage.c; if(waserror()) { kunmap(k); putpage(new); qlock(&s->lk); qunlock(&s->lk); | |
| 1992/0114 | faulterror("sys: page in I/O error"); | |
| 1991/0705 | } n = (*devtab[c->type].read)(c, kaddr, BY2PG, daddr); if(n != BY2PG) error(Eioload); poperror(); kunmap(k); qlock(&s->lk); if(pagedout(*p)) { new->daddr = daddr; cachepage(new, &swapimage); putswap(*p); *p = new; } else putpage(new); } | |
| 1991/1105 | } void | |
| 1992/0114 | faulterror(char *s) | |
| 1991/1105 | { | |
| 1992/1001 | print("faulterror %s\n", s); | |
| 1991/1105 | if(u->nerrlab) { postnote(u->p, 1, s, NDebug); | |
| 1992/0114 | error(s); | |
| 1991/1105 | } pexit(s, 0); | |
| 1990/0227 | } /* * Called only in a system call */ | |
| 1992/0616 | int okaddr(ulong addr, ulong len, int write) | |
| 1990/0227 | { | |
| 1991/0705 | Segment *s; | |
| 1990/0227 | ||
| 1991/0705 | if((long)len >= 0) { for(;;) { s = seg(u->p, addr, 0); if(s == 0 || (write && (s->type&SG_RONLY))) break; if(addr+len > s->top) { len -= s->top - addr; addr = s->top; continue; } | |
| 1992/0616 | return 1; | |
| 1991/0705 | } | |
| 1990/0617 | } | |
| 1992/0812 | pprint("suicide: invalid address 0x%lux in sys call pc=0x%lux\n", addr, userpc()); | |
| 1992/0616 | return 0; } void validaddr(ulong addr, ulong len, int write) { if(!okaddr(addr, len, write)) pexit("Suicide", 0); | |
| 1991/0705 | } | |
| 1990/0227 | /* * &s[0] is known to be a valid address. */ void* | |
| 1991/0705 | vmemchr(void *s, int c, int n) | |
| 1990/0227 | { int m; char *t; ulong a; a = (ulong)s; m = BY2PG - (a & (BY2PG-1)); | |
| 1991/0705 | if(m < n){ t = vmemchr(s, c, m); | |
| 1990/0227 | if(t) return t; if(!(a & KZERO)) validaddr(a+m, 1, 0); | |
| 1991/0705 | return vmemchr((void*)(a+m), c, n-m); | |
| 1990/0227 | } | |
| 1991/0705 | /* * All in one page */ return memchr(s, c, n); | |
| 1990/0227 | } | |
| 1991/0705 | Segment* seg(Proc *p, ulong addr, int dolock) | |
| 1990/0227 | { | |
| 1991/0705 | Segment **s, **et, *n; | |
| 1990/0227 | ||
| 1991/0606 | et = &p->seg[NSEG]; | |
| 1991/0705 | for(s = p->seg; s < et; s++) | |
| 1991/0927 | if(n = *s){ if(addr >= n->base && addr < n->top) { if(dolock == 0) return n; qlock(&n->lk); if(addr >= n->base && addr < n->top) return n; qunlock(&n->lk); } | |
| 1991/0705 | } | |
| 1991/0611 | ||
| 1990/0227 | return 0; } | |