## diffname ss/mmu.c 1990/1223 ## diff -e /dev/null /n/bootesdump/1990/1223/sys/src/9/sparc/mmu.c 0a #include "u.h" #include "lib.h" #include "mem.h" #include "dat.h" #include "fns.h" struct { Lock; int init; KMap *free; KMap arena[4*1024*1024/BY2PG]; /* kernel mmu maps up to 4MB */ }kmapalloc; /* * Called splhi, not in Running state */ void mapstack(Proc *p) { ulong tlbvirt, tlbphys; ulong next; MMU *mm, *mn, *me; if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); tlbvirt = USERADDR; tlbphys = PPN(p->upage->pa) | PTEVALID | PTEKERNEL; putkmmu(tlbvirt, tlbphys); u = (User*)USERADDR; /* * if not a kernel process and this process was not the * last process on this machine, flush & preload mmu */ if(!p->kp && p!=m->lproc){ flushmmu(); /* * preload the MMU with the last (up to) NMMU user entries * previously faulted into it for this process. */ mn = &u->mc.mmu[u->mc.next&(NMMU-1)]; me = &u->mc.mmu[NMMU]; if(u->mc.next >= NMMU){ for(mm = mn; mm < me; mm++) UMAP[mm->va] = mm->pa; } for(mm = u->mc.mmu; mm < mn; mm++) UMAP[mm->va] = mm->pa; m->lproc = p; } } void putkmmu(ulong tlbvirt, ulong tlbphys) { if(!(tlbvirt&KZERO)) panic("putkmmu"); tlbvirt &= ~KZERO; KMAP[(tlbvirt&0x003FE000L)>>2] = tlbphys; } void putmmu(ulong tlbvirt, ulong tlbphys) { if(tlbvirt&KZERO) panic("putmmu"); tlbphys |= VTAG(tlbvirt)<<24; tlbvirt = (tlbvirt&0x003FE000L)>>2; if(u){ MMU *mp; int s; s = splhi(); mp = &(u->mc.mmu[u->mc.next&(NMMU-1)]); mp->pa = tlbphys; mp->va = tlbvirt; u->mc.next++; splx(s); } UMAP[tlbvirt] = tlbphys; } void flushmmu(void) { flushcpucache(); *PARAM &= ~TLBFLUSH_; *PARAM |= TLBFLUSH_; } void clearmmucache(void) { if(u == 0) panic("flushmmucache"); u->mc.next = 0; } void kmapinit(void) { KMap *k; int i, e; if(kmapalloc.init == 0){ k = &kmapalloc.arena[0]; k->va = KZERO|(4*1024*1024-256*1024-BY2PG); k->next = 0; kmapalloc.free = k; kmapalloc.init = 1; return; } e = (4*1024*1024 - 256*1024)/BY2PG; /* screen lives at top 256K */ i = (((ulong)ialloc(0, 0))&~KZERO)/BY2PG; print("%lud free map registers\n", e-i); kmapalloc.free = 0; for(k=&kmapalloc.arena[i]; iva = i*BY2PG|KZERO; kunmap(k); } } KMap* kmap(Page *pg) { KMap *k; lock(&kmapalloc); k = kmapalloc.free; if(k == 0){ dumpstack(); panic("kmap"); } kmapalloc.free = k->next; unlock(&kmapalloc); k->pa = pg->pa; putkmmu(k->va, PPN(k->pa) | PTEVALID | PTEKERNEL); return k; } void kunmap(KMap *k) { k->pa = 0; lock(&kmapalloc); k->next = kmapalloc.free; kmapalloc.free = k; putkmmu(k->va, INVALIDPTE); unlock(&kmapalloc); } void invalidateu(void) { putkmmu(USERADDR, INVALIDPTE); } . ## diffname ss/mmu.c 1990/1226 ## diff -e /n/bootesdump/1990/1223/sys/src/9/sparc/mmu.c /n/bootesdump/1990/1226/sys/src/9/sparc/mmu.c 158c putpmeg(USERADDR, INVALIDPTE); . 151c putpmeg(k->va, INVALIDPTE); . 146a ulong pte; int i; . 143a KMap* kmap(Page *pg) { return kmap1(pg, PTEMAINMEM); } . 140c /* * 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); . 127c kmap1(Page *pg, ulong flag) . 120,121c k = kmapalloc.arena; for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ k->va = IOSEGM+i*BY2PG; . 108,118c print("low pmeg %d\n", kmapalloc.lowpmeg); . 106c int i; . 97,99c 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); /**/ . 95c cacheinit(void) . 89,91c 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(); . 83c /* * 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(); . 76,81c 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; . 68,74c short tp; Proc *p; . 64a . 59,62c 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; ipidhere[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"); . 39,50c void purgepid(int pid) { int i, rpid; . 36,37c putsegm(UZERO, kmapalloc.lowpmeg+(2*i)); putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+1); for(j=0; jlastpid+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); . 30a } . 27,29c /* 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); . 24a tp = p->pidonmach[m->machno]; if(tp == 0){ tp = newpid(p); p->pidonmach[m->machno] = tp; } . 21,23c short tp; ulong tlbphys; . 15a * On SPARC, tlbpid i == context i-1 so that 0 means unallocated */ int newpid(Proc*); void purgepid(int); /* . 12c KMap arena[(IOEND-IOSEGM)/BY2PG]; . 10a int lowpmeg; . 5a #include "io.h" . ## diffname ss/mmu.c 1990/1227 ## diff -e /n/bootesdump/1990/1226/sys/src/9/sparc/mmu.c /n/bootesdump/1990/1227/sys/src/9/sparc/mmu.c 271c return kmappa(pg->pa, PTEMAINMEM); . 264c putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); . 258c k->pa = pa; . 246c kmappa(ulong pa, ulong flag) . 236d 202a 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 . 171,173d 134,135c . 131,132c for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM) . 66a putcontext(i-1); . 42a /* * 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 */ . ## diffname ss/mmu.c 1990/1231 ## diff -e /n/bootesdump/1990/1227/sys/src/9/sparc/mmu.c /n/bootesdump/1990/1231/sys/src/9/sparc/mmu.c 215a if(u && u->p) m->pidhere[u->p->pidonmach[m->machno]] = 1; /* UGH! */ . 207a int tp; . 199,200d 184,187d 85a putcontext(int c) { m->pidhere[c] = 1; putcxreg(c); } void . 71d ## diffname ss/mmu.c 1991/0108 ## diff -e /n/bootesdump/1990/1231/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0108/sys/src/9/sparc/mmu.c 177a /* * Lance */ putsegm(LANCESEGM, LANCEPMEG); . ## diffname ss/mmu.c 1991/0109 ## diff -e /n/bootesdump/1991/0108/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0109/sys/src/9/sparc/mmu.c 202c if(tlbvirt>=TSTKTOP || (UZERO+4*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))) . 106c /* print("purge done\n");/**/ . 98c /* print("purge pid %d\n", pid);/**/ . 78c for(k=0; k<4; k++) putpmeg(UZERO+k*BY2SEGM+j*BY2PG, INVALIDPTE); . 75,76c for(j=0; j<4; j++) putsegm(UZERO, kmapalloc.lowpmeg+(2*i)+j); putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+4); . 73c * kludge: each context is allowed 5 pmegs, four for text & data and one for stack . 71a /* print("new pid %d\n", i); /**/ . 58c int i, j, k; . ## diffname ss/mmu.c 1991/0110 ## diff -e /n/bootesdump/1991/0109/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0110/sys/src/9/sparc/mmu.c 290a #endif splx(s); . 289a s = splhi(); #ifdef stupid { int i, c, d; c = u->p->pidonmach[m->machno]; /* * Flush old entries from cache */ for(d=0; dva+(i<<4), 0); } putcontext(c-1); if(u && u->p) m->pidhere[c] = 1; /* UGH! */ putw4(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); } #else . 274a ulong s; . 262a print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG); . 249,250c for(c=0; cp->pidonmach[m->machno]; if(tp) pidtime[tp] = 0; . 231a int tp; . 222,223c for(i=0; i<0x100; i+=16) putwD16(virt+(i<<4), 0); . 205,206c if(tlbvirt>=TSTKTOP || (UZERO+(NKLUDGE-1)*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))){ pprint("putmmu %lux", tlbvirt); pexit("Suicide", 0); } . 181,184d 132d 104,109c flushcontext(); . 101d 98a /* * Clear context from cache */ for(i=0; i<0x1000; i+=16) putwE16((i<<4), 0); } void purgepid(int pid) { . 97c int i; . 95c flushcontext(void) . 90c m->pidhere[c+1] = 1; . 80c for(k=0; kticks; . 61,63c t = ~0; i = 1+((m->ticks)&(NCONTEXT-1)); /* random guess */ for(j=1; jtext, p->pid, p->upage, p->upage->pa, p->upage->va); . 22a int pidtime[NTLBPID]; /* should be per m */ . 16a #define NKLUDGE 8 . ## diffname ss/mmu.c 1991/0111 ## diff -e /n/bootesdump/1991/0110/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0111/sys/src/9/sparc/mmu.c 332d 312,330d 213c pexit("Suicide", 1); . 160a * Invalidate high kernel addresses */ for(l=conf.maxialloc; lnmmuseg*BY2SEGM; for(j=p->nmmuseg; j<=seg; j++){ putsegm(l, kmapalloc.lowpmeg+tp+j); for(k=0; knmmuseg = seg+1; put: . 219,220c if(TSTKTOP-BY2SEGM<=tlbvirt && tlbvirtnmmuseg*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); . 207a ulong seg, l; int j, k; . 91,92c return i+1; . 85,89c putsegm(UZERO+j*BY2SEGM, INVALIDPMEG); putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+NKLUDGE*i+(NKLUDGE-1)); for(j=0; jnmmuseg = 0; . 82c * kludge: each context is allowed NKLUDGE pmegs. * NKLUDGE-1 for text & data and 1 for stack. * initialize by giving just a stack segment. . ## diffname ss/mmu.c 1991/0115 ## diff -e /n/bootesdump/1991/0112/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0115/sys/src/9/sparc/mmu.c 263,264d 236,237c tp = (tp-1)*NKLUDGE; /* now tp==base of pmeg area for this proc */ . 118,120d 99d 79d 74,75c purgepid(i); /* also does putcontext */ . 72c if(sp) . ## diffname ss/mmu.c 1991/01151 ## diff -e /n/bootesdump/1991/0115/sys/src/9/sparc/mmu.c /n/bootesdump/1991/01151/sys/src/9/sparc/mmu.c 155,162d ## diffname ss/mmu.c 1991/0507 ## diff -e /n/bootesdump/1991/0201/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0507/sys/src/9/slc/mmu.c 52a void mmurelease(Proc *p) { memset(p->pidonmach, 0, sizeof p->pidonmach); } . ## diffname ss/mmu.c 1991/0706 ## diff -e /n/bootesdump/1991/0507/sys/src/9/slc/mmu.c /n/bootesdump/1991/0706/sys/src/9/slc/mmu.c 197c putmmu(ulong tlbvirt, ulong tlbphys, Page *pg) . 35a if(p->newtlb) { flushcontext(); tp = u->p->pidonmach[m->machno]; if(tp) pidtime[tp] = 0; /* easiest is to forget what pid we had.... */ memset(u->p->pidonmach, 0, sizeof u->p->pidonmach); p->newtlb = 0; } . 24a void flushcontext(void); . ## diffname ss/mmu.c 1991/0928 ## diff -e /n/bootesdump/1991/0706/sys/src/9/slc/mmu.c /n/bootesdump/1991/0928/sys/src/9/slc/mmu.c 53c if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) . ## diffname ss/mmu.c 1991/1007 ## diff -e /n/bootesdump/1991/0928/sys/src/9/slc/mmu.c /n/bootesdump/1991/1007/sys/src/9/slc/mmu.c 275,281c u->p->newtlb = 1; . 273a nflushmmu++; . 269a putpmegnf(ulong virt, ulong phys) /* no need to flush */ { virt &= VAMASK; virt &= ~(BY2PG-1); putw4(virt, phys); } int nflushmmu; void . 245c putpmegnf(l, INVALIDPTE); . 108c putpmegnf((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); . 83c for(j=1; t && jpidonmach[m->machno]; if(tp) pidtime[tp] = 0; /* easiest is to forget what pid we had.... */ . 61c putpmegnf(USERADDR, tlbphys); . 58,59c * Don't need to flush cache because no other page has been * mapped at USERADDR in this context; can call putpmegnf. . 39,44c mmurelease(p); . 25a void putpmegnf(ulong, ulong); . ## diffname ss/mmu.c 1992/0101 ## diff -e /n/bootesdump/1991/1007/sys/src/9/slc/mmu.c /n/bootesdump/1992/0101/sys/src/9/slc/mmu.c 357a /* * Here we know it's a permanent entry and can be cached. */ . 356c kmapperm(Page *pg) . 349,352c return kmappa(pg->pa, PTEMAINMEM|PTENOCACHE); . 343a s = splhi(); putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag); splx(s); return k; } KMap* kmap(Page *pg) { . ## diffname ss/mmu.c 1992/0321 ## diff -e /n/bootesdump/1992/0101/sys/src/9/slc/mmu.c /n/bootesdump/1992/0321/sys/src/9/slc/mmu.c 2c #include "../port/lib.h" . ## diffname ss/mmu.c 1992/0619 ## diff -e /n/bootesdump/1992/0321/sys/src/9/slc/mmu.c /n/bootesdump/1992/0619/sys/src/9/slc/mmu.c 320c print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG); . 165a . 157c ktop /= BY2PG; for(i=0; i < ktop; i++) . 152a . 151a . 150c for(i=0; i < ktop/BY2SEGM; i++) . 145a * TEMP: just map the first 4M of bank 0 for the kernel - philw */ ktop = 4*1024*1024; /* . 143c ulong ktop, l, i, j, c, pte; . 139d ## diffname ss/mmu.c 1992/0711 ## diff -e /n/bootesdump/1992/0619/sys/src/9/slc/mmu.c /n/bootesdump/1992/0711/sys/src/9/slc/mmu.c 381,383d 290,291d 266d 224a USED(pg); . 79c int i, j; . ## diffname ss/mmu.c 1992/0722 ## diff -e /n/bootesdump/1992/0711/sys/src/9/slc/mmu.c /n/bootesdump/1992/0722/sys/src/9/slc/mmu.c 273,274c for(i=0; i>10);} void compile(void) { putcontext = compileconst(STBA, CONTEXT, 2); getenab = compileconst(LDUBA, ENAB, 2); putenab = compileconst(STBA, ENAB, 2); putpmegspace = compilestaddr(STA, 4); putsysspace = compilestaddr(STA, 2); getsysspace = compileldaddr(LDA, 2); if(conf.ss2){ flushpg = compile1(BY2PG, 6); flushcx = compile16(VACLINESZ, 7); }else{ flushpg = compile16(VACLINESZ, 0xD); flushcx = compile16(VACLINESZ, 0xE); } } void parameter(int param, int reg) { param += 1; /* 0th parameter is 1st word on stack */ param *= 4; /* LD #param(R1), Rreg */ *codep++ = (3<<30)|(reg<<25)|(LD<<19)|(1<<14)|(1<<13)|param; } void constant(ulong c, int reg) { *codep++ = (0<<30)|(reg<<25)|(SETHI<<22)|(c>>10); if(c & 0x3FF) *codep++ = (2<<30)|(reg<<25)|(OR<<19)|(reg<<14)|(1<<13)|(c&0x3FF); } /* * void f(int c) { *(word*,asi)addr = c } for stores * ulong f(void) { return *(word*,asi)addr } for loads */ void* compileconst(int op3, ulong addr, int asi) { void *a; a = codep; constant(addr, 8); /* MOVW $CONSTANT, R8 */ ret(); /* JMPL 8(R15), R0 */ /* in delay slot st or ld R7, (R8+R0, asi) */ *codep++ = (3<<30)|(7<<25)|(op3<<19)|(8<<14)|(asi<<5); return a; } /* * ulong f(ulong addr) { return *(word*,asi)addr } */ void* compileldaddr(int op3, int asi) { void *a; a = codep; ret(); /* JMPL 8(R15), R0 */ /* in delay slot ld (R7+R0, asi), R7 */ *codep++ = (3<<30)|(7<<25)|(op3<<19)|(7<<14)|(asi<<5); return a; } /* * void f(ulong addr, int c) { *(word*,asi)addr = c } */ void* compilestaddr(int op3, int asi) { void *a; a = codep; parameter(1, 8); /* MOVW (4*1)(FP), R8 */ ret(); /* JMPL 8(R15), R0 */ /* in delay slot st R8, (R7+R0, asi) */ *codep++ = (3<<30)|(8<<25)|(op3<<19)|(7<<14)|(asi<<5); return a; } /* * ulong f(ulong addr) { *addr=0; addr+=offset; return addr} * offset can be anything */ void* compile1(ulong offset, int asi) { void *a; a = codep; /* ST R0, (R7+R0, asi) */ *codep++ = (3<<30)|(0<<25)|(STA<<19)|(7<<14)|(asi<<5); if(offset < (1<<12)){ ret(); /* JMPL 8(R15), R0 */ /* in delay slot ADD $offset, R7 */ *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(1<<13)|offset; }else{ constant(offset, 8); ret(); /* JMPL 8(R15), R0 */ /* in delay slot ADD R8, R7 */ *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(0<<13)|8; } return a; } /* * ulong f(ulong addr) { for(i=0;i<16;i++) {*addr=0; addr+=offset}; return addr} * offset must be less than 1<<12 */ void* compile16(ulong offset, int asi) { void *a; int i; a = codep; for(i=0; i<16; i++){ /* ST R0, (R7+R0, asi) */ *codep++ = (3<<30)|(0<<25)|(STA<<19)|(7<<14)|(asi<<5); /* ADD $offset, R7 */ *codep++ = (2<<30)|(7<<25)|(ADD<<19)|(7<<14)|(1<<13)|offset; } ret(); /* JMPL 8(R15), R0 */ nop(); return a; . 325,326d 316c putenab(getenab()|ENABCACHE); /**/ . 306,311c for(i=0; iticks)&(nc-1)); /* random guess */ nc++; for(j=1; t && j=0; j--){ k = kmappa(pa+j*BY2PG, flag); if(va && va != k->va+BY2PG) systemreset(); va = k->va; } return va; . 334,335c for(i=0; i<(IOEND-IOSEGM0)/BY2PG; i++,k++){ k->va = IOSEGM0+i*BY2PG; . 223a NKLUDGE = ((TOPPMEG-kmapalloc.lowpmeg)/conf.ncontext); if(NKLUDGE>11)NKLUDGE=11; . 216c for(j=0; jpa = 0; lock(&kmapalloc); k->next = kmapalloc.free; kmapalloc.free = k; putpme(k->va, INVALIDPTE, 1); unlock(&kmapalloc); } . 349c putpme(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag, 1); . 327,328c for(va = IOSEGM; va < IOSEGM + IOSEGSIZE; va += BY2PG, k++){ k->va = va; . 323c ulong va; . 318a struct { Lock; KMap *free; KMap arena[IOSEGSIZE/BY2PG]; }kmapalloc; . 303,316c putpme(USERADDR, INVALIDPTE, 1); . 301c invalidateu(void) . 295,296c c = u->p->ctxonmach[m->machno]; if(c == 0) panic("flushmmu"); while(p = c->pmeg){ c->pmeg = p->cnext; freepmeg(p, 1); mkfirst(&m->plist, p); } . 293a Ctx *c; Pmeg *p; . 286,288c Ctx *c; ulong tlbphys; Pmeg *pm, *f, **l; if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) panic("mapstack %s %d %lux 0x%lux 0x%lux", p->text, p->pid, p->upage, p->upage->pa, p->upage->va); /* free a pmeg if a process needs one */ if(m->needpmeg){ pm = (Pmeg*)m->plist; if(c = pm->ctx){ /* remove from context list */ l = &c->pmeg; for(f = *l; f; f = f->cnext){ if(f == pm){ *l = f->cnext; break; } l = &f->cnext; } /* flush cache & remove mappings */ putctx(c); freepmeg(pm, 1); } m->needpmeg = 0; } /* give up our context if it is unclean */ if(p->newtlb){ c = p->ctxonmach[m->machno]; if(c) freectx(c, 1); p->newtlb = 0; } /* set to this proc's context */ c = p->ctxonmach[m->machno]; if(c == 0) allocctx(p); else putctx(c); /* make sure there's a mapping for u-> */ tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; putpmegspace(USERADDR, tlbphys); u = (User*)USERADDR; . 284c mapstack(Proc *p) . 282a /* * set up context for a process */ . 270,280c c = p->ctxonmach[m->machno]; if(c == 0) return; freectx(c, 1); mkfirst(&m->clist, c); . 268c Ctx *c; . 266c mmurelease(Proc *p) . 264a /* * give up our mmu context */ . 259,262c m->cctx = ctx = xalloc(conf.ncontext * sizeof(Ctx)); for(i = 0; i < conf.ncontext; i++, ctx++){ ctx->index = i; add(&m->clist, ctx); } putctx(m->cctx); . 252,257c m->pmeg = p = xalloc((INVALIDPMEG - fp) * sizeof(Pmeg)); m->pfirst = fp; for(; fp < INVALIDPMEG; fp++, p++){ p->index = fp; add(&m->plist, p); . 250c * allocate MMU management data for this CPU . 248a . 238,247c for(c = 0; c < conf.ncontext; c++){ putcontext(c); for(va = UZERO; va < (KZERO & VAMASK); va += BY2SEGM) putsegspace(va, INVALIDPMEG); for(va = ktop; va < IOSEGM; va += BY2SEGM) putsegspace(va, INVALIDPMEG); . 236c * invalidate everything outside the kernel in every context . 234a . 219,233c /* * Invalidate all entries in all other pmegs */ for(j = fp; j < conf.npmeg; j++){ putsegspace(INVALIDSEGM, j); for(va = INVALIDSEGM; va < INVALIDSEGM+BY2SEGM; va += BY2PG) putpme(va, INVALIDPTE, 1); . 215,217c fp = i; . 186,213c i = fp; for(va = IOSEGM; va < IOSEGM+IOSEGSIZE; va += BY2SEGM) putsegspace(va, i++); . 180,184c for(c = 0; c < conf.ncontext; c++){ . 178c * allocate pmegs for kmap'ing . 172,175c va = ROUNDUP(ktop, BY2SEGM); for(; ktop < va; ktop += BY2PG) putpme(ktop, INVALIDPTE, 1); . 170c * invalidate rest of kernel's PMEG . 165,168d 160,163c pme = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; i = 0; for(va = KZERO; va < ktop; va += BY2PG, i++) putpme(va, pme+i, 1); . 158c * Make sure cache is turned on for kernel . 156c ktop = PGROUND(conf.npage0); i = 0; for(c = 0; c < conf.ncontext; c++){ i = 0; for(va = KZERO; va < ktop; va += BY2SEGM) putcxsegm(c, va, i++); } fp = i; . 154c * First map kernel text, data, bss, and xalloc regions. * xinit sets conf.npage0 to end of these. . 152a . 151a conf.ncontext = 1; /**/ . 150c int c, i, j; ulong va, ktop, pme; int fp; /* first free pmeg */ Pmeg *p; Ctx *ctx; . 147a cacheinit(void) { int i; for(i=0; ipmeg[x - m->pfirst]; if(virt < p->lo) p->lo = virt; if(virt > p->hi) p->hi = virt; putpme(virt, phys, 1); splx(s); . 141c putmmu(ulong virt, ulong phys, Page *pg) . 139a /* * stuff an entry into a pmeg */ static void putpme(ulong virt, ulong phys, int flush) { virt = virt & ~(BY2PG-1); if(flush) flushpage(virt); putpmegspace(virt, phys); } /* * put a mapping into current context */ . 136,137c a = flushpg(a); while(a < evirt); . 134c static void flushpage(ulong virt) { ulong a, evirt; a = virt; evirt = virt+BY2PG; . 132c putcontext(c->index); m->cctx = c; } . 129,130c static void putctx(Ctx *c) . 114,126c static void freectx(Ctx *c, int flush) { Pmeg *p; putctx(c); /* give back mappings */ while(p = c->pmeg){ c->pmeg = p->cnext; freepmeg(p, flush); mkfirst(&m->plist, p); } /* flush u-> */ flushpage(USERADDR); /* detach from process */ c->proc->ctxonmach[m->machno] = 0; c->proc = 0; . 96,112c c = (Ctx*)m->clist; putctx(c); if(c->proc) freectx(c, 1); c->proc = proc; c->proc->ctxonmach[m->machno] = c; mklast(&m->clist, c); return c; } . 92,94c Ctx *c; . 89,90c static Ctx* allocctx(Proc *proc) . 87c * get a context for a process. . 85a static void freepmeg(Pmeg *p, int flush) { ulong x; /* invalidate any used PTE's, flush cache */ for(x = p->lo; x <= p->hi; x += BY2PG) putpme(x, INVALIDPTE, flush); /* invalidate segment pointer */ putsegspace(p->virt, INVALIDPMEG); p->hi = 0; p->lo = 0; p->cnext = 0; p->ctx = 0; p->virt = 0; } . 79,83c virt = virt & ~(BY2SEGM-1); for(;;){ p = (Pmeg*)m->plist; c = p->ctx; if(c == 0) break; m->needpmeg = 1; sched(); splhi(); } /* add to current context */ p->ctx = m->cctx; p->cnext = m->cctx->pmeg; m->cctx->pmeg = p; p->virt = virt; p->lo = virt; p->hi = virt; putsegspace(p->virt, p->index); mklast(&m->plist, p); return p; . 77c Pmeg *p; Ctx *c; . 74,75c /* * add a pmeg to the current context for the given address */ static Pmeg* allocpmeg(ulong virt) . 62,71c *list = entry; . 57,60c /* remove from list */ entry->prev->next = entry->next; entry->next->prev = entry->prev; /* chain back in */ entry->prev = first->prev; entry->next = first; first->prev->next = entry; first->prev = entry; } /* * move to front of use list */ static void mkfirst(List **list, List *entry) { List *first; first = *list; if(entry == first) return; /* already at front */ /* unchain */ entry->prev->next = entry->next; entry->next->prev = entry->prev; /* chain back in */ entry->prev = first->prev; entry->next = first; first->prev->next = entry; first->prev = entry; *list = entry; } /* * remove from list */ static void remove(List **list, List *entry) { if(*list == entry) *list = entry->next; entry->prev->next = entry->next; entry->next->prev = entry->prev; } /* * add to list */ static void add(List **list, List *entry) { List *first; first = *list; if(first == 0){ entry->prev = entry; entry->next = entry; } else { entry->prev = first->prev; entry->next = first; first->prev->next = entry; first->prev = entry; . 52,54c ulong lo; /* low water mark of used entries */ ulong hi; /* high water mark of used entries */ ushort index; /* which Pmeg this is */ ulong virt; /* virtual address this Pmeg represents */ Ctx *ctx; /* context Pmeg belongs to */ Pmeg *cnext; /* next pmeg used in same context */ }; #define HOWMANY(x, y) (((x)+((y)-1))/(y)) #define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) static Pmeg* allocpmeg(ulong); static void freepmeg(Pmeg*, int); static Ctx* allocctx(Proc*); static void freectx(Ctx*, int); static void putpme(ulong, ulong, int); static void mklast(List**, List*); static void mkfirst(List**, List*); static void remove(List**, List*); static void add(List**, List*); static void flushpage(ulong); static void putctx(Ctx*); /* * move to end of use list */ static void mklast(List **list, List *entry) { List *first; first = *list; if(entry == first){ *list = first->next; return; . 49,50c List; /* MUST BE FIRST IN STRUCTURE!! */ . 46,47c struct Pmeg . 44c * a Sparc PMEG description . 41c Proc *proc; /* process that owns this context */ Pmeg *pmeg; /* list of pmeg's used by this context */ ushort index; /* which context this is */ }; . 36,39c /* * a Sparc context description */ struct Ctx { List; /* MUST BE FIRST IN STRUCTURE!! */ . 34a /* * doubly linked list for LRU algorithm */ struct List { List *prev; /* less recently used */ List *next; /* more recently used */ }; . 33c * WARNING: Even though all MMU data is in the mach structure or * pointed to by it, this code will not work on a multi-processor * without modification. . 31a doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); rawputs(buf); } static void rawpanic(char *fmt, ...) { char buf[PRINTSIZE]; int s; s = splhi(); doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)); rawputs("rawpanic: "); rawputs(buf); systemreset(); splx(s); } . 30c void rawprint(char *fmt, ...) { char buf[PRINTSIZE]; . 24,28c while(*s) rawputc(*s++); } . 22c void rawputs(char *s) . 13,20c static int rawputc(int c) { if(c == '\n') rawputc('\r'); while((getsysspaceb(SERIALPORT+4) & (1<<2)) == 0) delay(10); putsysspaceb(SERIALPORT+6, c); if(c == '\n') delay(20); return c; } . 8,11c #define SERIALPORT 0xF0000000 /* MMU bypass */ . 1,6c #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" . ## diffname ss/mmu.c 1992/0912 ## diff -e /n/bootesdump/1992/0911/sys/src/9/ss/mmu.c /n/bootesdump/1992/0912/sys/src/9/ss/mmu.c 635d 568a kmapalloc.inited = 1; . 554a int inited; . 539d 519a if(c->proc != p || p->ctxonmach[m->machno] != c) panic("mapstack c->proc != p\n"); . 516c c = allocctx(p); . 496a if(f != pm) panic("mapstack f != pm\n"); . 467d 417,425d 405a * Invalidate all entries in all other pmegs */ for(j = fp; j < conf.npmeg; j++){ putsegspace(INVALIDSEGM, j); for(va = 0; va < BY2SEGM; va += BY2PG) putpmegspace(INVALIDSEGM+va, INVALIDPTE); } if(conf.base1 < conf.npage1){ /* * map kernel region 1, this may overlap kernel region 0's * PMEG's. */ ktop1 = PGROUND(conf.npage1); kbot1 = conf.base1 & ~(BY2SEGM - 1); if(kbot1 < ktop) kbot1 = ktop; for(c = 0; c < conf.ncontext; c++){ i = fp; putcontext(c); for(va = kbot1; va < ktop1; va += BY2SEGM) putsegspace(va, i++); } fp = i; /* * Make sure cache is turned on for kernel region 1 */ kbot1 = conf.base1 & ~(BY2PG - 1); pme = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; i = PPN(kbot1 & ~KZERO); for(va = kbot1; va < ktop1; va += BY2PG, i++) putpme(va, pme+i, 1); } /* . 399c * invalidate rest of kernel's region 0's PMEG's . 391c * Make sure cache is turned on for kernel region 0 . 378,379c * map all of kernel region 0. . 374c /* * mmuinit is entered with PMEG's 0 & 1 providing mappng * for virtual addresses KZERO<->KZERO+2*BY2SEGM to physical * 0<->2*BY2SEGM */ . 369c ulong va, ktop, pme, kbot1, ktop1; . 359c putenab(getenab()|ENABCACHE); . 334a if(x != p->index) panic("putmmu %d/%d\n", x, p->index); } . 333c else { . 304a . 283a mkfirst(&m->clist, c); . 275d 272a if(p->ctx != c) panic("freectx: %lux/%lux\n", p->ctx, c); . 269a if(c->proc->ctxonmach[m->machno] != c) panic("freectx %lux %lux\n", c->proc->ctxonmach[m->machno], c); . 257a } if(c->pmeg) panic("allocctx c->pmeg %lux\n", c->pmeg); . 256c if(c->proc){ . 243a mkfirst(&m->plist, p); . 232c /* invalidate any used PTE's */ . 220c p->lo = virt + BY2PG; . 207,208c if(p->ctx == 0) . 202d 162,174d ## diffname ss/mmu.c 1992/0913 ## diff -e /n/bootesdump/1992/0912/sys/src/9/ss/mmu.c /n/bootesdump/1992/0913/sys/src/9/ss/mmu.c 660a ulong va; KMap *k; /* * avoid an alias: if part of kernel memory, just return map */ va = pg->pa|KZERO; if((KZERO<=va && va<(ulong)end) || (conf.base0<=va && vanext; unlock(&kmapalloc); k->va = va; k->pa = va; return k; } . 633c if(pa != k->pa) putpme(k->va, INVALIDPTE, 1); . 628a ulong pa; pa = k->pa; . 439a ktop = ktop1; . 414a if(conf.base0 < conf.npage0){ /* * map kernel region 0, this may overlap kernel text image */ ktop1 = PGROUND(conf.npage0); kbot1 = conf.base0 & ~(BY2SEGM - 1); if(kbot1 < ktop) kbot1 = ktop; for(c = 0; c < conf.ncontext; c++){ i = fp; putcontext(c); for(va = kbot1; va < ktop1; va += BY2SEGM) putsegspace(va, i++); } fp = i; /* * Make sure cache is turned on for kernel region 0 */ kbot1 = conf.base0 & ~(BY2PG - 1); pme = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; i = PPN(kbot1 & ~KZERO); for(va = kbot1; va < ktop1; va += BY2PG, i++) putpme(va, pme+i, 1); ktop = ktop1; } . 392c * Make sure cache is turned on for program and data . 382c ktop = PGROUND((ulong)end); . 380c * map all of text image . 244d 242c if(c->proc) . ## diffname ss/mmu.c 1992/0914 ## diff -e /n/bootesdump/1992/0913/sys/src/9/ss/mmu.c /n/bootesdump/1992/0914/sys/src/9/ss/mmu.c 8,52d ## diffname ss/mmu.c 1993/0123 ## diff -e /n/bootesdump/1992/0914/sys/src/9/ss/mmu.c /n/bootesdump/1993/0123/sys/src/9/ss/mmu.c 327,329c * mmuinit is entered with PMEG's 0-3 providing mapping * for virtual addresses KZERO<->KZERO+4*BY2SEGM to physical * 0<->4*BY2SEGM . ## diffname ss/mmu.c 1993/0501 # deleted ## diff -e /n/bootesdump/1993/0123/sys/src/9/ss/mmu.c /n/fornaxdump/1993/0501/sys/src/brazil/ss/mmu.c 1,676d