Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/ss/mmu.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## 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]; i<e; i++,k++){
		k->va = 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<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);
.
57c
mmuinit(void)
.
55a

.
52,53c
	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");
.
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; j<PG2SEGM; j++){
		putpmeg(UZERO+j*BY2PG, INVALIDPTE);
		putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE);
	}
	return i;
}
.
33,34c
	 * kludge: each context is allowed 2 pmegs, one for text and one for stack
.
31a
/*
 * 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);
.
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; d<NCONTEXT; d++){
		putcontext(d);
		for(i=0; i<0x100; i+=16)
			putwD16(k->va+(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; c<NCONTEXT; c++){	/* necessary? */
		putcontext(c);
		for(i=0; i<0x1000; i++)
			putw2(CACHETAGS+(i<<4), 0);
	}
	putcontext(0);

.
243c
	int c, i;
.
232a
	flushcontext();
	tp = u->p->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; k<NKLUDGE-1; k++)
.
76,78c
	for(j=0; j<NKLUDGE-1; j++)
		putsegm(UZERO+j*BY2SEGM, kmapalloc.lowpmeg+(NKLUDGE*(i-1))+j);
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(NKLUDGE*(i-1))+(NKLUDGE-1));
.
74c
	 * kludge: each context is allowed NKLUDGE pmegs, NKLUDGE-1 for text & data and 1 for stack
.
72d
68a
	pidtime[i] = m->ticks;
.
61,63c
	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];
		}
	
.
58a
	ulong t;
.
44,46c
	 * shouldn't need putpmeg because nothing has been mapped at
	 * USERADDR in this context except this page.  however, it crashes.
.
39,40c
		panic("mapstack %s %d %lux 0x%lux 0x%lux", p->text, 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; l<IOSEGM0; l+=BY2SEGM)
			putsegm(l, INVALIDPMEG);
#endif

		/*
.
159a
#ifdef doesntwork
.
156d
79a

.
17c
#define	NKLUDGE	12
.
## diffname ss/mmu.c 1991/0112
## diff -e /n/bootesdump/1991/0111/sys/src/9/sparc/mmu.c /n/bootesdump/1991/0112/sys/src/9/sparc/mmu.c
222a
	/*
	 * Prepare mmu up to this address
	 */
	tp--;	/* now tp==context */
	tp = tp*NKLUDGE;
	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:
.
219,220c
	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);
.
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; j<PG2SEGM; j++)
.
83a
	i--;	/* now i==context */
	p->nmmuseg = 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 && j<NTLBPID; j++)
.
67a
	int tp;

	tp = p->pidonmach[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<VACSIZE; i+=16*VACLINESZ)
		putwD16(virt+i, 0);
.
147c
	ktop = 8*1024*1024;
.
145c
	 * TEMP: just map the first 8M of bank 0 for the kernel - philw
.
## diffname ss/mmu.c 1992/0724
## diff -e /n/bootesdump/1992/0722/sys/src/9/slc/mmu.c /n/bootesdump/1992/0724/sys/src/9/slc/mmu.c
308,309c
		for(i=0; i<VACSIZE; i+=VACLINESZ)
			putw2(CACHETAGS+i, 0);
.
273c
	for(i=0; i<BY2PG; i+=16*VACLINESZ)
.
147c
	ktop = 4*1024*1024;
.
145c
	 * TEMP: just map the first 4M of bank 0 for the kernel - philw
.
128,129c
	for(i=0; i<VACSIZE; i+=16*VACLINESZ)
		putwE16(i, 0);
.
## diffname ss/mmu.c 1992/0806
## diff -e /n/bootesdump/1992/0724/sys/src/9/slc/mmu.c /n/bootesdump/1992/0806/sys/src/9/slc/mmu.c
390a
}

/*
 * Compile MMU code for this machine, since the MMU can only
 * be addressed from parameterless machine instructions.
 * What's wrong with MMUs you can talk to from C?
 */

/* op3 */
#define	LD	0
#define	ADD	0
#define	OR	2
#define	LDA	16
#define	LDUBA	17
#define	STA	20
#define	STBA	21
#define	JMPL	56
/* op2 */
#define	SETHI	4

void	*compileconst(int, ulong, int);	/* value to/from constant address */
void	*compileldaddr(int, int);	/* value from parameter address */
void	*compilestaddr(int, int);	/* value to parameter address */
void	*compile16(ulong, int);		/* 16 stores of zero */
void	*compile1(ulong, int);		/* 1 stores of zero */

#define	ret()	{*codep++ = (2<<30)|(0<<25)|(JMPL<<19)|(15<<14)|(1<<13)|8;}
#define	nop()	{*codep++ = (0<<30)|(0<<25)|(SETHI<<22)|(0>>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; i<VACSIZE; i+=VACLINESZ)
		putsysspace(CACHETAGS+i, 0);
.
301a
	putcontext(0);
.
300c
	int i;
.
290d
286d
283c
	putpmegspace(virt, phys);
