| plan 9 kernel history: overview | file list | diff list |
1991/0115/ss/mmu.c (diff list | history)
| 1991/0115/sys/src/9/ss/mmu.c:1,363 – 1991/01151/sys/src/9/ss/mmu.c:1,355 (short | long | prev | next) | ||
| 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; | |
| 1991/0111 | #define NKLUDGE 12 | |
| 1991/0110 | ||
| 1990/1223 | /* | |
| 1990/1226 | * On SPARC, tlbpid i == context i-1 so that 0 means unallocated */ int newpid(Proc*); void purgepid(int); | |
| 1991/0110 | int pidtime[NTLBPID]; /* should be per m */ | |
| 1990/1226 | /* | |
| 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))) | |
| 1991/0110 | panic("mapstack %s %d %lux 0x%lux 0x%lux", p->text, p->pid, p->upage, p->upage->pa, p->upage->va); | |
| 1990/1226 | tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; putcontext(tp-1); | |
| 1990/1227 | /* | |
| 1991/0110 | * shouldn't need putpmeg because nothing has been mapped at * USERADDR in this context except this page. however, it crashes. | |
| 1990/1227 | */ | |
| 1990/1226 | putpmeg(USERADDR, tlbphys); | |
| 1990/1223 | u = (User*)USERADDR; | |
| 1990/1226 | } | |
| 1990/1223 | ||
| 1990/1226 | /* * Process must be non-interruptible */ int newpid(Proc *p) { | |
| 1991/0109 | int i, j, k; | |
| 1991/0110 | ulong t; | |
| 1990/1226 | Proc *sp; | |
| 1991/0110 | t = ~0; i = 1+((m->ticks)&(NCONTEXT-1)); /* random guess */ for(j=1; j<NTLBPID; j++) if(pidtime[j] < t){ i = j; t = pidtime[j]; } | |
| 1990/1226 | sp = m->pidproc[i]; | |
| 1991/0115 | if(sp) | |
| 1990/1226 | sp->pidonmach[m->machno] = 0; | |
| 1991/0115 | purgepid(i); /* also does putcontext */ | |
| 1991/0110 | pidtime[i] = m->ticks; | |
| 1990/1226 | m->pidproc[i] = p; m->lastpid = i; | |
| 1991/0111 | ||
| 1990/1223 | /* | |
| 1991/0112 | * kludge: each context is allowed NKLUDGE pmegs. * NKLUDGE-1 for text & data and 1 for stack. * initialize by giving just a stack segment. | |
| 1990/1223 | */ | |
| 1991/0112 | i--; /* now i==context */ p->nmmuseg = 0; | |
| 1991/0110 | for(j=0; j<NKLUDGE-1; j++) | |
| 1991/0112 | putsegm(UZERO+j*BY2SEGM, INVALIDPMEG); putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+NKLUDGE*i+(NKLUDGE-1)); for(j=0; j<PG2SEGM; j++) | |
| 1990/1226 | putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); | |
| 1991/0112 | return i+1; | |
| 1990/1226 | } | |
| 1990/1223 | ||
| 1990/1226 | void | |
| 1990/1231 | putcontext(int c) { putcxreg(c); } void | |
| 1991/0110 | flushcontext(void) | |
| 1990/1226 | { | |
| 1991/0110 | int i; | |
| 1990/1223 | ||
| 1991/0110 | /* * Clear context from cache */ for(i=0; i<0x1000; i+=16) putwE16((i<<4), 0); } void purgepid(int pid) { | |
| 1990/1226 | putcontext(pid-1); | |
| 1991/0110 | flushcontext(); | |
| 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 */ | |
| 1990/1227 | for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM) | |
| 1990/1226 | putsegm(l, INVALIDPMEG); | |
| 1990/1227 | ||
| 1991/0111 |
| |
| 1990/1226 |
| |
| 1991/0111 |
| |
| 1990/1226 | * 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 | } void putmmu(ulong tlbvirt, ulong tlbphys) { | |
| 1990/1226 | short tp; Proc *p; | |
| 1991/0112 | ulong seg, l; int j, k; | |
| 1990/1223 | ||
| 1990/1226 | splhi(); p = u->p; 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 */ | |
| 1991/0112 | if(TSTKTOP-BY2SEGM<=tlbvirt && tlbvirt<TSTKTOP) /* stack; easy */ goto put; /* UZERO is known to be zero here */ if(tlbvirt < UZERO+p->nmmuseg*BY2SEGM) /* in range; easy */ goto put; seg = tlbvirt/BY2SEGM; if(seg >= (UZERO/BY2SEGM)+(NKLUDGE-1)){ pprint("putmmu %lux\n", tlbvirt); print("putmmu %lux %d %s\n", tlbvirt, seg, p->text); | |
| 1991/0111 | pexit("Suicide", 1); | |
| 1991/0110 | } | |
| 1991/0112 | /* * Prepare mmu up to this address */ | |
| 1991/0115 | tp = (tp-1)*NKLUDGE; /* now tp==base of pmeg area for this proc */ | |
| 1991/0112 | l = UZERO+p->nmmuseg*BY2SEGM; for(j=p->nmmuseg; j<=seg; j++){ putsegm(l, kmapalloc.lowpmeg+tp+j); for(k=0; k<PG2SEGM; k++,l+=BY2PG) putpmeg(l, INVALIDPTE); } p->nmmuseg = seg+1; put: | |
| 1990/1226 | putpmeg(tlbvirt, tlbphys); spllo(); | |
| 1990/1223 | } void | |
| 1990/1227 | putpmeg(ulong virt, ulong phys) { int i; | |
| 1990/1231 | int tp; | |
| 1990/1227 | virt &= VAMASK; virt &= ~(BY2PG-1); /* * Flush old entries from cache */ | |
| 1991/0110 | for(i=0; i<0x100; i+=16) putwD16(virt+(i<<4), 0); | |
| 1990/1227 | putw4(virt, phys); } void | |
| 1990/1223 | flushmmu(void) { | |
| 1991/0110 | int tp; | |
| 1990/1226 | splhi(); | |
| 1991/0110 | flushcontext(); tp = u->p->pidonmach[m->machno]; if(tp) pidtime[tp] = 0; | |
| 1990/1226 | /* 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 | { | |
| 1991/0110 | int c, i; | |
| 1990/1226 | /* * Initialize cache by clearing the valid bit * (along with the others) in all cache entries */ | |
| 1991/0110 | for(c=0; c<NCONTEXT; c++){ /* necessary? */ putcontext(c); for(i=0; i<0x1000; i++) putw2(CACHETAGS+(i<<4), 0); } putcontext(0); | |
| 1990/1226 | /* * Turn cache on */ putb2(ENAB, getb2(ENAB)|ENABCACHE); /**/ | |
| 1990/1223 | } void kmapinit(void) { KMap *k; | |
| 1990/1226 | int i; | |
| 1990/1223 | ||
| 1991/0110 | print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG); | |
| 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/1227 | kmappa(ulong pa, ulong flag) | |
| 1990/1223 | { KMap *k; | |
| 1991/0110 | ulong s; | |
| 1990/1223 | lock(&kmapalloc); k = kmapalloc.free; if(k == 0){ dumpstack(); panic("kmap"); } kmapalloc.free = k->next; unlock(&kmapalloc); | |
| 1990/1227 | k->pa = 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. */ | |
| 1991/0110 | s = splhi(); | |
| 1990/1227 | putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); | |
| 1991/0110 | splx(s); | |
| 1990/1223 | return k; } | |
| 1990/1226 | KMap* kmap(Page *pg) { | |
| 1990/1227 | return kmappa(pg->pa, PTEMAINMEM); | |
| 1990/1226 | } | |
| 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 | } | |