#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#define TLBINVLAID KZERO
void
mmuinit(void)
{
int i;
print("mmuinit\n");
for(i=0; i<STLBSIZE; i++)
m->stb[i].virt = TLBINVLAID;
}
void
flushmmu(void)
{
int x;
if(0)print("flushmmu(%ld)\n", up->pid);
x = splhi();
up->newtlb = 1;
mmuswitch(up);
splx(x);
}
/*
* called with splhi
*/
void
mmuswitch(Proc *p)
{
int tp;
if(0)print("mmuswitch()\n");
if(p->newtlb) {
memset(p->pidonmach, 0, sizeof p->pidonmach);
p->newtlb = 0;
}
tp = p->pidonmach[m->machno];
putcasid(tp);
}
void
mmurelease(Proc* p)
{
if(0)print("mmurelease(%ld)\n", p->pid);
memset(p->pidonmach, 0, sizeof p->pidonmach);
}
void
purgetlb(int pid)
{
int i, mno;
Proc *sp, **pidproc;
Softtlb *entry, *etab;
if(0)print("purgetlb: pid = %d\n", pid);
m->tlbpurge++;
/*
* find all pid entries that are no longer used by processes
*/
mno = m->machno;
pidproc = m->pidproc;
for(i=1; i<NTLBPID; i++) {
sp = pidproc[i];
if(sp && sp->pidonmach[mno] != i)
pidproc[i] = 0;
}
/*
* shoot down the one we want
*/
sp = pidproc[pid];
if(sp != 0)
sp->pidonmach[mno] = 0;
pidproc[pid] = 0;
/*
* clean out all dead pids from the stlb;
*/
entry = m->stb;
for(etab = &entry[STLBSIZE]; entry < etab; entry++)
if(pidproc[TLBPID(entry->virt)] == 0)
entry->virt = TLBINVLAID;
/*
* clean up the hardware
*/
tlbflushall();
}
int
newtlbpid(Proc *p)
{
int i, s;
Proc **h;
i = m->lastpid;
h = m->pidproc;
for(s = 0; s < NTLBPID; s++) {
i++;
if(i >= NTLBPID)
i = 1;
if(h[i] == 0)
break;
}
if(h[i]) {
i = m->purgepid+1;
if(i >= NTLBPID)
i = 1;
m->purgepid = i;
purgetlb(i);
}
if(h[i] != 0)
panic("newtlb");
m->pidproc[i] = p;
p->pidonmach[m->machno] = i;
m->lastpid = i;
if(0)print("newtlbpid: pid=%ld = tlbpid = %d\n", p->pid, i);
return i;
}
void
putmmu(ulong va, ulong pa, Page *pg)
{
char *ctl;
int tp;
ulong h;
qlock(&m->stlblk);
tp = up->pidonmach[m->machno];
if(tp == 0) {
tp = newtlbpid(up);
putcasid(tp);
}
h = ((va>>12)^(va>>24)^(tp<<8)) & 0xfff;
m->stb[h].virt = va|tp;
m->stb[h].phys = pa;
tlbflush(va);
qunlock(&m->stlblk);
ctl = &pg->cachectl[m->machno];
if(0)print("putmmu tp=%d h=%ld va=%lux pa=%lux ctl=%x\n", tp, h,va, pa, *ctl);
switch(*ctl) {
default:
panic("putmmu: %d\n", *ctl);
break;
case PG_NOFLUSH:
break;
case PG_TXTFLUSH:
dcflush((void*)pg->va, BY2PG);
icflush((void*)pg->va, BY2PG);
*ctl = PG_NOFLUSH;
break;
case PG_NEWCOL:
print("PG_NEWCOL!!\n");
*ctl = PG_NOFLUSH;
break;
}
}