| plan 9 kernel history: overview | file list | diff list |
1990/1226/ss/mmu.c (diff list | history)
| ss/mmu.c on 1990/1223 | ||
| 1990/1223 | #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1990/1226 | #include "io.h" | |
| 1990/1223 | struct { Lock; int init; | |
| 1990/1226 | int lowpmeg; | |
| 1990/1223 | KMap *free; | |
| 1990/1226 | KMap arena[(IOEND-IOSEGM)/BY2PG]; | |
| 1990/1223 | }kmapalloc; /* | |
| 1990/1226 | * On SPARC, tlbpid i == context i-1 so that 0 means unallocated */ int newpid(Proc*); void purgepid(int); /* | |
| 1990/1223 | * Called splhi, not in Running state */ void mapstack(Proc *p) { | |
| 1990/1226 | short tp; ulong tlbphys; | |
| 1990/1223 | ||
| 1990/1226 | tp = p->pidonmach[m->machno]; if(tp == 0){ tp = newpid(p); p->pidonmach[m->machno] = tp; } | |
| 1990/1223 | if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); | |
| 1990/1226 | /* don't set m->pidhere[*tp] because we're only writing U entry */ tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; putcontext(tp-1); putpmeg(USERADDR, tlbphys); | |
| 1990/1223 | u = (User*)USERADDR; | |
| 1990/1226 | } | |
| 1990/1223 | ||
| 1990/1226 | /* * Process must be non-interruptible */ int newpid(Proc *p) { int i, j; Proc *sp; i = m->lastpid+1; if(i >= NCONTEXT+1) i = 1; sp = m->pidproc[i]; if(sp){ sp->pidonmach[m->machno] = 0; purgepid(i); } m->pidproc[i] = p; m->lastpid = i; print("new context %d\n", i); | |
| 1990/1223 | /* | |
| 1990/1226 | * kludge: each context is allowed 2 pmegs, one for text and one for stack | |
| 1990/1223 | */ | |
| 1990/1226 | putsegm(UZERO, kmapalloc.lowpmeg+(2*i)); putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+1); for(j=0; j<PG2SEGM; j++){ putpmeg(UZERO+j*BY2PG, INVALIDPTE); putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); } return i; } | |
| 1990/1223 | ||
| 1990/1226 | void purgepid(int pid) { int i, rpid; | |
| 1990/1223 | ||
| 1990/1226 | if(m->pidhere[pid] == 0) return; print("purge pid %d\n", pid); memset(m->pidhere, 0, sizeof m->pidhere); putcontext(pid-1); /* * Clear context from cache */ for(i=0; i<0x1000; i++) putwE((i<<4), 0); print("purge done\n"); | |
| 1990/1223 | } | |
| 1990/1226 | ||
| 1990/1223 | void | |
| 1990/1226 | mmuinit(void) | |
| 1990/1223 | { | |
| 1990/1226 | ulong l, i, j, c, pte; /* * First map lots of memory as kernel addressable in all contexts */ i = 0; /* used */ for(c=0; c<NCONTEXT; c++) for(i=0; i<conf.maxialloc/BY2SEGM; i++) putcxsegm(c, KZERO+i*BY2SEGM, i); kmapalloc.lowpmeg = i; /* * Make sure cache is turned on for kernel */ pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; for(i=0; i<conf.maxialloc/BY2PG; i++) putpmeg(KZERO+i*BY2PG, pte+i); /* * Create invalid pmeg; use highest segment */ putsegm(INVALIDSEGM, INVALIDPMEG); for(i=0; i<PG2SEGM; i++) putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE); for(c=0; c<NCONTEXT; c++){ putcontext(c); putsegm(INVALIDSEGM, INVALIDPMEG); /* * Invalidate user addresses */ /* for(l=UZERO; l<KZERO; l+=BY2SEGM) putsegm(l, INVALIDPMEG); */ putsegm(0x0000, INVALIDPMEG); /* * One segment for screen */ putsegm(SCREENSEGM, SCREENPMEG); if(c == 0){ pte = PTEVALID|PTEWRITE|PTEKERNEL|PTENOCACHE| PTEIO|((DISPLAYRAM>>PGSHIFT)&0xFFFF); for(i=0; i<PG2SEGM; i++) putpmeg(SCREENSEGM+i*BY2PG, pte+i); } /* * First page of IO space includes ROM; be careful */ putsegm(IOSEGM0, IOPMEG0); /* IOSEGM == ROMSEGM */ if(c == 0){ pte = PTEVALID|PTEKERNEL|PTENOCACHE| PTEIO|((EPROM>>PGSHIFT)&0xFFFF); for(i=0; i<PG2ROM; i++) putpmeg(IOSEGM0+i*BY2PG, pte+i); for(; i<PG2SEGM; i++) putpmeg(IOSEGM0+i*BY2PG, INVALIDPTE); } /* * Remaining segments for IO and kmap */ for(j=1; j<NIOSEGM; j++){ putsegm(IOSEGM0+j*BY2SEGM, IOPMEG0+j); if(c == 0) for(i=0; i<PG2SEGM; i++) putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE); } } putcontext(0); | |
| 1990/1223 | } | |
| 1990/1226 | ||
| 1990/1223 | void putmmu(ulong tlbvirt, ulong tlbphys) { | |
| 1990/1226 | short tp; Proc *p; | |
| 1990/1223 | ||
| 1990/1226 | splhi(); p = u->p; /* if(p->state != Running) panic("putmmu state %lux %lux %s\n", u, p, statename[p->state]); */ p->state = MMUing; tp = p->pidonmach[m->machno]; if(tp == 0){ tp = newpid(p); p->pidonmach[m->machno] = tp; | |
| 1990/1223 | } | |
| 1990/1226 | /* * kludge part 2: make sure we've got a valid segment */ if(tlbvirt>=TSTKTOP || (UZERO+BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))) panic("putmmu %lux", tlbvirt); putpmeg(tlbvirt, tlbphys); m->pidhere[tp] = 1; p->state = Running; spllo(); | |
| 1990/1223 | } void flushmmu(void) { | |
| 1990/1226 | splhi(); /* easiest is to forget what pid we had.... */ memset(u->p->pidonmach, 0, sizeof u->p->pidonmach); /* ....then get a new one by trying to map our stack */ mapstack(u->p); spllo(); | |
| 1990/1223 | } void | |
| 1990/1226 | cacheinit(void) | |
| 1990/1223 | { | |
| 1990/1226 | int i; /* * Initialize cache by clearing the valid bit * (along with the others) in all cache entries */ for(i=0; i<0x1000; i++) putw2(CACHETAGS+(i<<4), 0); /* * Turn cache on */ putb2(ENAB, getb2(ENAB)|ENABCACHE); /**/ | |
| 1990/1223 | } void kmapinit(void) { KMap *k; | |
| 1990/1226 | int i; | |
| 1990/1223 | ||
| 1990/1226 | print("low pmeg %d\n", kmapalloc.lowpmeg); | |
| 1990/1223 | kmapalloc.free = 0; | |
| 1990/1226 | k = kmapalloc.arena; for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ k->va = IOSEGM+i*BY2PG; | |
| 1990/1223 | kunmap(k); } } KMap* | |
| 1990/1226 | kmap1(Page *pg, ulong flag) | |
| 1990/1223 | { KMap *k; lock(&kmapalloc); k = kmapalloc.free; if(k == 0){ dumpstack(); panic("kmap"); } kmapalloc.free = k->next; unlock(&kmapalloc); k->pa = pg->pa; | |
| 1990/1226 | /* * Cache is virtual and a pain to deal with. * Must avoid having the same entry in the cache twice, so * must use NOCACHE or else extreme cleverness elsewhere. */ putpmeg(k->va, PPN(k->pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); | |
| 1990/1223 | return k; } | |
| 1990/1226 | KMap* kmap(Page *pg) { return kmap1(pg, PTEMAINMEM); } | |
| 1990/1223 | void kunmap(KMap *k) { | |
| 1990/1226 | ulong pte; int i; | |
| 1990/1223 | k->pa = 0; lock(&kmapalloc); k->next = kmapalloc.free; kmapalloc.free = k; | |
| 1990/1226 | putpmeg(k->va, INVALIDPTE); | |
| 1990/1223 | unlock(&kmapalloc); } void invalidateu(void) { | |
| 1990/1226 | putpmeg(USERADDR, INVALIDPTE); | |
| 1990/1223 | } | |