#include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" struct { Lock; int init; int lowpmeg; KMap *free; KMap arena[(IOEND-IOSEGM)/BY2PG]; }kmapalloc; /* * On SPARC, tlbpid i == context i-1 so that 0 means unallocated */ int newpid(Proc*); void purgepid(int); /* * Called splhi, not in Running state */ void mapstack(Proc *p) { short tp; ulong tlbphys; tp = p->pidonmach[m->machno]; if(tp == 0){ tp = newpid(p); p->pidonmach[m->machno] = tp; } if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); /* 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); /* * putw4(USERADDR, tlbphys) might be good enough but * there is that fuss in pexit/pwait() copying between * u areas and that might surprise any cache entries */ putpmeg(USERADDR, tlbphys); u = (User*)USERADDR; } /* * 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); putcontext(i-1); /* * kludge: each context is allowed 2 pmegs, one for text and one for stack */ putsegm(UZERO, kmapalloc.lowpmeg+(2*i)); putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+1); for(j=0; jpidhere[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"); } void mmuinit(void) { ulong l, i, j, c, pte; /* * First map lots of memory as kernel addressable in all contexts */ i = 0; /* used */ for(c=0; c>PGSHIFT)&0xFFFF); for(i=0; i>PGSHIFT)&0xFFFF); for(i=0; ip; /* 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; } /* * 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(); } void putpmeg(ulong virt, ulong phys) { int i; virt &= VAMASK; virt &= ~(BY2PG-1); /* * Flush old entries from cache */ for(i=0; i<0x100; i++) putwD(virt+(i<<4), 0); putw4(virt, phys); } void flushmmu(void) { 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(); } void cacheinit(void) { 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); /**/ } void kmapinit(void) { KMap *k; int i; kmapalloc.free = 0; k = kmapalloc.arena; for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ k->va = IOSEGM+i*BY2PG; kunmap(k); } } KMap* kmappa(ulong pa, ulong flag) { KMap *k; lock(&kmapalloc); k = kmapalloc.free; if(k == 0){ dumpstack(); panic("kmap"); } kmapalloc.free = k->next; unlock(&kmapalloc); k->pa = pa; /* * 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(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); return k; } KMap* kmap(Page *pg) { return kmappa(pg->pa, PTEMAINMEM); } void kunmap(KMap *k) { ulong pte; int i; k->pa = 0; lock(&kmapalloc); k->next = kmapalloc.free; kmapalloc.free = k; putpmeg(k->va, INVALIDPTE); unlock(&kmapalloc); } void invalidateu(void) { putpmeg(USERADDR, INVALIDPTE); }