| plan 9 kernel history: overview | file list | diff list |
1992/0321/port/page.c (diff list | history)
| port/page.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 | ||
| 1991/0705 | #define PGHFUN(x, y) (((ulong)x^(ulong)y)%PGHSIZE) #define pghash(s) palloc.hash[PGHFUN(s->image, p->daddr)] | |
| 1990/0227 | ||
| 1991/0705 | struct Palloc palloc; struct Ptealloc | |
| 1990/0227 | { Lock; | |
| 1991/0705 | Pte *free; int pages; }ptealloclk; | |
| 1990/0227 | ||
| 1992/0315 | ulong hiaddr; | |
| 1991/0705 | static Lock pglock; | |
| 1990/0227 | ||
| 1991/0705 | /* Multiplex a hardware lock for per page manipulations */ void lockpage(Page *p) { int s; | |
| 1990/0227 | ||
| 1991/0705 | for(;;) { if(p->lock == 0) { s = splhi(); lock(&pglock); if(p->lock == 0) { p->lock = 1; unlock(&pglock); splx(s); return; } unlock(&pglock); splx(s); } sched(); } } | |
| 1990/0227 | ||
| 1991/0705 | void unlockpage(Page *p) { p->lock = 0; } | |
| 1991/0425 | ||
| 1992/0313 | typedef struct Region Region; struct Region { ulong start; ulong end; }; enum { Nregion= 10, }; Region region[Nregion]; void addsplit(Region *r, ulong start, ulong end) { Region *rr; int len = end - start; /* first look for an unused one */ for(rr = region; rr < ®ion[Nregion]; rr++){ if(rr == r) continue; if(rr->end - rr->start == 0){ rr->start = start; rr->end = end; return; } } /* then look for a smaller one */ for(rr = region; rr < ®ion[Nregion]; rr++){ if(rr == r) continue; if(rr->end - rr->start < len){ rr->start = start; rr->end = end; return; } } } | |
| 1992/0315 | /* * Called to allocate permanent data structures, before calling pageinit(). * We assume all of text+data+bss is in the first memory bank. * | |
| 1992/0317 | * alignment is in number of bytes. It pertains both to the start and | |
| 1992/0315 | * end of the allocated memory. * * If crevasse is specified, no allocation can span an address that is * a multiple of crevasse. */ | |
| 1990/0227 | void* | |
| 1992/0313 | iallocspan(ulong n, int align, ulong crevasse) | |
| 1990/0227 | { ulong p; | |
| 1992/0313 | Region *r; int m; int ledge; | |
| 1990/0227 | ||
| 1990/1212 | if(palloc.active && n!=0) | |
| 1990/0227 | print("ialloc bad\n"); | |
| 1991/0606 | ||
| 1991/0802 | if(palloc.addr0 == 0){ | |
| 1992/0319 | region[Nregion-2].start = (((ulong)end)&~KZERO) + conf.base0; | |
| 1992/0313 | region[Nregion-2].end = conf.base0 + (conf.npage0<<PGSHIFT); region[Nregion-1].start = conf.base1; region[Nregion-1].end = conf.base1 + (conf.npage1<<PGSHIFT); palloc.addr0 = region[Nregion-2].start; palloc.addr1 = region[Nregion-1].start; | |
| 1991/0802 | } | |
| 1991/0801 | ||
| 1991/0802 | /* | |
| 1992/0313 | * alignment also applies to length | |
| 1991/0802 | */ | |
| 1992/0313 | if(align){ m = n % align; if(m) n += align - m; } | |
| 1991/0606 | ||
| 1992/0313 | p = 0; for(r = region; r < ®ion[Nregion]; r++){ | |
| 1992/0315 | /* align region */ | |
| 1992/0313 | p = r->start; if(align){ m = p % align; if(m) p += align - m; } | |
| 1991/0705 | ||
| 1992/0313 | /* check for crossing a crevasse */ if(crevasse){ ledge = p / crevasse; if(ledge != ((p+n-1) / crevasse)) p = ((p+n-1) / crevasse) * crevasse; } /* see if it fits */ if(p + n > r->end) continue; /* split the region */ if(p != r->start) addsplit(r, r->start, p); r->start = p + n; break; } if(r == ®ion[Nregion]) panic("out of memory"); | |
| 1991/0802 | /* | |
| 1992/0313 | * remember high water marks | |
| 1991/0802 | */ | |
| 1992/0313 | if(palloc.addr0 < r->start && r->start <= conf.base0+(conf.npage0<<PGSHIFT)) palloc.addr0 = r->start; else if(palloc.addr1 < r->start && r->start <= conf.base1+(conf.npage1<<PGSHIFT)) palloc.addr1 = r->start; | |
| 1991/0802 | /* | |
| 1992/0313 | * zero it | |
| 1991/0802 | */ | |
| 1992/0313 | memset((void*)(p|KZERO), 0, n); | |
| 1991/0802 | ||
| 1990/0227 | return (void*)(p|KZERO); | |
| 1992/0313 | } /* * allocate with possible page alignment */ void* ialloc(ulong n, int align) { return iallocspan(n, align ? BY2PG : 0, 0); | |
| 1990/0227 | } void pageinit(void) { | |
| 1991/0802 | ulong np, addr, lim; | |
| 1992/0303 | ulong i, vmem, pmem, hw, hr; | |
| 1990/0227 | Page *p; | |
| 1991/0802 | /* * calculate an upper bound to the number of pages structures * we'll need (np). */ np = (conf.npage0<<PGSHIFT) - (palloc.addr0 - conf.base0); np += (conf.npage1<<PGSHIFT) - (palloc.addr1 - conf.base1); np = np>>PGSHIFT; | |
| 1990/0227 | /* | |
| 1991/0802 | * allocate Page structs (no more ialloc's allowed after this). * np is useless after this ialloc since we've just eaten up * some pages for the Page structures. | |
| 1990/0227 | */ | |
| 1991/0802 | palloc.head = ialloc(np*sizeof(Page), 0); palloc.active = 1; | |
| 1990/0227 | ||
| 1991/0802 | /* * for each page in each bank, point a page structure to * the page and chain it into the free list */ p = palloc.head; addr = palloc.addr0 = PGROUND(palloc.addr0); lim = conf.base0 + (conf.npage0<<PGSHIFT); for(; addr < lim; addr += BY2PG){ | |
| 1990/0227 | p->next = p+1; p->prev = p-1; | |
| 1991/0802 | p->pa = addr; p++; | |
| 1990/0227 | } | |
| 1991/0802 | addr = palloc.addr1 = PGROUND(palloc.addr1); lim = conf.base1 + (conf.npage1<<PGSHIFT); for(; addr < lim; addr += BY2PG){ p->next = p+1; p->prev = p-1; p->pa = addr; p++; } palloc.tail = p - 1; | |
| 1990/0227 | palloc.head->prev = 0; palloc.tail->next = 0; | |
| 1991/0802 | palloc.user = palloc.freecount = p - palloc.head; pmem = palloc.user*BY2PG/1024; vmem = pmem + ((conf.nswap)*BY2PG)/1024; | |
| 1992/0303 | /* Pageing numbers */ swapalloc.highwater = (palloc.freecount*5)/100; swapalloc.headroom = swapalloc.highwater + (swapalloc.highwater/4); hw = (swapalloc.highwater*BY2PG)/1024; hr = (swapalloc.headroom*BY2PG)/1024; print("%lud free pages, %dK bytes, swap %dK bytes, highwater %dK, headroom %dK\n", palloc.user, pmem, vmem, hw, hr); | |
| 1990/0227 | } Page* | |
| 1991/0705 | newpage(int clear, Segment **s, ulong va) | |
| 1990/0227 | { Page *p; | |
| 1990/0617 | KMap *k; | |
| 1991/0705 | int i; | |
| 1990/0227 | if(palloc.active == 0) print("newpage inactive\n"); | |
| 1991/0705 | ||
| 1990/0227 | lock(&palloc); | |
| 1991/0705 | /* The kp test is a poor guard against the pager deadlocking */ | |
| 1992/0303 | while((palloc.freecount < swapalloc.highwater && u->p->kp == 0)||palloc.freecount == 0) { | |
| 1991/0705 | palloc.wanted++; | |
| 1991/0806 | unlock(&palloc); | |
| 1991/0705 | if(s && *s) { qunlock(&((*s)->lk)); *s = 0; | |
| 1990/0227 | } | |
| 1991/0705 | qlock(&palloc.pwait); /* Hold memory requesters here */ | |
| 1991/0906 | while(waserror()) /* Ignore interrupts */ ; | |
| 1991/0806 | ||
| 1991/0705 | kickpager(); tsleep(&palloc.r, ispages, 0, 1000); | |
| 1991/0806 | poperror(); | |
| 1991/0705 | qunlock(&palloc.pwait); lock(&palloc); palloc.wanted--; | |
| 1990/0227 | } | |
| 1991/0705 | p = palloc.head; if(palloc.head = p->next) /* = Assign */ palloc.head->prev = 0; else palloc.tail = 0; palloc.freecount--; | |
| 1990/0227 | unlock(&palloc); | |
| 1991/0705 | lockpage(p); if(p->ref != 0) | |
| 1990/0227 | panic("newpage"); | |
| 1991/0705 | uncachepage(p); p->ref++; p->va = va; p->modref = 0; for(i = 0; i < MAXMACH; i++) p->cachectl[i] = PG_NOFLUSH; unlockpage(p); if(clear){ | |
| 1990/0617 | k = kmap(p); memset((void*)VA(k), 0, BY2PG); kunmap(k); } | |
| 1990/0227 | return p; } | |
| 1991/0705 | int ispages(void *p) | |
| 1990/0227 | { | |
| 1991/1115 | USED(p); | |
| 1992/0303 | return palloc.freecount >= swapalloc.highwater; | |
| 1990/0227 | } | |
| 1990/0801 | void | |
| 1991/0705 | putpage(Page *p) | |
| 1990/0801 | { | |
| 1991/0705 | if(onswap(p)) { putswap(p); return; } | |
| 1990/0227 | ||
| 1991/0705 | lockpage(p); if(--p->ref == 0) { lock(&palloc); | |
| 1992/0303 | if(p->image && p->image != &swapimage) { | |
| 1991/0705 | if(palloc.tail) { p->prev = palloc.tail; palloc.tail->next = p; | |
| 1990/0227 | } | |
| 1991/0705 | else { | |
| 1992/0303 | palloc.head = p; | |
| 1992/0204 | p->prev = 0; | |
| 1991/0705 | } | |
| 1992/0303 | palloc.tail = p; | |
| 1992/0204 | p->next = 0; | |
| 1990/0227 | } | |
| 1991/0705 | else { if(palloc.head) { p->next = palloc.head; palloc.head->prev = p; } else { | |
| 1992/0303 | palloc.tail = p; | |
| 1992/0204 | p->next = 0; | |
| 1991/0705 | } | |
| 1992/0303 | palloc.head = p; | |
| 1992/0204 | p->prev = 0; | |
| 1991/0705 | } palloc.freecount++; /* Release people waiting for memory */ unlock(&palloc); } unlockpage(p); | |
| 1990/0227 | } | |
| 1991/0705 | void | |
| 1991/1003 | simpleputpage(Page *pg) /* Always call with palloc locked */ { pg->ref = 0; palloc.freecount++; if(palloc.head) { pg->next = palloc.head; palloc.head->prev = pg; pg->prev = 0; palloc.head = pg; } else { palloc.head = palloc.tail = pg; pg->prev = pg->next = 0; } } void | |
| 1991/0705 | duppage(Page *p) /* Always call with p locked */ | |
| 1990/0227 | { | |
| 1991/0705 | Page *np; | |
| 1990/0227 | ||
| 1991/0705 | lock(&palloc); | |
| 1992/0303 | /* No freelist cache when memory is very low, No dup for swap pages */ if(palloc.freecount < swapalloc.highwater || p->image == &swapimage) { | |
| 1991/0705 | unlock(&palloc); uncachepage(p); return; | |
| 1990/0227 | } | |
| 1991/0705 | np = palloc.head; /* Allocate a new page from freelist */ if(palloc.head = np->next) /* = Assign */ palloc.head->prev = 0; else palloc.tail = 0; if(palloc.tail) { /* Link back onto tail to give us lru */ np->prev = palloc.tail; palloc.tail->next = np; np->next = 0; palloc.tail = np; | |
| 1990/0227 | } | |
| 1991/0705 | else { palloc.head = palloc.tail = np; np->prev = np->next = 0; } | |
| 1990/0227 | ||
| 1991/0705 | unlock(&palloc); | |
| 1990/0227 | ||
| 1991/0705 | lockpage(np); /* Cache the new version */ if(np->ref != 0) { /* Stolen by new page */ uncachepage(p); unlockpage(np); return; | |
| 1990/0227 | } | |
| 1991/0705 | uncachepage(np); np->va = p->va; np->daddr = p->daddr; copypage(p, np); cachepage(np, p->image); unlockpage(np); uncachepage(p); | |
| 1990/0227 | } void | |
| 1991/0705 | copypage(Page *f, Page *t) | |
| 1990/0227 | { | |
| 1991/0705 | KMap *ks, *kd; | |
| 1990/0227 | ||
| 1991/0705 | ks = kmap(f); kd = kmap(t); memmove((void*)VA(kd), (void*)VA(ks), BY2PG); kunmap(ks); kunmap(kd); | |
| 1990/0227 | } void | |
| 1991/0718 | uncachepage(Page *p) /* Always called with a locked page */ | |
| 1990/0227 | { | |
| 1991/0705 | Page **l, *f; | |
| 1990/0227 | ||
| 1991/0705 | if(p->image) { lock(&palloc.hashlock); l = &pghash(p); for(f = *l; f; f = f->hash) { if(f == p) { *l = p->hash; break; | |
| 1990/0227 | } | |
| 1991/0705 | l = &f->hash; | |
| 1990/0227 | } | |
| 1991/0705 | unlock(&palloc.hashlock); putimage(p->image); p->image = 0; | |
| 1990/0227 | } } | |
| 1991/0705 | void cachepage(Page *p, Image *i) | |
| 1990/0227 | { | |
| 1991/0705 | Page **l; | |
| 1990/0227 | ||
| 1991/0705 | incref(i); lock(&palloc.hashlock); p->image = i; l = &pghash(p); p->hash = *l; *l = p; unlock(&palloc.hashlock); | |
| 1990/0227 | } | |
| 1991/0705 | Page * lookpage(Image *i, ulong daddr) | |
| 1990/0227 | { | |
| 1991/0705 | Page *f; | |
| 1990/0227 | ||
| 1991/0705 | lock(&palloc.hashlock); for(f = palloc.hash[PGHFUN(i, daddr)]; f; f = f->hash) { if(f->image == i && f->daddr == daddr) { unlock(&palloc.hashlock); lockpage(f); if(f->image != i || f->daddr != daddr) { unlockpage(f); return 0; | |
| 1990/0227 | } | |
| 1991/0705 | lock(&palloc); if(++f->ref == 1) { if(f->prev) f->prev->next = f->next; else palloc.head = f->next; if(f->next) f->next->prev = f->prev; else palloc.tail = f->prev; palloc.freecount--; } unlock(&palloc); unlockpage(f); return f; | |
| 1990/0227 | } | |
| 1991/0607 | } | |
| 1991/0705 | unlock(&palloc.hashlock); return 0; | |
| 1990/0227 | } | |
| 1991/0705 | Pte* ptecpy(Pte *old) | |
| 1990/0227 | { | |
| 1991/0705 | Page **src, **dst, **end; Pte *new; | |
| 1990/0227 | ||
| 1991/0705 | new = ptealloc(); | |
| 1991/1122 | dst = &new->pages[old->first-old->pages]; new->first = dst; for(src = old->first; src <= old->last; src++, dst++) | |
| 1991/0705 | if(*src) { if(onswap(*src)) dupswap(*src); else { lockpage(*src); (*src)->ref++; unlockpage(*src); } | |
| 1991/1122 | new->last = dst; | |
| 1991/0705 | *dst = *src; | |
| 1990/0227 | } | |
| 1990/0802 | ||
| 1991/0705 | return new; | |
| 1990/0227 | } | |
| 1991/0705 | Pte* ptealloc(void) | |
| 1990/0227 | { | |
| 1991/0705 | Pte *new; int i, n; KMap *k; | |
| 1990/0227 | ||
| 1991/0705 | lock(&ptealloclk); while(ptealloclk.free == 0) { unlock(&ptealloclk); | |
| 1992/0131 | k = kmap(newpage(1, 0, 0)); | |
| 1991/0705 | new = (Pte*)VA(k); n = (BY2PG/sizeof(Pte))-1; for(i = 0; i < n; i++) new[i].next = &new[i+1]; lock(&ptealloclk); ptealloclk.pages++; new[i].next = ptealloclk.free; ptealloclk.free = new; | |
| 1990/0227 | } | |
| 1991/0705 | new = ptealloclk.free; ptealloclk.free = new->next; unlock(&ptealloclk); | |
| 1991/1122 | new->first = &new->pages[PTEPERTAB]; new->last = new->pages; | |
| 1992/0131 | ||
| 1991/0705 | return new; | |
| 1991/0606 | } | |
| 1991/0705 | void freepte(Segment *s, Pte *p) | |
| 1991/0606 | { | |
| 1991/0705 | Page **pg, **ptop; | |
| 1991/0606 | ||
| 1991/0705 | switch(s->type&SG_TYPE) { case SG_PHYSICAL: | |
| 1991/1122 | ptop = &p->pages[PTEPERTAB]; | |
| 1991/0705 | for(pg = p->pages; pg < ptop; pg++) | |
| 1992/0131 | if(*pg) { | |
| 1991/0705 | (*s->pgfree)(*pg); | |
| 1992/0131 | *pg = 0; } | |
| 1991/0705 | break; default: | |
| 1991/1122 | for(pg = p->first; pg <= p->last; pg++) | |
| 1992/0131 | if(*pg) { | |
| 1991/0705 | putpage(*pg); | |
| 1992/0131 | *pg = 0; } | |
| 1991/0606 | } | |
| 1991/0705 | lock(&ptealloclk); p->next = ptealloclk.free; ptealloclk.free = p; unlock(&ptealloclk); | |
| 1990/0227 | } | |