13e12c5d1SDavid du Colombier #include "u.h" 23e12c5d1SDavid du Colombier #include "../port/lib.h" 33e12c5d1SDavid du Colombier #include "mem.h" 43e12c5d1SDavid du Colombier #include "dat.h" 53e12c5d1SDavid du Colombier #include "fns.h" 63e12c5d1SDavid du Colombier #include "../port/error.h" 73e12c5d1SDavid du Colombier 83e12c5d1SDavid du Colombier void faulterror(char*); 93e12c5d1SDavid du Colombier 103e12c5d1SDavid du Colombier int 113e12c5d1SDavid du Colombier fault(ulong addr, int read) 123e12c5d1SDavid du Colombier { 133e12c5d1SDavid du Colombier Segment *s; 143e12c5d1SDavid du Colombier char *sps; 153e12c5d1SDavid du Colombier 163e12c5d1SDavid du Colombier sps = u->p->psstate; 173e12c5d1SDavid du Colombier u->p->psstate = "Fault"; 183e12c5d1SDavid du Colombier spllo(); 193e12c5d1SDavid du Colombier 203e12c5d1SDavid du Colombier m->pfault++; 213e12c5d1SDavid du Colombier for(;;) { 223e12c5d1SDavid du Colombier s = seg(u->p, addr, 1); 233e12c5d1SDavid du Colombier if(s == 0) { 243e12c5d1SDavid du Colombier u->p->psstate = sps; 253e12c5d1SDavid du Colombier return -1; 263e12c5d1SDavid du Colombier } 273e12c5d1SDavid du Colombier 283e12c5d1SDavid du Colombier if(!read && (s->type&SG_RONLY)) { 293e12c5d1SDavid du Colombier qunlock(&s->lk); 303e12c5d1SDavid du Colombier u->p->psstate = sps; 313e12c5d1SDavid du Colombier return -1; 323e12c5d1SDavid du Colombier } 333e12c5d1SDavid du Colombier 343e12c5d1SDavid du Colombier if(fixfault(s, addr, read, 1) == 0) 353e12c5d1SDavid du Colombier break; 363e12c5d1SDavid du Colombier } 373e12c5d1SDavid du Colombier 383e12c5d1SDavid du Colombier u->p->psstate = sps; 393e12c5d1SDavid du Colombier return 0; 403e12c5d1SDavid du Colombier } 413e12c5d1SDavid du Colombier 423e12c5d1SDavid du Colombier int 433e12c5d1SDavid du Colombier fixfault(Segment *s, ulong addr, int read, int doputmmu) 443e12c5d1SDavid du Colombier { 45*219b2ee8SDavid du Colombier int type; 46*219b2ee8SDavid du Colombier Pte **p, *etp; 473e12c5d1SDavid du Colombier ulong mmuphys=0, soff; 483e12c5d1SDavid du Colombier Page **pg, *lkp, *new; 49*219b2ee8SDavid du Colombier Page *(*fn)(Segment*, ulong); 503e12c5d1SDavid du Colombier 513e12c5d1SDavid du Colombier addr &= ~(BY2PG-1); 523e12c5d1SDavid du Colombier soff = addr-s->base; 533e12c5d1SDavid du Colombier p = &s->map[soff/PTEMAPMEM]; 543e12c5d1SDavid du Colombier if(*p == 0) 553e12c5d1SDavid du Colombier *p = ptealloc(); 563e12c5d1SDavid du Colombier 573e12c5d1SDavid du Colombier etp = *p; 583e12c5d1SDavid du Colombier pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 593e12c5d1SDavid du Colombier type = s->type&SG_TYPE; 603e12c5d1SDavid du Colombier 613e12c5d1SDavid du Colombier if(pg < etp->first) 623e12c5d1SDavid du Colombier etp->first = pg; 633e12c5d1SDavid du Colombier if(pg > etp->last) 643e12c5d1SDavid du Colombier etp->last = pg; 653e12c5d1SDavid du Colombier 663e12c5d1SDavid du Colombier switch(type) { 673e12c5d1SDavid du Colombier default: 683e12c5d1SDavid du Colombier panic("fault"); 693e12c5d1SDavid du Colombier break; 703e12c5d1SDavid du Colombier 713e12c5d1SDavid du Colombier case SG_TEXT: 723e12c5d1SDavid du Colombier if(pagedout(*pg)) /* Demand load */ 733e12c5d1SDavid du Colombier pio(s, addr, soff, pg); 743e12c5d1SDavid du Colombier 753e12c5d1SDavid du Colombier mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 763e12c5d1SDavid du Colombier (*pg)->modref = PG_REF; 773e12c5d1SDavid du Colombier break; 783e12c5d1SDavid du Colombier 793e12c5d1SDavid du Colombier case SG_SHDATA: /* Shared data */ 803e12c5d1SDavid du Colombier if(pagedout(*pg)) 813e12c5d1SDavid du Colombier pio(s, addr, soff, pg); 823e12c5d1SDavid du Colombier 83*219b2ee8SDavid du Colombier lkp = *pg; 84*219b2ee8SDavid du Colombier lock(lkp); 85*219b2ee8SDavid du Colombier if(lkp->image) 86*219b2ee8SDavid du Colombier duppage(lkp); 87*219b2ee8SDavid du Colombier unlock(lkp); 883e12c5d1SDavid du Colombier goto done; 893e12c5d1SDavid du Colombier 903e12c5d1SDavid du Colombier case SG_BSS: 913e12c5d1SDavid du Colombier case SG_SHARED: /* Zero fill on demand */ 923e12c5d1SDavid du Colombier case SG_STACK: 933e12c5d1SDavid du Colombier if(*pg == 0) { 943e12c5d1SDavid du Colombier new = newpage(1, &s, addr); 953e12c5d1SDavid du Colombier if(s == 0) 963e12c5d1SDavid du Colombier return -1; 973e12c5d1SDavid du Colombier 983e12c5d1SDavid du Colombier *pg = new; 993e12c5d1SDavid du Colombier } 1003e12c5d1SDavid du Colombier /* NO break */ 1013e12c5d1SDavid du Colombier 1023e12c5d1SDavid du Colombier case SG_DATA: /* Demand load/pagein/copy on write */ 1033e12c5d1SDavid du Colombier if(pagedout(*pg)) 1043e12c5d1SDavid du Colombier pio(s, addr, soff, pg); 1053e12c5d1SDavid du Colombier 1063e12c5d1SDavid du Colombier if(type == SG_SHARED) 1073e12c5d1SDavid du Colombier goto done; 1083e12c5d1SDavid du Colombier 1093e12c5d1SDavid du Colombier if(read && conf.copymode == 0) { 1103e12c5d1SDavid du Colombier mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 1113e12c5d1SDavid du Colombier (*pg)->modref |= PG_REF; 1123e12c5d1SDavid du Colombier break; 1133e12c5d1SDavid du Colombier } 1143e12c5d1SDavid du Colombier 1153e12c5d1SDavid du Colombier lkp = *pg; 1163e12c5d1SDavid du Colombier lock(lkp); 1173e12c5d1SDavid du Colombier if(lkp->ref > 1) { 1183e12c5d1SDavid du Colombier unlock(lkp); 1193e12c5d1SDavid du Colombier new = newpage(0, &s, addr); 1203e12c5d1SDavid du Colombier if(s == 0) 1213e12c5d1SDavid du Colombier return -1; 1223e12c5d1SDavid du Colombier *pg = new; 1233e12c5d1SDavid du Colombier copypage(lkp, *pg); 1243e12c5d1SDavid du Colombier putpage(lkp); 1253e12c5d1SDavid du Colombier } 1263e12c5d1SDavid du Colombier else { 1273e12c5d1SDavid du Colombier /* put a duplicate of a text page back onto the free list */ 1283e12c5d1SDavid du Colombier if(lkp->image) 1293e12c5d1SDavid du Colombier duppage(lkp); 1303e12c5d1SDavid du Colombier 1313e12c5d1SDavid du Colombier unlock(lkp); 1323e12c5d1SDavid du Colombier } 1333e12c5d1SDavid du Colombier done: 1343e12c5d1SDavid du Colombier mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEVALID; 1353e12c5d1SDavid du Colombier (*pg)->modref = PG_MOD|PG_REF; 1363e12c5d1SDavid du Colombier break; 1373e12c5d1SDavid du Colombier 1383e12c5d1SDavid du Colombier case SG_PHYSICAL: 139*219b2ee8SDavid du Colombier if(*pg == 0) { 140*219b2ee8SDavid du Colombier fn = s->pseg->pgalloc; 141*219b2ee8SDavid du Colombier if(fn) 142*219b2ee8SDavid du Colombier *pg = (*fn)(s, addr); 143*219b2ee8SDavid du Colombier else { 144*219b2ee8SDavid du Colombier new = smalloc(sizeof(Page)); 145*219b2ee8SDavid du Colombier new->va = addr; 146*219b2ee8SDavid du Colombier new->pa = s->pseg->pa+(addr-s->base); 147*219b2ee8SDavid du Colombier new->ref = 1; 148*219b2ee8SDavid du Colombier *pg = new; 149*219b2ee8SDavid du Colombier } 150*219b2ee8SDavid du Colombier } 1513e12c5d1SDavid du Colombier 1523e12c5d1SDavid du Colombier mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID; 1533e12c5d1SDavid du Colombier (*pg)->modref = PG_MOD|PG_REF; 154*219b2ee8SDavid du Colombier /* print("v %lux p %lux\n", addr, mmuphys); /**/ 1553e12c5d1SDavid du Colombier break; 1563e12c5d1SDavid du Colombier } 1573e12c5d1SDavid du Colombier 1583e12c5d1SDavid du Colombier if(s->flushme) 1593e12c5d1SDavid du Colombier memset((*pg)->cachectl, PG_TXTFLUSH, sizeof(new->cachectl)); 1603e12c5d1SDavid du Colombier 1613e12c5d1SDavid du Colombier qunlock(&s->lk); 1623e12c5d1SDavid du Colombier 1633e12c5d1SDavid du Colombier if(doputmmu) 1643e12c5d1SDavid du Colombier putmmu(addr, mmuphys, *pg); 1653e12c5d1SDavid du Colombier 1663e12c5d1SDavid du Colombier return 0; 1673e12c5d1SDavid du Colombier } 1683e12c5d1SDavid du Colombier 1693e12c5d1SDavid du Colombier void 1703e12c5d1SDavid du Colombier pio(Segment *s, ulong addr, ulong soff, Page **p) 1713e12c5d1SDavid du Colombier { 1723e12c5d1SDavid du Colombier Page *new; 1733e12c5d1SDavid du Colombier KMap *k; 1743e12c5d1SDavid du Colombier Chan *c; 1753e12c5d1SDavid du Colombier int n, ask; 1763e12c5d1SDavid du Colombier char *kaddr; 1773e12c5d1SDavid du Colombier ulong daddr; 1783e12c5d1SDavid du Colombier Page *loadrec; 1793e12c5d1SDavid du Colombier 1803e12c5d1SDavid du Colombier loadrec = *p; 1813e12c5d1SDavid du Colombier if(loadrec == 0) { 1823e12c5d1SDavid du Colombier daddr = s->fstart+soff; /* Compute disc address */ 1833e12c5d1SDavid du Colombier new = lookpage(s->image, daddr); 1843e12c5d1SDavid du Colombier } 1853e12c5d1SDavid du Colombier else { 1863e12c5d1SDavid du Colombier daddr = swapaddr(loadrec); 1873e12c5d1SDavid du Colombier new = lookpage(&swapimage, daddr); 1883e12c5d1SDavid du Colombier if(new) 1893e12c5d1SDavid du Colombier putswap(loadrec); 1903e12c5d1SDavid du Colombier } 1913e12c5d1SDavid du Colombier 1923e12c5d1SDavid du Colombier if(new) { /* Page found from cache */ 1933e12c5d1SDavid du Colombier *p = new; 1943e12c5d1SDavid du Colombier return; 1953e12c5d1SDavid du Colombier } 1963e12c5d1SDavid du Colombier 1973e12c5d1SDavid du Colombier qunlock(&s->lk); 1983e12c5d1SDavid du Colombier 1993e12c5d1SDavid du Colombier new = newpage(0, 0, addr); 2003e12c5d1SDavid du Colombier k = kmap(new); 2013e12c5d1SDavid du Colombier kaddr = (char*)VA(k); 2023e12c5d1SDavid du Colombier 2033e12c5d1SDavid du Colombier if(loadrec == 0) { /* This is demand load */ 2043e12c5d1SDavid du Colombier c = s->image->c; 2053e12c5d1SDavid du Colombier while(waserror()) { 2063e12c5d1SDavid du Colombier if(strcmp(u->error, Eintr) == 0) 2073e12c5d1SDavid du Colombier continue; 2083e12c5d1SDavid du Colombier kunmap(k); 2093e12c5d1SDavid du Colombier putpage(new); 2103e12c5d1SDavid du Colombier faulterror("sys: demand load I/O error"); 2113e12c5d1SDavid du Colombier } 2123e12c5d1SDavid du Colombier 2133e12c5d1SDavid du Colombier ask = s->flen-soff; 2143e12c5d1SDavid du Colombier if(ask > BY2PG) 2153e12c5d1SDavid du Colombier ask = BY2PG; 2163e12c5d1SDavid du Colombier 2173e12c5d1SDavid du Colombier n = (*devtab[c->type].read)(c, kaddr, ask, daddr); 218*219b2ee8SDavid du Colombier if(n != ask){ 219*219b2ee8SDavid du Colombier print("demand load: %s: %d %d\n", u->error, n, ask); 2203e12c5d1SDavid du Colombier error(Eioload); 221*219b2ee8SDavid du Colombier } 2223e12c5d1SDavid du Colombier if(ask < BY2PG) 2233e12c5d1SDavid du Colombier memset(kaddr+ask, 0, BY2PG-ask); 2243e12c5d1SDavid du Colombier 2253e12c5d1SDavid du Colombier poperror(); 2263e12c5d1SDavid du Colombier kunmap(k); 2273e12c5d1SDavid du Colombier qlock(&s->lk); 2283e12c5d1SDavid du Colombier if(*p == 0) { /* Someone may have got there first */ 2293e12c5d1SDavid du Colombier new->daddr = daddr; 2303e12c5d1SDavid du Colombier cachepage(new, s->image); 2313e12c5d1SDavid du Colombier *p = new; 2323e12c5d1SDavid du Colombier } 2333e12c5d1SDavid du Colombier else 2343e12c5d1SDavid du Colombier putpage(new); 2353e12c5d1SDavid du Colombier } 2363e12c5d1SDavid du Colombier else { /* This is paged out */ 2373e12c5d1SDavid du Colombier c = swapimage.c; 2383e12c5d1SDavid du Colombier 2393e12c5d1SDavid du Colombier if(waserror()) { 2403e12c5d1SDavid du Colombier kunmap(k); 2413e12c5d1SDavid du Colombier putpage(new); 2423e12c5d1SDavid du Colombier qlock(&s->lk); 2433e12c5d1SDavid du Colombier qunlock(&s->lk); 2443e12c5d1SDavid du Colombier faulterror("sys: page in I/O error"); 2453e12c5d1SDavid du Colombier } 2463e12c5d1SDavid du Colombier 2473e12c5d1SDavid du Colombier n = (*devtab[c->type].read)(c, kaddr, BY2PG, daddr); 248*219b2ee8SDavid du Colombier if(n != BY2PG){ 249*219b2ee8SDavid du Colombier print("page in: %s: %d %d\n", u->error, n, BY2PG); 2503e12c5d1SDavid du Colombier error(Eioload); 251*219b2ee8SDavid du Colombier } 2523e12c5d1SDavid du Colombier 2533e12c5d1SDavid du Colombier poperror(); 2543e12c5d1SDavid du Colombier kunmap(k); 2553e12c5d1SDavid du Colombier qlock(&s->lk); 2563e12c5d1SDavid du Colombier 2573e12c5d1SDavid du Colombier if(pagedout(*p)) { 2583e12c5d1SDavid du Colombier new->daddr = daddr; 2593e12c5d1SDavid du Colombier cachepage(new, &swapimage); 2603e12c5d1SDavid du Colombier putswap(*p); 2613e12c5d1SDavid du Colombier *p = new; 2623e12c5d1SDavid du Colombier } 2633e12c5d1SDavid du Colombier else 2643e12c5d1SDavid du Colombier putpage(new); 2653e12c5d1SDavid du Colombier } 2663e12c5d1SDavid du Colombier } 2673e12c5d1SDavid du Colombier 2683e12c5d1SDavid du Colombier void 2693e12c5d1SDavid du Colombier faulterror(char *s) 2703e12c5d1SDavid du Colombier { 2713e12c5d1SDavid du Colombier if(u->nerrlab) { 272*219b2ee8SDavid du Colombier postnote(u->p, 1, s, NUser); 2733e12c5d1SDavid du Colombier error(s); 2743e12c5d1SDavid du Colombier } 275*219b2ee8SDavid du Colombier pexit(s, 1); 2763e12c5d1SDavid du Colombier } 2773e12c5d1SDavid du Colombier 2783e12c5d1SDavid du Colombier /* 2793e12c5d1SDavid du Colombier * Called only in a system call 2803e12c5d1SDavid du Colombier */ 2813e12c5d1SDavid du Colombier int 2823e12c5d1SDavid du Colombier okaddr(ulong addr, ulong len, int write) 2833e12c5d1SDavid du Colombier { 2843e12c5d1SDavid du Colombier Segment *s; 2853e12c5d1SDavid du Colombier 2863e12c5d1SDavid du Colombier if((long)len >= 0) { 2873e12c5d1SDavid du Colombier for(;;) { 2883e12c5d1SDavid du Colombier s = seg(u->p, addr, 0); 2893e12c5d1SDavid du Colombier if(s == 0 || (write && (s->type&SG_RONLY))) 2903e12c5d1SDavid du Colombier break; 2913e12c5d1SDavid du Colombier 2923e12c5d1SDavid du Colombier if(addr+len > s->top) { 2933e12c5d1SDavid du Colombier len -= s->top - addr; 2943e12c5d1SDavid du Colombier addr = s->top; 2953e12c5d1SDavid du Colombier continue; 2963e12c5d1SDavid du Colombier } 2973e12c5d1SDavid du Colombier return 1; 2983e12c5d1SDavid du Colombier } 2993e12c5d1SDavid du Colombier } 3003e12c5d1SDavid du Colombier pprint("suicide: invalid address 0x%lux in sys call pc=0x%lux\n", addr, userpc()); 3013e12c5d1SDavid du Colombier return 0; 3023e12c5d1SDavid du Colombier } 3033e12c5d1SDavid du Colombier 3043e12c5d1SDavid du Colombier void 3053e12c5d1SDavid du Colombier validaddr(ulong addr, ulong len, int write) 3063e12c5d1SDavid du Colombier { 3073e12c5d1SDavid du Colombier if(!okaddr(addr, len, write)) 3083e12c5d1SDavid du Colombier pexit("Suicide", 0); 3093e12c5d1SDavid du Colombier } 3103e12c5d1SDavid du Colombier 3113e12c5d1SDavid du Colombier /* 3123e12c5d1SDavid du Colombier * &s[0] is known to be a valid address. 3133e12c5d1SDavid du Colombier */ 3143e12c5d1SDavid du Colombier void* 3153e12c5d1SDavid du Colombier vmemchr(void *s, int c, int n) 3163e12c5d1SDavid du Colombier { 3173e12c5d1SDavid du Colombier int m; 3183e12c5d1SDavid du Colombier char *t; 3193e12c5d1SDavid du Colombier ulong a; 3203e12c5d1SDavid du Colombier 3213e12c5d1SDavid du Colombier a = (ulong)s; 3223e12c5d1SDavid du Colombier m = BY2PG - (a & (BY2PG-1)); 3233e12c5d1SDavid du Colombier if(m < n){ 3243e12c5d1SDavid du Colombier t = vmemchr(s, c, m); 3253e12c5d1SDavid du Colombier if(t) 3263e12c5d1SDavid du Colombier return t; 3273e12c5d1SDavid du Colombier if(!(a & KZERO)) 3283e12c5d1SDavid du Colombier validaddr(a+m, 1, 0); 3293e12c5d1SDavid du Colombier return vmemchr((void*)(a+m), c, n-m); 3303e12c5d1SDavid du Colombier } 3313e12c5d1SDavid du Colombier /* 3323e12c5d1SDavid du Colombier * All in one page 3333e12c5d1SDavid du Colombier */ 3343e12c5d1SDavid du Colombier return memchr(s, c, n); 3353e12c5d1SDavid du Colombier } 3363e12c5d1SDavid du Colombier 3373e12c5d1SDavid du Colombier Segment* 3383e12c5d1SDavid du Colombier seg(Proc *p, ulong addr, int dolock) 3393e12c5d1SDavid du Colombier { 3403e12c5d1SDavid du Colombier Segment **s, **et, *n; 3413e12c5d1SDavid du Colombier 3423e12c5d1SDavid du Colombier et = &p->seg[NSEG]; 3433e12c5d1SDavid du Colombier for(s = p->seg; s < et; s++) 3443e12c5d1SDavid du Colombier if(n = *s){ 3453e12c5d1SDavid du Colombier if(addr >= n->base && addr < n->top) { 3463e12c5d1SDavid du Colombier if(dolock == 0) 3473e12c5d1SDavid du Colombier return n; 3483e12c5d1SDavid du Colombier 3493e12c5d1SDavid du Colombier qlock(&n->lk); 3503e12c5d1SDavid du Colombier if(addr >= n->base && addr < n->top) 3513e12c5d1SDavid du Colombier return n; 3523e12c5d1SDavid du Colombier qunlock(&n->lk); 3533e12c5d1SDavid du Colombier } 3543e12c5d1SDavid du Colombier } 3553e12c5d1SDavid du Colombier 3563e12c5d1SDavid du Colombier return 0; 3573e12c5d1SDavid du Colombier } 358