.
273,275c
	a = virt;
	evirt = virt+BY2PG;
	do
		a = flushpg(a);
	while(a < evirt);
	putpmegspace(virt, phys);
.
269a
#ifdef asdf
	if(conf.ss2)
		putw6(virt, 0);
	else
		for(i=0; i<BY2PG; i+=16*VACLINESZ)
			putwD16(virt+i, 0);
#endif
.
266c
	ulong a, evirt;
.
147c
	ktop = PADDR(conf.npage0);
.
145c
	 * xinit sets conf.npage0 to maximum kernel address
.
143a
	compile();
.
125,129c
	a = 0;
	do
		a = flushcx(a);
	while(a < VACSIZE);
.
123c
	ulong a;
.
115,120d
17c
#define	NKLUDGE	11		/* <= ((TOPPMEG-kmap.lowpmeg)/NCONTEXT) */
.
11d
7a
void	compile(void);
#define	NCODE	1024
static	ulong	code[NCODE];
static	ulong	*codep = code;

void	(*putcontext)(ulong);
void	(*putenab)(ulong);
ulong	(*getenab)(void);
void	(*putpmegspace)(ulong, ulong);
void	(*putsysspace)(ulong, ulong);
ulong	(*getsysspace)(ulong);
ulong	(*flushcx)(ulong);
ulong	(*flushpg)(ulong);

.
## diffname ss/mmu.c 1992/0807
## diff -e /n/bootesdump/1992/0807/sys/src/9/slc/mmu.c /n/bootesdump/1992/0807/sys/src/9/ss/mmu.c
443,444c
		flushpg = compile16(conf.vaclinesize, 0xD);
		flushcx = compile16(conf.vaclinesize, 0xE);
.
441c
		flushcx = compile16(conf.vaclinesize, 7);
.
322c
	for(i=0; i<conf.vacsize; i+=conf.vaclinesize)
.
277,283d
180c
	for(c=0; c<conf.ncontext; c++){
.
159c
	for(c=0; c<conf.ncontext; c++)
.
135c
	while(a < conf.vacsize);
.
97,98c
	nc = conf.ncontext;
	i = 1+((m->ticks)&(nc-1));	/* random guess */
	nc++;
	for(j=1; t && j<nc; j++)
.
92c
	int i, j, nc;
.
## diffname ss/mmu.c 1992/0812
## diff -e /n/bootesdump/1992/0807/sys/src/9/ss/mmu.c /n/bootesdump/1992/0812/sys/src/9/ss/mmu.c
358a
}

ulong
kmapregion(ulong pa, ulong n, ulong flag)
{
	KMap *k;
	ulong va;
	int i, j;

	/*
	 * kmap's are initially in reverse order so rearrange them.
	 */
	i = (n+(BY2PG-1))/BY2PG;
	va = 0;
	for(j=i-1; 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; j<NIOSEGM; j++){
.
214c
		 * Segments for IO and kmap
.
196,205d
194c
		putsegm(ROMSEGM, ROMPMEG);
.
192c
		 * Map ROM
.
165a
	if(PADDR(ktop) & (BY2SEGM-1))
		kmapalloc.lowpmeg++;
.
30c
int	NKLUDGE;
.
27c
	KMap	arena[(IOEND-IOSEGM0)/BY2PG];
.
## diffname ss/mmu.c 1992/0813
## diff -e /n/bootesdump/1992/0812/sys/src/9/ss/mmu.c /n/bootesdump/1992/0813/sys/src/9/ss/mmu.c
217d
203c
				putpmeg(ROMSEGM+i*BY2PG, INVALIDPTE);
.
201c
				putpmeg(ROMSEGM+i*BY2PG, pte+i);
.
199c
				PTEIO|PPN(EPROM);
.
166c
	if(ktop & (BY2SEGM-1))
.
## diffname ss/mmu.c 1992/0911
## diff -e /n/bootesdump/1992/0813/sys/src/9/ss/mmu.c /n/bootesdump/1992/0911/sys/src/9/ss/mmu.c
386,567d
353a

void
kunmap(KMap *k)
{
	k->pa = 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; i<conf.vacsize; i+=conf.vaclinesize)
		putsysspace(CACHETAGS+i, 0);

	/*
	 * Turn cache on
	 */
	putenab(getenab()&~ENABCACHE);
}

/*
 *  set up initial mappings and a the LRU lists for contexts and pmegs
 */
void
.
146a
/*
 * Initialize cache by clearing the valid bit
 * (along with the others) in all cache entries
 */
.
143,144c
	ulong x, v;
	Pmeg *p;
	int s;

	USED(pg);
	s = splhi();
	v = virt & ~(BY2SEGM-1);
	x = getsegspace(v);
	if(x == INVALIDPMEG)
		p = allocpmeg(v);
	else
		p = &m->pmeg[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 && va<conf.npage0) ||
	   (conf.base1<=va && va<conf.npage1)){
		lock(&kmapalloc);
		k = kmapalloc.free;
		if(k == 0){
			dumpstack();
			panic("kmap");
		}
		kmapalloc.free = k->next;
		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

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.