## diffname gnot/page.c 1990/03091 ## diff -e /dev/null /n/bootesdump/1990/03091/sys/src/9/68020/page.c 0a #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "ureg.h" struct { Lock; ulong addr; int active; Page *page; /* base of Page structures, indexed by phys addr */ ulong minppn; /* index of first usable page */ Page *head; /* most recently used */ Page *tail; /* least recently used */ }palloc; struct { Lock; Orig *arena; Orig *free; }origalloc; typedef union PTEA PTEA; union PTEA{ PTE; struct{ ulong n; /* for growpte */ Orig *o; /* for growpte */ PTEA *next; /* for newmod */ }; }; struct { Lock; PTEA *arena; PTEA *free; PTEA *end; }ptealloc; struct{ Lock; PTEA *free; }modalloc; /* * Called to allocate permanent data structures, before calling pageinit(). */ void* ialloc(ulong n, int align) { ulong p; if(palloc.active) print("ialloc bad\n"); if(palloc.addr == 0) palloc.addr = ((ulong)&end)&~KZERO; if(align){ palloc.addr += BY2PG-1; palloc.addr &= ~(BY2PG-1); } memset((void*)(palloc.addr|KZERO), 0, n); p = palloc.addr; palloc.addr += n; if(align){ palloc.addr += BY2PG-1; palloc.addr &= ~(BY2PG-1); } return (void*)(p|KZERO); } void audit(char *s) { int nf, nb; Page *p; static int here; do;while(here); here=1; p = palloc.head; nf=nb=0; while(p){ print("%lux %lux %d\n", p->pa, p->va, p->ref); if(p->o){ print("\t%d %lux %c\n", p->o->nproc, p->o->qid, devchar[p->o->type]); delay(100); /* let it drain; there's a lot here */ } nf++; p = p->next; } p = palloc.tail; while(p){ nb++; p = p->prev; } print("%s: nf: %d nb: %d\n", s, nf, nb); delay(1000); here=0; } void pageinit(void) { ulong pa, nb, ppn; ulong i; Page *p; PTEA *pte; Orig *o; ptealloc.arena = ialloc(conf.npte*sizeof(PTEA), 0); ptealloc.free = ptealloc.arena; ptealloc.end = ptealloc.arena+conf.npte; modalloc.free = ialloc(conf.nmod*sizeof(PTEA), 0); pte = modalloc.free; for(i=0; inext = pte+1; pte->next = 0; origalloc.free = ialloc(conf.norig*sizeof(Orig), 0); origalloc.arena = origalloc.free; o = origalloc.free; for(i=0; inext = o+1; o->next = 0; palloc.active = 1; nb = (conf.npage<>PGSHIFT)*sizeof(Page); /* safe overestimate */ nb &= ~(BY2PG-1); pa = (conf.npage<> PGSHIFT; /* physical page number of first free page */ palloc.page = (Page *)((palloc.addr - ppn*sizeof(Page))|KZERO); /* * Now palloc.page[ppn] describes first free page */ palloc.minppn = ppn; palloc.addr = ppn<next = p+1; p->prev = p-1; p->pa = ppn<prev = 0; palloc.tail->next = 0; } Page* newpage(int noclear, Orig *o, ulong va) { Page *p; Orig *o1; if(palloc.active == 0) print("newpage inactive\n"); loop: lock(&palloc); for(p=palloc.tail; p; p=p->prev){ if(p->ref == 0) goto out; #ifdef asdf if(p->ref == 1){ /* a pageout daemon should do this */ o1 = p->o; if(o1 && o1->nproc==0 && canlock(o1)){ if(o1->nproc){ unlock(o1); continue; } print("free %d pages va %lux %lux %c\n", o1->npage, o->va, o1->qid, devchar[o1->type]); freepage(o1); /* neworig will free the orig and pte's later */ unlock(o1); if(p->ref == 0) goto out; print("newpage ref != 0"); } } #endif } print("no physical memory\n"); unlock(&palloc); if(u == 0) panic("newpage"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); goto loop; out: if(p->o){ print("page in use %lux %lux %lux\n", p->va, p->o, origalloc.arena); print("%c %lux %lux, %d %d %d\n", devchar[p->o->type], p->o->va, p->o->qid, p->o->flag, p->o->nproc, p->o->npte); panic("shit"); } p->ref = 1; usepage(p, 0); unlock(&palloc); if(!noclear) memset((void*)(p->pa|KZERO), 0, BY2PG); p->o = o; p->va = va; return p; } /* * Move page to head of list */ void usepage(Page *p, int dolock) { if(dolock) lock(&palloc); /* * Unlink */ if(p->prev) p->prev->next = p->next; else palloc.head = p->next; if(p->next) p->next->prev = p->prev; else palloc.tail = p->prev; /* * Link */ p->next = palloc.head; p->prev = 0; if(p->next) p->next->prev = p; else palloc.tail = p; palloc.head = p; if(dolock) unlock(&palloc); } Orig* lookorig(ulong va, ulong npte, int flag, Chan *c) { Orig *o; ulong i; for(o=origalloc.arena,i=0; inpage && o->qid==c->qid && o->va==va){ lock(o); if(o->npage && o->qid==c->qid) if(o->va==va && o->npte==npte && o->flag==flag) if(o->mchan==c->mchan && o->mqid==c->mqid && o->type==c->type){ if(o->chan == 0){ o->chan = c; incref(c); } o->nproc++; unlock(o); return o; } unlock(o); } return 0; } Orig* neworig(ulong va, ulong npte, int flag, Chan *c) { Orig *o; int i, freed; lock(&origalloc); loop: if(o = origalloc.free){ /* assign = */ origalloc.free = o->next; o->va = va; o->pte = 0; o->flag = flag; o->nproc = 1; o->npage = 0; o->chan = c; if(c){ o->type = c->type; o->qid = c->qid; o->mchan = c->mchan; o->mqid = c->mqid; incref(c); }else{ o->type = -1; o->qid = -1; o->mqid = -1; o->mchan = 0; } growpte(o, npte); unlock(&origalloc); return o; } /* * This is feeble. Orig's should perhaps be held in * an LRU list. This algorithm is too aggressive. */ freed = 0; for(o=origalloc.arena,i=0; inproc==0 && canlock(o)){ if(o->nproc){ unlock(o); continue; } freepage(o); freepte(o); unlock(o); o->next = origalloc.free; origalloc.free = o; freed++; } } if(freed) goto loop; print("no origs freed\n"); unlock(&origalloc); if(u == 0) panic("neworig"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); lock(&origalloc); goto loop; } PTE* newmod(void) { PTEA *pte; loop: lock(&modalloc); if(pte = modalloc.free){ /* assign = */ modalloc.free = pte->next; unlock(&modalloc); memset(pte, 0, sizeof(PTE)); return pte; } unlock(&modalloc); print("no mods\n"); if(u == 0) panic("newmod"); u->p->state = Wakeme; alarm(1000, wakeme, u->p); sched(); goto loop; } /* * Duplicate mod structure for this segment (old) in new process p. * old->o must be locked. */ void forkmod(Seg *old, Seg *new, Proc *p) { Orig *o; PTE *pte, *ppte, *opte, *npte; ulong va; o = old->o; ppte = 0; pte = old->mod; while(pte){ if(pte->page==0) panic("forkmod zero page"); if(pte->proc != u->p) panic("forkmod wrong page"); npte = newmod(); npte->proc = p; npte->page = pte->page; pte->page->ref++; o->npage++; /* * Link into mod list for this va */ npte->nextmod = pte->nextmod; pte->nextmod = npte; /* * Link into mod list for new segment */ if(ppte == 0) new->mod = npte; else ppte->nextva = npte; npte->nextva = 0; ppte = npte; pte = pte->nextva; } } void freesegs(int save) { int i, j; Seg *s; Orig *o; PTE *pte, *opte; PTEA *old; Page *pg; Chan *c; s = u->p->seg; for(i=0; io; if(o == 0) continue; lock(o); if(pte = s->mod){ /* assign = */ while(pte){ opte = &o->pte[(pte->page->va-o->va)>>PGSHIFT]; while(opte->nextmod != pte){ if(opte->page && opte->page->va != pte->page->va) panic("pte %lux %lux\n", opte->page->va, pte->page->va); opte = opte->nextmod; if(opte == 0) panic("freeseg opte==0"); } opte->nextmod = pte->nextmod; pg = pte->page; if(pg->ref == 1){ pte->page = 0; pg->o = 0; } pg->ref--; o->npage--; old = (PTEA*)pte; pte = pte->nextva; lock(&modalloc); old->next = modalloc.free; modalloc.free = old; unlock(&modalloc); } } o->nproc--; if(o->nproc == 0){ if(c = o->chan){ /* assign = */ o->chan = 0; close(c); } if(!(o->flag&OCACHED) || o->npage==0){ freepage(o); freepte(o); unlock(o); lock(&origalloc); o->next = origalloc.free; origalloc.free = o; unlock(&origalloc); }else unlock(o); }else{ /* * BUG: there is a leak here. if the origin pte is being used only * by the exiting process, the associated page will linger. the fix * is to remember either the length of the mod list at each va or * the number of processes sharing the origin pte, and to promote one * of the mods to the origin pte when no process is left using the * origin pte. */ unlock(o); } } } /* * Adjust segment to desired size. This implementation is rudimentary. */ int segaddr(Seg *s, ulong min, ulong max) { Orig *o; if(max < min) return 0; if(min != s->minva) /* can't grow down yet (stacks: fault.c) */ return 0; max = (max+(BY2PG-1)) & ~(BY2PG-1); o = s->o; if(max == s->maxva) return 1; if(max > s->maxva){ /* * Grow */ /* BUG: check spill onto other segments */ if(o->va+BY2PG*o->npte < max) growpte(o, (max-o->va)>>PGSHIFT); s->maxva = max; return 1; } /* * Shrink */ print("segaddr shrink"); for(;;); } /* * o is locked */ void freepage(Orig *o) { PTE *pte; Page *pg; int i; pte = o->pte; for(i=0; inpte; i++,pte++) if(pg = pte->page){ /* assign = */ if(pg->ref == 1){ pte->page = 0; pg->o = 0; } pg->ref--; } o->npage = 0; } /* * Compacting allocator */ void freepte(Orig *o) /* o is locked */ { PTEA *p; p = (PTEA*)(o->pte - 1); p->o = 0; } void growpte(Orig *o, ulong n) { PTEA *p; ulong nfree; lock(&ptealloc); lock(o); if(o->pte){ if(o->npte == n) panic("growpte pointless"); p = (PTEA*)(o->pte - 1); if(o->npte > n){ nfree = o->npte - n; p->n -= nfree; o->npte -= nfree; p += p->n; p->o = 0; p->n = nfree; }else{ n++; if(p+p->n == ptealloc.free){ compactpte(o, n - p->n); p = (PTEA*)(o->pte - 1); ptealloc.free += n - p->n; }else{ compactpte(o, n); p = ptealloc.free; ptealloc.free += n; memcpy(p+1, o->pte, o->npte*sizeof(PTE)); p->o = o; ((PTEA*)(o->pte-1))->o = 0; o->pte = p+1; } memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE)); p->n = n; o->npte = n-1; } unlock(o); unlock(&ptealloc); return; } n++; compactpte(o, n); p = ptealloc.free; ptealloc.free += n; memset(p, 0, n*sizeof(PTE)); p->n = n; p->o = o; o->pte = p+1; o->npte = n-1; unlock(o); unlock(&ptealloc); } void compactpte(Orig *o, ulong n) { PTEA *p1, *p2; Orig *p2o; if(ptealloc.end-ptealloc.free >= n) return; p1 = ptealloc.arena; /* dest */ p2 = ptealloc.arena; /* source */ while(p2 < ptealloc.free){ p2o = p2->o; if(p2o == 0){ Free: p2 += p2->n; continue; } if(p1 != p2){ if(p2o != o) lock(p2o); if(p2->o != p2o){ /* freepte()d very recently */ if(p2->o) panic("compactpte p2->o %lux\n", p2->o); unlock(p2o); goto Free; } memcpy(p1, p2, p2->n*sizeof(PTE)); p2o->pte = p1+1; if(p2o != o) unlock(p2o); } p2 += p1->n; p1 += p1->n; } ptealloc.free = p1; if(ptealloc.end-ptealloc.free >= n) return; unlock(o); unlock(&ptealloc); panic("compactpte %d %lux %d", n, o->va, o->npte); } . ## diffname gnot/page.c 1990/06021 ## diff -e /n/bootesdump/1990/03091/sys/src/9/68020/page.c /n/bootesdump/1990/06021/sys/src/9/68020/page.c 208,209c if(!noclear){ k = kmap(p); memset((void*)k->va, 0, BY2PG); kunmap(k); } . 163a KMap *k; . 153c if(ppn < conf.npage0) p->pa = conf.base0+(ppn<pa = conf.base1+((ppn-conf.npage0)<= (4*1024*1024-256*1024-BY2PG)) panic("keep bill joy away"); . ## diffname gnot/page.c 1990/0728 ## diff -e /n/bootesdump/1990/0709/sys/src/9/68020/page.c /n/bootesdump/1990/0728/sys/src/9/68020/page.c 604a Return: . 592,594c goto Return; . 566a print("growpte shrink"); goto Return; . 563,564c if(o->npte == n){ print("growpte pointless\n"); goto Return; } . ## diffname gnot/page.c 1990/0802 ## diff -e /n/bootesdump/1990/0728/sys/src/9/68020/page.c /n/bootesdump/1990/0802/sys/src/9/68020/page.c 651c if(u && u->p) print("%s: %s: ", u->p->text, u->p->pgrp->user); print("compactpte fails addr %lux\n", o->va+n*BY2PG); return 0; . 648c return 1; . 619c return 1; . 612c int . 609a return; Trouble: unlock(&ptealloc); if(u && u->p) error(0, Enovmem); panic("growpte fails %d %lux %d\n", n, o->va, o->npte); . 608d 599c if(!compactpte(o, n)) goto Trouble; . 584c if(!compactpte(o, n)) goto Trouble; . 580c if(!compactpte(o, n - p->n)) goto Trouble; . 563a if(u && u->p) print("%s: ", u->p->text); . 561d 509a unlock(o); poperror(); . 507a lock(o); if(waserror()){ unlock(o); nexterror(); } . 313a if(u && u->p) poperror(); unlock(o); . 312a lock(o); if(u && u->p && waserror()){ unlock(o); unlock(&origalloc); nexterror(); } . 6a #include "errno.h" . ## diffname gnot/page.c 1990/0814 ## diff -e /n/bootesdump/1990/0802/sys/src/9/68020/page.c /n/bootesdump/1990/0814/sys/src/9/68020/page.c 632a unlock(o); . 628a unlock(o); . 614a memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE)); p->n = n; o->npte = n-1; . 595,613c if(!compactpte(o, n)) goto Trouble; p = ptealloc.free; ptealloc.free += n; memcpy(p+1, o->pte, o->npte*sizeof(PTE)); p->o = o; ((PTEA*)(o->pte-1))->o = 0; o->pte = p+1; . 585,593c n++; if(p+p->n == ptealloc.free){ if(!compactpte(o, n - p->n)) goto Trouble; p = (PTEA*)(o->pte - 1); ptealloc.free += n - p->n; . 583d 579,581c if(o->npte >= n) . 577a lock(o); . 570a /* * o is locked. this will always do a grow; if n<=o->npte someone * else got here first and we can just return. */ . 525,526d 518,522d 323d 316d 314d ## diffname gnot/page.c 1990/11211 ## diff -e /n/bootesdump/1990/0814/sys/src/9/68020/page.c /n/bootesdump/1990/11211/sys/src/9/68020/page.c 617c error(Enovmem); . 310,311c o->qid.path = -1; o->qid.vers = 0; o->mqid.path = -1; o->mqid.vers = 0; . 272c if(o->mchan==c->mchan && eqqid(o->mqid, c->mqid) && o->type==c->type){ . 270c if(o->npage && eqqid(o->qid, c->qid)) . 268c if(o->npage && eqqid(o->qid, c->qid) && o->va==va){ . ## diffname gnot/page.c 1990/1126 ## diff -e /n/bootesdump/1990/11211/sys/src/9/68020/page.c /n/bootesdump/1990/1126/sys/src/9/68020/page.c 309c o->type = ~0; . ## diffname gnot/page.c 1990/1211 ## diff -e /n/bootesdump/1990/1126/sys/src/9/68020/page.c /n/bootesdump/1990/1211/sys/src/9/68020/page.c 260a /* * Move page to tail of list */ void unusepage(Page *p, int dolock) { } . ## diffname gnot/page.c 1990/1212 # deleted ## diff -e /n/bootesdump/1990/1211/sys/src/9/68020/page.c /n/bootesdump/1990/1212/sys/src/9/68020/page.c 1,674d