plan 9 kernel history: overview | file list | diff list

1991/01151/ss/mmu.c (diff list | history)

1990/1223/sys/src/9/ss/mmu.c:3,1021990/1226/sys/src/9/ss/mmu.c:3,230 (short | long)
1990/1223    
#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; 
	KMap	arena[4*1024*1024/BY2PG];	/* kernel mmu maps up to 4MB */ 
1990/1226    
	KMap	arena[(IOEND-IOSEGM)/BY2PG]; 
1990/1223    
}kmapalloc; 
 
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
 */ 
 
int	newpid(Proc*); 
void	purgepid(int); 
 
/* 
1990/1223    
 * Called splhi, not in Running state 
 */ 
void 
mapstack(Proc *p) 
{ 
	ulong tlbvirt, tlbphys; 
	ulong next; 
	MMU *mm, *mn, *me; 
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))) 
		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); 
1990/1226    
	/* 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); 
1990/1223    
	u = (User*)USERADDR; 
1990/1226    
} 
1990/1223    
 
1990/1226    
/* 
 * 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); 
1990/1223    
	/* 
	 *  if not a kernel process and this process was not the  
	 *  last process on this machine, flush & preload mmu 
1990/1226    
	 * kludge: each context is allowed 2 pmegs, one for text and one for stack 
1990/1223    
	 */ 
	if(!p->kp && p!=m->lproc){ 
		flushmmu(); 
1990/1226    
	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; 
} 
1990/1223    
 
		/* 
		 *  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; 
1990/1226    
void 
purgepid(int pid) 
{ 
	int i, rpid; 
1990/1223    
 
		m->lproc = p; 
	} 
1990/1226    
	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"); 
1990/1223    
} 
 
1990/1226    
 
1990/1223    
void 
putkmmu(ulong tlbvirt, ulong tlbphys) 
1990/1226    
mmuinit(void) 
1990/1223    
{ 
	if(!(tlbvirt&KZERO)) 
		panic("putkmmu"); 
	tlbvirt &= ~KZERO; 
	KMAP[(tlbvirt&0x003FE000L)>>2] = tlbphys; 
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 
		 */ 
/* 
		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); 
1990/1223    
} 
 
1990/1226    
 
 
 
1990/1223    
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; 
1990/1226    
	short tp; 
	Proc *p; 
1990/1223    
 
		s = splhi(); 
		mp = &(u->mc.mmu[u->mc.next&(NMMU-1)]); 
		mp->pa = tlbphys; 
		mp->va = tlbvirt; 
		u->mc.next++; 
		splx(s); 
1990/1226    
	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; 
1990/1223    
	} 
	UMAP[tlbvirt] = tlbphys; 
1990/1226    
	/* 
	 * 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(); 
1990/1223    
} 
 
void 
flushmmu(void) 
{ 
	flushcpucache(); 
	*PARAM &= ~TLBFLUSH_; 
	*PARAM |= TLBFLUSH_; 
1990/1226    
	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(); 
1990/1223    
} 
 
void 
clearmmucache(void) 
1990/1226    
cacheinit(void) 
1990/1223    
{ 
	if(u == 0) 
		panic("flushmmucache"); 
	u->mc.next = 0; 
1990/1226    
	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); /**/ 
1990/1223    
} 
 
void 
1990/1223/sys/src/9/ss/mmu.c:103,1301990/1226/sys/src/9/ss/mmu.c:231,249
1990/1223    
kmapinit(void) 
{ 
	KMap *k; 
	int i, e; 
1990/1226    
	int i; 
1990/1223    
 
	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); 
1990/1226    
print("low pmeg %d\n", kmapalloc.lowpmeg); 
1990/1223    
	kmapalloc.free = 0; 
	for(k=&kmapalloc.arena[i]; i<e; i++,k++){ 
		k->va = i*BY2PG|KZERO; 
1990/1226    
	k = kmapalloc.arena; 
	for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ 
		k->va = IOSEGM+i*BY2PG; 
1990/1223    
		kunmap(k); 
	} 
} 
 
KMap* 
kmap(Page *pg) 
1990/1226    
kmap1(Page *pg, ulong flag) 
1990/1223    
{ 
	KMap *k; 
 
1990/1223/sys/src/9/ss/mmu.c:137,1541990/1226/sys/src/9/ss/mmu.c:256,287
1990/1223    
	kmapalloc.free = k->next; 
	unlock(&kmapalloc); 
	k->pa = pg->pa; 
	putkmmu(k->va, PPN(k->pa) | PTEVALID | PTEKERNEL); 
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. 
	 */ 
	putpmeg(k->va, PPN(k->pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); 
1990/1223    
	return k; 
} 
 
1990/1226    
KMap* 
kmap(Page *pg) 
{ 
	return kmap1(pg, PTEMAINMEM); 
} 
 
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; 
	putkmmu(k->va, INVALIDPTE); 
1990/1226    
	putpmeg(k->va, INVALIDPTE); 
1990/1223    
	unlock(&kmapalloc); 
} 
 
1990/1223/sys/src/9/ss/mmu.c:155,1591990/1226/sys/src/9/ss/mmu.c:288,292
1990/1223    
void 
invalidateu(void) 
{ 
	putkmmu(USERADDR, INVALIDPTE); 
1990/1226    
	putpmeg(USERADDR, INVALIDPTE); 
1990/1223    
} 
1990/1226/sys/src/9/ss/mmu.c:40,451990/1227/sys/src/9/ss/mmu.c:40,50 (short | long)
1990/1226    
	/* 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); 
1990/1227    
	/* 
	 * 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 
	 */ 
1990/1226    
	putpmeg(USERADDR, tlbphys); 
1990/1223    
	u = (User*)USERADDR; 
1990/1226    
} 
1990/1226/sys/src/9/ss/mmu.c:64,691990/1227/sys/src/9/ss/mmu.c:69,75
1990/1226    
	m->pidproc[i] = p; 
	m->lastpid = i; 
print("new context %d\n", i); 
1990/1227    
	putcontext(i-1); 
1990/1223    
	/* 
1990/1226    
	 * kludge: each context is allowed 2 pmegs, one for text and one for stack 
1990/1223    
	 */ 
1990/1226/sys/src/9/ss/mmu.c:128,1381990/1227/sys/src/9/ss/mmu.c:134,143
1990/1226    
		/* 
		 * Invalidate user addresses 
		 */ 
/* 
		for(l=UZERO; l<KZERO; l+=BY2SEGM) 
1990/1227    
 
		for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM) 
1990/1226    
			putsegm(l, INVALIDPMEG); 
*/ 
putsegm(0x0000, INVALIDPMEG); 
1990/1227    
 
1990/1226    
		/* 
		 * One segment for screen 
		 */ 
1990/1226/sys/src/9/ss/mmu.c:168,1761990/1227/sys/src/9/ss/mmu.c:173,178
1990/1226    
	putcontext(0); 
1990/1223    
} 
 
1990/1226    
                 
                 
                 
1990/1223    
void 
putmmu(ulong tlbvirt, ulong tlbphys) 
{ 
1990/1226/sys/src/9/ss/mmu.c:200,2051990/1227/sys/src/9/ss/mmu.c:202,222
1990/1223    
} 
 
void 
1990/1227    
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 
1990/1223    
flushmmu(void) 
{ 
1990/1226    
	splhi(); 
1990/1226/sys/src/9/ss/mmu.c:233,2391990/1227/sys/src/9/ss/mmu.c:250,255
1990/1223    
	KMap *k; 
1990/1226    
	int i; 
1990/1223    
 
1990/1226    
print("low pmeg %d\n", kmapalloc.lowpmeg); 
1990/1223    
	kmapalloc.free = 0; 
1990/1226    
	k = kmapalloc.arena; 
	for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ 
1990/1226/sys/src/9/ss/mmu.c:243,2491990/1227/sys/src/9/ss/mmu.c:259,265
1990/1223    
} 
 
KMap* 
1990/1226    
kmap1(Page *pg, ulong flag) 
1990/1227    
kmappa(ulong pa, ulong flag) 
1990/1223    
{ 
	KMap *k; 
 
1990/1226/sys/src/9/ss/mmu.c:255,2671990/1227/sys/src/9/ss/mmu.c:271,283
1990/1223    
	} 
	kmapalloc.free = k->next; 
	unlock(&kmapalloc); 
	k->pa = pg->pa; 
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. 
	 */ 
	putpmeg(k->va, PPN(k->pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); 
1990/1227    
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); 
1990/1223    
	return k; 
} 
 
1990/1226/sys/src/9/ss/mmu.c:268,2741990/1227/sys/src/9/ss/mmu.c:284,290
1990/1226    
KMap* 
kmap(Page *pg) 
{ 
	return kmap1(pg, PTEMAINMEM); 
1990/1227    
	return kmappa(pg->pa, PTEMAINMEM); 
1990/1226    
} 
 
1990/1223    
void 
1990/1227/sys/src/9/ss/mmu.c:68,741990/1231/sys/src/9/ss/mmu.c:68,73 (short | long)
1990/1226    
	} 
	m->pidproc[i] = p; 
	m->lastpid = i; 
print("new context %d\n", i); 
1990/1227    
	putcontext(i-1); 
1990/1223    
	/* 
1990/1226    
	 * kludge: each context is allowed 2 pmegs, one for text and one for stack 
1990/1227/sys/src/9/ss/mmu.c:83,881990/1231/sys/src/9/ss/mmu.c:82,94
1990/1226    
} 
1990/1223    
 
1990/1226    
void 
1990/1231    
putcontext(int c) 
{ 
	m->pidhere[c] = 1; 
	putcxreg(c); 
} 
 
void 
1990/1226    
purgepid(int pid) 
{ 
	int i, rpid; 
1990/1227/sys/src/9/ss/mmu.c:181,1901990/1231/sys/src/9/ss/mmu.c:187,192
1990/1223    
 
1990/1226    
	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); 
1990/1227/sys/src/9/ss/mmu.c:196,2031990/1231/sys/src/9/ss/mmu.c:198,203
1990/1226    
	if(tlbvirt>=TSTKTOP || (UZERO+BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))) 
		panic("putmmu %lux", tlbvirt); 
	putpmeg(tlbvirt, tlbphys); 
	m->pidhere[tp] = 1; 
	p->state = Running; 
	spllo(); 
1990/1223    
} 
 
1990/1227/sys/src/9/ss/mmu.c:205,2101990/1231/sys/src/9/ss/mmu.c:205,211
1990/1227    
putpmeg(ulong virt, ulong phys) 
{ 
	int i; 
1990/1231    
	int tp; 
1990/1227    
 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
1990/1227/sys/src/9/ss/mmu.c:213,2181990/1231/sys/src/9/ss/mmu.c:214,221
1990/1227    
	 */ 
	for(i=0; i<0x100; i++) 
		putwD(virt+(i<<4), 0); 
1990/1231    
	if(u && u->p) 
		m->pidhere[u->p->pidonmach[m->machno]] = 1;	/* UGH! */ 
1990/1227    
	putw4(virt, phys); 
} 
 
1990/1231/sys/src/9/ss/mmu.c:175,1801991/0108/sys/src/9/ss/mmu.c:175,184 (short | long)
1990/1226    
				for(i=0; i<PG2SEGM; i++) 
					putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE); 
		} 
1991/0108    
		/* 
		 * Lance 
		 */ 
		putsegm(LANCESEGM, LANCEPMEG); 
1990/1226    
	} 
	putcontext(0); 
1990/1223    
} 
1991/0108/sys/src/9/ss/mmu.c:55,611991/0109/sys/src/9/ss/mmu.c:55,61 (short | long)
1990/1226    
int 
newpid(Proc *p) 
{ 
	int i, j; 
1991/0109    
	int i, j, k; 
1990/1226    
	Proc *sp; 
 
	i = m->lastpid+1; 
1991/0108/sys/src/9/ss/mmu.c:69,811991/0109/sys/src/9/ss/mmu.c:69,84
1990/1226    
	m->pidproc[i] = p; 
	m->lastpid = i; 
1990/1227    
	putcontext(i-1); 
1991/0109    
/* print("new pid %d\n", i); /**/ 
1990/1223    
	/* 
1990/1226    
	 * kludge: each context is allowed 2 pmegs, one for text and one for stack 
1991/0109    
	 * kludge: each context is allowed 5 pmegs, four for text & data and one for stack 
1990/1223    
	 */ 
1990/1226    
	putsegm(UZERO, kmapalloc.lowpmeg+(2*i)); 
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+1); 
1991/0109    
	for(j=0; j<4; j++) 
		putsegm(UZERO, kmapalloc.lowpmeg+(2*i)+j); 
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+4); 
1990/1226    
	for(j=0; j<PG2SEGM; j++){ 
		putpmeg(UZERO+j*BY2PG, INVALIDPTE); 
1991/0109    
		for(k=0; k<4; k++) 
			putpmeg(UZERO+k*BY2SEGM+j*BY2PG, INVALIDPTE); 
1990/1226    
		putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); 
	} 
	return i; 
1991/0108/sys/src/9/ss/mmu.c:95,1011991/0109/sys/src/9/ss/mmu.c:98,104
1990/1223    
 
1990/1226    
	if(m->pidhere[pid] == 0) 
		return; 
print("purge pid %d\n", pid); 
1991/0109    
/* print("purge pid %d\n", pid);/**/ 
1990/1226    
	memset(m->pidhere, 0, sizeof m->pidhere); 
	putcontext(pid-1); 
	/* 
1991/0108/sys/src/9/ss/mmu.c:103,1091991/0109/sys/src/9/ss/mmu.c:106,112
1990/1226    
	 */ 
	for(i=0; i<0x1000; i++) 
		putwE((i<<4), 0); 
print("purge done\n"); 
1991/0109    
/* print("purge done\n");/**/ 
1990/1223    
} 
 
1990/1226    
 
1991/0108/sys/src/9/ss/mmu.c:199,2051991/0109/sys/src/9/ss/mmu.c:202,208
1990/1226    
	/* 
	 * kludge part 2: make sure we've got a valid segment 
	 */ 
	if(tlbvirt>=TSTKTOP || (UZERO+BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))) 
1991/0109    
	if(tlbvirt>=TSTKTOP || (UZERO+4*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))) 
1990/1226    
		panic("putmmu %lux", tlbvirt); 
	putpmeg(tlbvirt, tlbphys); 
	spllo(); 
1991/0109/sys/src/9/ss/mmu.c:14,191991/0110/sys/src/9/ss/mmu.c:14,21 (short | long)
1990/1226    
	KMap	arena[(IOEND-IOSEGM)/BY2PG]; 
1990/1223    
}kmapalloc; 
 
1991/0110    
#define	NKLUDGE	8 
 
1990/1223    
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
 */ 
1991/0109/sys/src/9/ss/mmu.c:20,251991/0110/sys/src/9/ss/mmu.c:22,28
1990/1226    
 
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 
1991/0109/sys/src/9/ss/mmu.c:36,491991/0110/sys/src/9/ss/mmu.c:39,50
1990/1226    
		p->pidonmach[m->machno] = tp; 
	} 
1990/1223    
	if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) 
		panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va); 
1990/1226    
	/* don't set m->pidhere[*tp] because we're only writing U entry */ 
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    
	/* 
	 * 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 
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; 
1991/0109/sys/src/9/ss/mmu.c:56,831991/0110/sys/src/9/ss/mmu.c:57,90
1990/1226    
newpid(Proc *p) 
{ 
1991/0109    
	int i, j, k; 
1991/0110    
	ulong t; 
1990/1226    
	Proc *sp; 
 
	i = m->lastpid+1; 
	if(i >= NCONTEXT+1) 
		i = 1; 
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]; 
	if(sp){ 
		sp->pidonmach[m->machno] = 0; 
		purgepid(i); 
	} 
1991/0110    
	pidtime[i] = m->ticks; 
1990/1226    
	m->pidproc[i] = p; 
	m->lastpid = i; 
1990/1227    
	putcontext(i-1); 
1991/0109    
/* print("new pid %d\n", i); /**/ 
1990/1223    
	/* 
1991/0109    
	 * kludge: each context is allowed 5 pmegs, four for text & data and one for stack 
1991/0110    
	 * kludge: each context is allowed NKLUDGE pmegs, NKLUDGE-1 for text & data and 1 for stack 
1990/1223    
	 */ 
1991/0109    
	for(j=0; j<4; j++) 
		putsegm(UZERO, kmapalloc.lowpmeg+(2*i)+j); 
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+4); 
1991/0110    
	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)); 
1990/1226    
	for(j=0; j<PG2SEGM; j++){ 
1991/0109    
		for(k=0; k<4; k++) 
1991/0110    
		for(k=0; k<NKLUDGE-1; k++) 
1991/0109    
			putpmeg(UZERO+k*BY2SEGM+j*BY2PG, INVALIDPTE); 
1990/1226    
		putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); 
	} 
1991/0109/sys/src/9/ss/mmu.c:87,1121991/0110/sys/src/9/ss/mmu.c:94,123
1990/1226    
void 
1990/1231    
putcontext(int c) 
{ 
	m->pidhere[c] = 1; 
1991/0110    
	m->pidhere[c+1] = 1; 
1990/1231    
	putcxreg(c); 
} 
 
void 
1990/1226    
purgepid(int pid) 
1991/0110    
flushcontext(void) 
1990/1226    
{ 
	int i, rpid; 
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    
	if(m->pidhere[pid] == 0) 
		return; 
1991/0109    
/* print("purge pid %d\n", pid);/**/ 
1990/1226    
	memset(m->pidhere, 0, sizeof m->pidhere); 
	putcontext(pid-1); 
	/* 
	 * Clear context from cache 
	 */ 
	for(i=0; i<0x1000; i++) 
		putwE((i<<4), 0); 
1991/0109    
/* print("purge done\n");/**/ 
1991/0110    
	flushcontext(); 
1990/1223    
} 
 
1990/1226    
 
1991/0109/sys/src/9/ss/mmu.c:129,1351991/0110/sys/src/9/ss/mmu.c:140,145
1990/1226    
	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 
1991/0109/sys/src/9/ss/mmu.c:178,1871991/0110/sys/src/9/ss/mmu.c:188,193
1990/1226    
				for(i=0; i<PG2SEGM; i++) 
					putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE); 
		} 
1991/0108    
		/* 
		 * Lance 
		 */ 
		putsegm(LANCESEGM, LANCEPMEG); 
1990/1226    
	} 
	putcontext(0); 
1990/1223    
} 
1991/0109/sys/src/9/ss/mmu.c:202,2091991/0110/sys/src/9/ss/mmu.c:208,217
1990/1226    
	/* 
	 * kludge part 2: make sure we've got a valid segment 
	 */ 
1991/0109    
	if(tlbvirt>=TSTKTOP || (UZERO+4*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))) 
1990/1226    
		panic("putmmu %lux", tlbvirt); 
1991/0110    
	if(tlbvirt>=TSTKTOP || (UZERO+(NKLUDGE-1)*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))){ 
		pprint("putmmu %lux", tlbvirt); 
		pexit("Suicide", 0); 
	} 
1990/1226    
	putpmeg(tlbvirt, tlbphys); 
	spllo(); 
1990/1223    
} 
1991/0109/sys/src/9/ss/mmu.c:219,2261991/0110/sys/src/9/ss/mmu.c:227,234
1990/1227    
	/* 
	 * Flush old entries from cache 
	 */ 
	for(i=0; i<0x100; i++) 
		putwD(virt+(i<<4), 0); 
1991/0110    
	for(i=0; i<0x100; i+=16) 
		putwD16(virt+(i<<4), 0); 
1990/1231    
	if(u && u->p) 
		m->pidhere[u->p->pidonmach[m->machno]] = 1;	/* UGH! */ 
1990/1227    
	putw4(virt, phys); 
1991/0109/sys/src/9/ss/mmu.c:229,2351991/0110/sys/src/9/ss/mmu.c:237,249
1990/1227    
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 */ 
1991/0109/sys/src/9/ss/mmu.c:240,2531991/0110/sys/src/9/ss/mmu.c:254,272
1990/1223    
void 
1990/1226    
cacheinit(void) 
1990/1223    
{ 
1990/1226    
	int i; 
1991/0110    
	int c, i; 
1990/1226    
 
	/* 
	 * 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); 
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 
	 */ 
1991/0109/sys/src/9/ss/mmu.c:260,2651991/0110/sys/src/9/ss/mmu.c:279,285
1990/1223    
	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++){ 
1991/0109/sys/src/9/ss/mmu.c:272,2771991/0110/sys/src/9/ss/mmu.c:292,298
1990/1227    
kmappa(ulong pa, ulong flag) 
1990/1223    
{ 
	KMap *k; 
1991/0110    
	ulong s; 
1990/1223    
 
	lock(&kmapalloc); 
	k = kmapalloc.free; 
1991/0109/sys/src/9/ss/mmu.c:287,2931991/0110/sys/src/9/ss/mmu.c:308,336
1990/1226    
	 * Must avoid having the same entry in the cache twice, so 
	 * must use NOCACHE or else extreme cleverness elsewhere. 
	 */ 
1991/0110    
	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 
1990/1227    
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); 
1991/0110    
#endif 
	splx(s); 
1990/1223    
	return k; 
} 
 
1991/0110/sys/src/9/ss/mmu.c:14,201991/0111/sys/src/9/ss/mmu.c:14,20 (short | long)
1990/1226    
	KMap	arena[(IOEND-IOSEGM)/BY2PG]; 
1990/1223    
}kmapalloc; 
 
1991/0110    
#define	NKLUDGE	8 
1991/0111    
#define	NKLUDGE	12 
1991/0110    
 
1990/1223    
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
1991/0110/sys/src/9/ss/mmu.c:77,821991/0111/sys/src/9/ss/mmu.c:77,83
1990/1226    
	m->pidproc[i] = p; 
	m->lastpid = i; 
1990/1227    
	putcontext(i-1); 
1991/0111    
 
1990/1223    
	/* 
1991/0110    
	 * kludge: each context is allowed NKLUDGE pmegs, NKLUDGE-1 for text & data and 1 for stack 
1990/1223    
	 */ 
1991/0110/sys/src/9/ss/mmu.c:153,1631991/0111/sys/src/9/ss/mmu.c:154,171
1990/1226    
		/* 
		 * Invalidate user addresses 
		 */ 
1990/1227    
                 
		for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM) 
1990/1226    
			putsegm(l, INVALIDPMEG); 
1990/1227    
 
1991/0111    
#ifdef doesntwork 
1990/1226    
		/* 
1991/0111    
		 * Invalidate high kernel addresses 
		 */ 
		for(l=conf.maxialloc; l<IOSEGM0; l+=BY2SEGM) 
			putsegm(l, INVALIDPMEG); 
#endif 
 
		/* 
1990/1226    
		 * One segment for screen 
		 */ 
		putsegm(SCREENSEGM, SCREENPMEG); 
1991/0110/sys/src/9/ss/mmu.c:210,2161991/0111/sys/src/9/ss/mmu.c:218,224
1990/1226    
	 */ 
1991/0110    
	if(tlbvirt>=TSTKTOP || (UZERO+(NKLUDGE-1)*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))){ 
		pprint("putmmu %lux", tlbvirt); 
		pexit("Suicide", 0); 
1991/0111    
		pexit("Suicide", 1); 
1991/0110    
	} 
1990/1226    
	putpmeg(tlbvirt, tlbphys); 
	spllo(); 
1991/0110/sys/src/9/ss/mmu.c:309,3351991/0111/sys/src/9/ss/mmu.c:317,323
1990/1226    
	 * must use NOCACHE or else extreme cleverness elsewhere. 
	 */ 
1991/0110    
	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 
1990/1227    
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); 
1991/0110    
#endif 
	splx(s); 
1990/1223    
	return k; 
} 
1991/0111/sys/src/9/ss/mmu.c:79,951991/0112/sys/src/9/ss/mmu.c:79,96 (short | long)
1990/1227    
	putcontext(i-1); 
1991/0111    
 
1990/1223    
	/* 
1991/0110    
	 * kludge: each context is allowed NKLUDGE pmegs, NKLUDGE-1 for text & data and 1 for stack 
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++) 
		putsegm(UZERO+j*BY2SEGM, kmapalloc.lowpmeg+(NKLUDGE*(i-1))+j); 
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(NKLUDGE*(i-1))+(NKLUDGE-1)); 
1990/1226    
	for(j=0; j<PG2SEGM; j++){ 
1991/0110    
		for(k=0; k<NKLUDGE-1; k++) 
1991/0109    
			putpmeg(UZERO+k*BY2SEGM+j*BY2PG, INVALIDPTE); 
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); 
	} 
	return i; 
1991/0112    
	return i+1; 
1990/1226    
} 
1990/1223    
 
1990/1226    
void 
1991/0111/sys/src/9/ss/mmu.c:205,2101991/0112/sys/src/9/ss/mmu.c:206,213
1990/1223    
{ 
1990/1226    
	short tp; 
	Proc *p; 
1991/0112    
	ulong seg, l; 
	int j, k; 
1990/1223    
 
1990/1226    
	splhi(); 
	p = u->p; 
1991/0111/sys/src/9/ss/mmu.c:216,2251991/0112/sys/src/9/ss/mmu.c:219,248
1990/1226    
	/* 
	 * kludge part 2: make sure we've got a valid segment 
	 */ 
1991/0110    
	if(tlbvirt>=TSTKTOP || (UZERO+(NKLUDGE-1)*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))){ 
		pprint("putmmu %lux", tlbvirt); 
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 
	 */ 
	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: 
1990/1226    
	putpmeg(tlbvirt, tlbphys); 
	spllo(); 
1990/1223    
} 
1991/0112/sys/src/9/ss/mmu.c:69,821991/0115/sys/src/9/ss/mmu.c:69,80 (short | long)
1991/0110    
		} 
	 
1990/1226    
	sp = m->pidproc[i]; 
	if(sp){ 
1991/0115    
	if(sp) 
1990/1226    
		sp->pidonmach[m->machno] = 0; 
		purgepid(i); 
	} 
1991/0115    
	purgepid(i);	/* also does putcontext */ 
1991/0110    
	pidtime[i] = m->ticks; 
1990/1226    
	m->pidproc[i] = p; 
	m->lastpid = i; 
1990/1227    
	putcontext(i-1); 
1991/0111    
 
1990/1223    
	/* 
1991/0112    
	 * kludge: each context is allowed NKLUDGE pmegs. 
1991/0112/sys/src/9/ss/mmu.c:96,1021991/0115/sys/src/9/ss/mmu.c:94,99
1990/1226    
void 
1990/1231    
putcontext(int c) 
{ 
1991/0110    
	m->pidhere[c+1] = 1; 
1990/1231    
	putcxreg(c); 
} 
 
1991/0112/sys/src/9/ss/mmu.c:115,1231991/0115/sys/src/9/ss/mmu.c:112,117
1991/0110    
void 
purgepid(int pid) 
{ 
1990/1226    
	if(m->pidhere[pid] == 0) 
		return; 
	memset(m->pidhere, 0, sizeof m->pidhere); 
	putcontext(pid-1); 
1991/0110    
	flushcontext(); 
1990/1223    
} 
1991/0112/sys/src/9/ss/mmu.c:233,2401991/0115/sys/src/9/ss/mmu.c:227,233
1991/0112    
	/* 
	 * Prepare mmu up to this address 
	 */ 
	tp--;	/* now tp==context */ 
	tp = tp*NKLUDGE; 
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); 
1991/0112/sys/src/9/ss/mmu.c:260,2671991/0115/sys/src/9/ss/mmu.c:253,258
1990/1227    
	 */ 
1991/0110    
	for(i=0; i<0x100; i+=16) 
		putwD16(virt+(i<<4), 0); 
1990/1231    
	if(u && u->p) 
		m->pidhere[u->p->pidonmach[m->machno]] = 1;	/* UGH! */ 
1990/1227    
	putw4(virt, phys); 
} 
 
1991/0115/sys/src/9/ss/mmu.c:152,1651991/01151/sys/src/9/ss/mmu.c:152,157 (short | long)
1990/1227    
		for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM) 
1990/1226    
			putsegm(l, INVALIDPMEG); 
1990/1227    
 
1991/0111    
#ifdef doesntwork 
1990/1226    
		/* 
1991/0111    
		 * Invalidate high kernel addresses 
		 */ 
		for(l=conf.maxialloc; l<IOSEGM0; l+=BY2SEGM) 
			putsegm(l, INVALIDPMEG); 
#endif 
                 
		/* 
1990/1226    
		 * One segment for screen 
		 */ 
1991/01151/sys/src/9/ss/mmu.c:50,551991/0507/sys/src/9/ss/mmu.c:50,61 (short | long)
1990/1223    
	u = (User*)USERADDR; 
1990/1226    
} 
1990/1223    
 
1991/0507    
void 
mmurelease(Proc *p) 
{ 
	memset(p->pidonmach, 0, sizeof p->pidonmach); 
} 
 
1990/1226    
/* 
 * Process must be non-interruptible 
 */ 
1991/0507/sys/src/9/ss/mmu.c:22,271991/0706/sys/src/9/ss/mmu.c:22,29 (short | long)
1990/1226    
 
int	newpid(Proc*); 
void	purgepid(int); 
1991/0706    
void	flushcontext(void); 
 
1991/0110    
int	pidtime[NTLBPID];	/* should be per m */ 
1990/1226    
 
/* 
1991/0507/sys/src/9/ss/mmu.c:33,381991/0706/sys/src/9/ss/mmu.c:35,50
1990/1226    
	short tp; 
	ulong tlbphys; 
1990/1223    
 
1991/0706    
	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; 
	} 
 
1990/1226    
	tp = p->pidonmach[m->machno]; 
	if(tp == 0){ 
		tp = newpid(p); 
1991/0507/sys/src/9/ss/mmu.c:194,2001991/0706/sys/src/9/ss/mmu.c:206,212
1990/1223    
} 
 
void 
putmmu(ulong tlbvirt, ulong tlbphys) 
1991/0706    
putmmu(ulong tlbvirt, ulong tlbphys, Page *pg) 
1990/1223    
{ 
1990/1226    
	short tp; 
	Proc *p; 
1991/0706/sys/src/9/ss/mmu.c:50,561991/0928/sys/src/9/ss/mmu.c:50,56 (short | long)
1990/1226    
		tp = newpid(p); 
		p->pidonmach[m->machno] = tp; 
	} 
1990/1223    
	if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) 
1991/0928    
	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) 
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); 
1991/0928/sys/src/9/ss/mmu.c:23,281991/1007/sys/src/9/ss/mmu.c:23,29 (short | long)
1990/1226    
int	newpid(Proc*); 
void	purgepid(int); 
1991/0706    
void	flushcontext(void); 
1991/1007    
void	putpmegnf(ulong, ulong); 
1991/0706    
 
1991/0110    
int	pidtime[NTLBPID];	/* should be per m */ 
1990/1226    
 
1991/0928/sys/src/9/ss/mmu.c:36,471991/1007/sys/src/9/ss/mmu.c:37,43
1990/1226    
	ulong tlbphys; 
1990/1223    
 
1991/0706    
	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); 
1991/1007    
		mmurelease(p); 
1991/0706    
		p->newtlb = 0; 
	} 
 
1991/0928/sys/src/9/ss/mmu.c:55,641991/1007/sys/src/9/ss/mmu.c:51,60
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. 
1991/1007    
	 * Don't need to flush cache because no other page has been 
	 * mapped at USERADDR in this context; can call putpmegnf. 
1990/1227    
	 */ 
1990/1226    
	putpmeg(USERADDR, tlbphys); 
1991/1007    
	putpmegnf(USERADDR, tlbphys); 
1990/1223    
	u = (User*)USERADDR; 
1990/1226    
} 
1990/1223    
 
1991/0928/sys/src/9/ss/mmu.c:65,701991/1007/sys/src/9/ss/mmu.c:61,72
1991/0507    
void 
mmurelease(Proc *p) 
{ 
1991/1007    
	int tp; 
 
	tp = p->pidonmach[m->machno]; 
	if(tp) 
		pidtime[tp] = 0; 
	/* easiest is to forget what pid we had.... */ 
1991/0507    
	memset(p->pidonmach, 0, sizeof p->pidonmach); 
} 
 
1991/0928/sys/src/9/ss/mmu.c:80,861991/1007/sys/src/9/ss/mmu.c:82,88
1990/1226    
 
1991/0110    
	t = ~0; 
	i = 1+((m->ticks)&(NCONTEXT-1));	/* random guess */ 
	for(j=1; j<NTLBPID; j++) 
1991/1007    
	for(j=1; t && j<NTLBPID; j++) 
1991/0110    
		if(pidtime[j] < t){ 
			i = j; 
			t = pidtime[j]; 
1991/0928/sys/src/9/ss/mmu.c:105,1111991/1007/sys/src/9/ss/mmu.c:107,113
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/1007    
		putpmegnf((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); 
1991/0112    
	return i+1; 
1990/1226    
} 
1990/1223    
 
1991/0928/sys/src/9/ss/mmu.c:242,2481991/1007/sys/src/9/ss/mmu.c:244,250
1991/0112    
	for(j=p->nmmuseg; j<=seg; j++){ 
		putsegm(l, kmapalloc.lowpmeg+tp+j); 
		for(k=0; k<PG2SEGM; k++,l+=BY2PG) 
			putpmeg(l, INVALIDPTE); 
1991/1007    
			putpmegnf(l, INVALIDPTE); 
1991/0112    
	} 
	p->nmmuseg = seg+1; 
    put: 
1991/0928/sys/src/9/ss/mmu.c:267,2841991/1007/sys/src/9/ss/mmu.c:269,290
1990/1227    
} 
 
void 
1991/1007    
putpmegnf(ulong virt, ulong phys)	/* no need to flush */ 
{ 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
	putw4(virt, phys); 
} 
 
int nflushmmu; 
void 
1990/1223    
flushmmu(void) 
{ 
1991/0110    
	int tp; 
 
1991/1007    
nflushmmu++; 
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 */ 
1991/1007    
	u->p->newtlb = 1; 
1990/1226    
	mapstack(u->p); 
	spllo(); 
1990/1223    
} 
1991/1007/sys/src/9/ss/mmu.c:341,3601992/0101/sys/src/9/ss/mmu.c:341,369 (short | long)
1990/1223    
	kmapalloc.free = k->next; 
	unlock(&kmapalloc); 
1990/1227    
	k->pa = pa; 
1992/0101    
	s = splhi(); 
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag); 
	splx(s); 
	return k; 
} 
 
KMap* 
kmap(Page *pg) 
{ 
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; 
1992/0101    
	return kmappa(pg->pa, PTEMAINMEM|PTENOCACHE); 
1990/1223    
} 
 
1990/1226    
KMap* 
kmap(Page *pg) 
1992/0101    
kmapperm(Page *pg) 
1990/1226    
{ 
1992/0101    
	/* 
	 * Here we know it's a permanent entry and can be cached. 
	 */ 
1990/1227    
	return kmappa(pg->pa, PTEMAINMEM); 
1990/1226    
} 
 
1992/0101/sys/src/9/ss/mmu.c:1,51992/0321/sys/src/9/ss/mmu.c:1,5 (short | long)
1990/1223    
#include	"u.h" 
#include	"lib.h" 
1992/0321    
#include	"../port/lib.h" 
1990/1223    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0321/sys/src/9/ss/mmu.c:136,1601992/0619/sys/src/9/ss/mmu.c:136,166 (short | long)
1991/0110    
	flushcontext(); 
1990/1223    
} 
 
1990/1226    
                 
1990/1223    
void 
1990/1226    
mmuinit(void) 
1990/1223    
{ 
1990/1226    
	ulong l, i, j, c, pte; 
1992/0619    
	ulong ktop, l, i, j, c, pte; 
1990/1226    
 
	/* 
1992/0619    
	 * TEMP: just map the first 4M of bank 0 for the kernel - philw 
	 */ 
	ktop = 4*1024*1024; 
	/* 
1990/1226    
	 * 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++) 
1992/0619    
		for(i=0; i < ktop/BY2SEGM; i++) 
1990/1226    
			putcxsegm(c, KZERO+i*BY2SEGM, i); 
1992/0619    
 
1990/1226    
	kmapalloc.lowpmeg = i; 
1992/0619    
 
1990/1226    
	/* 
	 * Make sure cache is turned on for kernel 
	 */ 
	pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; 
	for(i=0; i<conf.maxialloc/BY2PG; i++) 
1992/0619    
	ktop /= BY2PG; 
	for(i=0; i < ktop; i++) 
1990/1226    
		putpmeg(KZERO+i*BY2PG, pte+i); 
 
	/* 
1992/0321/sys/src/9/ss/mmu.c:163,1681992/0619/sys/src/9/ss/mmu.c:169,175
1990/1226    
	putsegm(INVALIDSEGM, INVALIDPMEG); 
	for(i=0; i<PG2SEGM; i++) 
		putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE); 
1992/0619    
 
1990/1226    
	for(c=0; c<NCONTEXT; c++){ 
		putcontext(c); 
		putsegm(INVALIDSEGM, INVALIDPMEG); 
1992/0321/sys/src/9/ss/mmu.c:317,3231992/0619/sys/src/9/ss/mmu.c:324,331
1990/1223    
	KMap *k; 
1990/1226    
	int i; 
1990/1223    
 
1991/0110    
print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG); 
1992/0619    
	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++){ 
1992/0619/sys/src/9/ss/mmu.c:76,821992/0711/sys/src/9/ss/mmu.c:76,82 (short | long)
1990/1226    
int 
newpid(Proc *p) 
{ 
1991/0109    
	int i, j, k; 
1992/0711    
	int i, j; 
1991/0110    
	ulong t; 
1990/1226    
	Proc *sp; 
 
1992/0619/sys/src/9/ss/mmu.c:222,2271992/0711/sys/src/9/ss/mmu.c:222,228
1991/0112    
	ulong seg, l; 
	int j, k; 
1990/1223    
 
1992/0711    
	USED(pg); 
1990/1226    
	splhi(); 
	p = u->p; 
	tp = p->pidonmach[m->machno]; 
1992/0619/sys/src/9/ss/mmu.c:263,2691992/0711/sys/src/9/ss/mmu.c:264,269
1990/1227    
putpmeg(ulong virt, ulong phys) 
{ 
	int i; 
1990/1231    
	int tp; 
1990/1227    
 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
1992/0619/sys/src/9/ss/mmu.c:287,2941992/0711/sys/src/9/ss/mmu.c:287,292
1991/1007    
void 
1990/1223    
flushmmu(void) 
{ 
1991/0110    
	int tp; 
                 
1991/1007    
nflushmmu++; 
1990/1226    
	splhi(); 
1991/1007    
	u->p->newtlb = 1; 
1992/0619/sys/src/9/ss/mmu.c:378,3861992/0711/sys/src/9/ss/mmu.c:376,381
1990/1223    
void 
kunmap(KMap *k) 
{ 
1990/1226    
	ulong pte; 
	int i; 
                 
1990/1223    
	k->pa = 0; 
	lock(&kmapalloc); 
	k->next = kmapalloc.free; 
1992/0711/sys/src/9/ss/mmu.c:142,1501992/0722/sys/src/9/ss/mmu.c:142,150 (short | long)
1992/0619    
	ulong ktop, l, i, j, c, pte; 
1990/1226    
 
	/* 
1992/0619    
	 * TEMP: just map the first 4M of bank 0 for the kernel - philw 
1992/0722    
	 * TEMP: just map the first 8M of bank 0 for the kernel - philw 
1992/0619    
	 */ 
	ktop = 4*1024*1024; 
1992/0722    
	ktop = 8*1024*1024; 
1992/0619    
	/* 
1990/1226    
	 * First map lots of memory as kernel addressable in all contexts 
	 */ 
1992/0711/sys/src/9/ss/mmu.c:270,2771992/0722/sys/src/9/ss/mmu.c:270,277
1990/1227    
	/* 
	 * Flush old entries from cache 
	 */ 
1991/0110    
	for(i=0; i<0x100; i+=16) 
		putwD16(virt+(i<<4), 0); 
1992/0722    
	for(i=0; i<VACSIZE; i+=16*VACLINESZ) 
		putwD16(virt+i, 0); 
1990/1227    
	putw4(virt, phys); 
} 
 
1992/0722/sys/src/9/ss/mmu.c:125,1321992/0724/sys/src/9/ss/mmu.c:125,132 (short | long)
1991/0110    
	/* 
	 * Clear context from cache 
	 */ 
	for(i=0; i<0x1000; i+=16) 
		putwE16((i<<4), 0); 
1992/0724    
	for(i=0; i<VACSIZE; i+=16*VACLINESZ) 
		putwE16(i, 0); 
1991/0110    
} 
 
void 
1992/0722/sys/src/9/ss/mmu.c:142,1501992/0724/sys/src/9/ss/mmu.c:142,150
1992/0619    
	ulong ktop, l, i, j, c, pte; 
1990/1226    
 
	/* 
1992/0722    
	 * TEMP: just map the first 8M of bank 0 for the kernel - philw 
1992/0724    
	 * TEMP: just map the first 4M of bank 0 for the kernel - philw 
1992/0619    
	 */ 
1992/0722    
	ktop = 8*1024*1024; 
1992/0724    
	ktop = 4*1024*1024; 
1992/0619    
	/* 
1990/1226    
	 * First map lots of memory as kernel addressable in all contexts 
	 */ 
1992/0722/sys/src/9/ss/mmu.c:270,2761992/0724/sys/src/9/ss/mmu.c:270,276
1990/1227    
	/* 
	 * Flush old entries from cache 
	 */ 
1992/0722    
	for(i=0; i<VACSIZE; i+=16*VACLINESZ) 
1992/0724    
	for(i=0; i<BY2PG; i+=16*VACLINESZ) 
1992/0722    
		putwD16(virt+i, 0); 
1990/1227    
	putw4(virt, phys); 
} 
1992/0722/sys/src/9/ss/mmu.c:305,3121992/0724/sys/src/9/ss/mmu.c:305,312
1990/1226    
	 */ 
1991/0110    
	for(c=0; c<NCONTEXT; c++){	/* necessary? */ 
		putcontext(c); 
		for(i=0; i<0x1000; i++) 
			putw2(CACHETAGS+(i<<4), 0); 
1992/0724    
		for(i=0; i<VACSIZE; i+=VACLINESZ) 
			putw2(CACHETAGS+i, 0); 
1991/0110    
	} 
	putcontext(0); 
 
1992/0724/sys/src/9/ss/mmu.c:5,201992/0806/sys/src/9/ss/mmu.c:5,33 (short | long)
1990/1223    
#include	"fns.h" 
1990/1226    
#include	"io.h" 
1990/1223    
 
1992/0806    
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); 
 
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 
1992/0806    
#define	NKLUDGE	11		/* <= ((TOPPMEG-kmap.lowpmeg)/NCONTEXT) */ 
1991/0110    
 
1990/1223    
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
1992/0724/sys/src/9/ss/mmu.c:112,1321992/0806/sys/src/9/ss/mmu.c:125,138
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; 
1992/0806    
	ulong a; 
1990/1223    
 
1991/0110    
	/* 
	 * Clear context from cache 
	 */ 
1992/0724    
	for(i=0; i<VACSIZE; i+=16*VACLINESZ) 
		putwE16(i, 0); 
1992/0806    
	a = 0; 
	do 
		a = flushcx(a); 
	while(a < VACSIZE); 
1991/0110    
} 
 
void 
1992/0724/sys/src/9/ss/mmu.c:141,1501992/0806/sys/src/9/ss/mmu.c:147,157
1990/1223    
{ 
1992/0619    
	ulong ktop, l, i, j, c, pte; 
1990/1226    
 
1992/0806    
	compile(); 
1990/1226    
	/* 
1992/0724    
	 * TEMP: just map the first 4M of bank 0 for the kernel - philw 
1992/0806    
	 * xinit sets conf.npage0 to maximum kernel address 
1992/0619    
	 */ 
1992/0724    
	ktop = 4*1024*1024; 
1992/0806    
	ktop = PADDR(conf.npage0); 
1992/0619    
	/* 
1990/1226    
	 * First map lots of memory as kernel addressable in all contexts 
	 */ 
1992/0724/sys/src/9/ss/mmu.c:263,2781992/0806/sys/src/9/ss/mmu.c:270,295
1990/1223    
void 
1990/1227    
putpmeg(ulong virt, ulong phys) 
{ 
	int i; 
1992/0806    
	ulong a, evirt; 
1990/1227    
 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
1992/0806    
#ifdef asdf 
	if(conf.ss2) 
		putw6(virt, 0); 
	else 
		for(i=0; i<BY2PG; i+=16*VACLINESZ) 
			putwD16(virt+i, 0); 
#endif 
1990/1227    
	/* 
	 * Flush old entries from cache 
	 */ 
1992/0724    
	for(i=0; i<BY2PG; i+=16*VACLINESZ) 
1992/0722    
		putwD16(virt+i, 0); 
1990/1227    
	putw4(virt, phys); 
1992/0806    
	a = virt; 
	evirt = virt+BY2PG; 
	do 
		a = flushpg(a); 
	while(a < evirt); 
	putpmegspace(virt, phys); 
1990/1227    
} 
 
void 
1992/0724/sys/src/9/ss/mmu.c:280,2931992/0806/sys/src/9/ss/mmu.c:297,308
1991/1007    
{ 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
	putw4(virt, phys); 
1992/0806    
	putpmegspace(virt, phys); 
1991/1007    
} 
 
int nflushmmu; 
void 
1990/1223    
flushmmu(void) 
{ 
1991/1007    
nflushmmu++; 
1990/1226    
	splhi(); 
1991/1007    
	u->p->newtlb = 1; 
1990/1226    
	mapstack(u->p); 
1992/0724/sys/src/9/ss/mmu.c:297,3191992/0806/sys/src/9/ss/mmu.c:312,331
1990/1223    
void 
1990/1226    
cacheinit(void) 
1990/1223    
{ 
1991/0110    
	int c, i; 
1992/0806    
	int i; 
1990/1226    
 
1992/0806    
	putcontext(0); 
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); 
1992/0724    
		for(i=0; i<VACSIZE; i+=VACLINESZ) 
			putw2(CACHETAGS+i, 0); 
1991/0110    
	} 
	putcontext(0); 
1992/0806    
	for(i=0; i<VACSIZE; i+=VACLINESZ) 
		putsysspace(CACHETAGS+i, 0); 
1991/0110    
 
1990/1226    
	/* 
	 * Turn cache on 
	 */ 
	putb2(ENAB, getb2(ENAB)|ENABCACHE); /**/ 
1992/0806    
	putenab(getenab()|ENABCACHE); /**/ 
1990/1223    
} 
 
void 
1992/0724/sys/src/9/ss/mmu.c:322,3291992/0806/sys/src/9/ss/mmu.c:334,339
1990/1223    
	KMap *k; 
1990/1226    
	int i; 
1990/1223    
 
1992/0619    
	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++){ 
1992/0724/sys/src/9/ss/mmu.c:388,3911992/0806/sys/src/9/ss/mmu.c:398,558
1990/1223    
invalidateu(void) 
{ 
1990/1226    
	putpmeg(USERADDR, INVALIDPTE); 
1992/0806    
} 
 
/* 
 * 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; 
1990/1223    
} 
1992/0806/sys/src/9/ss/mmu.c:89,1011992/0807/sys/src/9/ss/mmu.c:89,103 (short | long)
Created.
rsc Fri Mar 4 12:44:25 2005
1990/1226    
int 
newpid(Proc *p) 
{ 
1992/0711    
	int i, j; 
1992/0807    
	int i, j, nc; 
1991/0110    
	ulong t; 
1990/1226    
	Proc *sp; 
 
1991/0110    
	t = ~0; 
	i = 1+((m->ticks)&(NCONTEXT-1));	/* random guess */ 
1991/1007    
	for(j=1; t && j<NTLBPID; j++) 
1992/0807    
	nc = conf.ncontext; 
	i = 1+((m->ticks)&(nc-1));	/* random guess */ 
	nc++; 
	for(j=1; t && j<nc; j++) 
1991/0110    
		if(pidtime[j] < t){ 
			i = j; 
			t = pidtime[j]; 
1992/0806/sys/src/9/ss/mmu.c:132,1381992/0807/sys/src/9/ss/mmu.c:134,140
1992/0806    
	a = 0; 
	do 
		a = flushcx(a); 
	while(a < VACSIZE); 
1992/0807    
	while(a < conf.vacsize); 
1991/0110    
} 
 
void 
1992/0806/sys/src/9/ss/mmu.c:156,1621992/0807/sys/src/9/ss/mmu.c:158,164
1990/1226    
	 * First map lots of memory as kernel addressable in all contexts 
	 */ 
	i = 0;		/* used */ 
	for(c=0; c<NCONTEXT; c++) 
1992/0807    
	for(c=0; c<conf.ncontext; c++) 
1992/0619    
		for(i=0; i < ktop/BY2SEGM; i++) 
1990/1226    
			putcxsegm(c, KZERO+i*BY2SEGM, i); 
1992/0619    
 
1992/0806/sys/src/9/ss/mmu.c:177,1831992/0807/sys/src/9/ss/mmu.c:179,185
1990/1226    
	for(i=0; i<PG2SEGM; i++) 
		putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE); 
1992/0619    
 
1990/1226    
	for(c=0; c<NCONTEXT; c++){ 
1992/0807    
	for(c=0; c<conf.ncontext; c++){ 
1990/1226    
		putcontext(c); 
		putsegm(INVALIDSEGM, INVALIDPMEG); 
		/* 
1992/0806/sys/src/9/ss/mmu.c:274,2861992/0807/sys/src/9/ss/mmu.c:276,281
1990/1227    
 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
1992/0806    
#ifdef asdf 
	if(conf.ss2) 
		putw6(virt, 0); 
	else 
		for(i=0; i<BY2PG; i+=16*VACLINESZ) 
			putwD16(virt+i, 0); 
#endif 
1990/1227    
	/* 
	 * Flush old entries from cache 
	 */ 
1992/0806/sys/src/9/ss/mmu.c:319,3251992/0807/sys/src/9/ss/mmu.c:314,320
1990/1226    
	 * Initialize cache by clearing the valid bit 
	 * (along with the others) in all cache entries 
	 */ 
1992/0806    
	for(i=0; i<VACSIZE; i+=VACLINESZ) 
1992/0807    
	for(i=0; i<conf.vacsize; i+=conf.vaclinesize) 
1992/0806    
		putsysspace(CACHETAGS+i, 0); 
1991/0110    
 
1990/1226    
	/* 
1992/0806/sys/src/9/ss/mmu.c:438,4471992/0807/sys/src/9/ss/mmu.c:433,442
1992/0806    
	getsysspace = compileldaddr(LDA, 2); 
	if(conf.ss2){ 
		flushpg = compile1(BY2PG, 6); 
		flushcx = compile16(VACLINESZ, 7); 
1992/0807    
		flushcx = compile16(conf.vaclinesize, 7); 
1992/0806    
	}else{ 
		flushpg = compile16(VACLINESZ, 0xD); 
		flushcx = compile16(VACLINESZ, 0xE); 
1992/0807    
		flushpg = compile16(conf.vaclinesize, 0xD); 
		flushcx = compile16(conf.vaclinesize, 0xE); 
1992/0806    
	} 
} 
 
1992/0807/sys/src/9/ss/mmu.c:24,331992/0812/sys/src/9/ss/mmu.c:24,33 (short | long)
1990/1223    
	Lock; 
1990/1226    
	int	lowpmeg; 
1990/1223    
	KMap	*free; 
1990/1226    
	KMap	arena[(IOEND-IOSEGM)/BY2PG]; 
1992/0812    
	KMap	arena[(IOEND-IOSEGM0)/BY2PG]; 
1990/1223    
}kmapalloc; 
 
1992/0806    
#define	NKLUDGE	11		/* <= ((TOPPMEG-kmap.lowpmeg)/NCONTEXT) */ 
1992/0812    
int	NKLUDGE; 
1991/0110    
 
1990/1223    
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
1992/0807/sys/src/9/ss/mmu.c:163,1681992/0812/sys/src/9/ss/mmu.c:163,170
1990/1226    
			putcxsegm(c, KZERO+i*BY2SEGM, i); 
1992/0619    
 
1990/1226    
	kmapalloc.lowpmeg = i; 
1992/0812    
	if(PADDR(ktop) & (BY2SEGM-1)) 
		kmapalloc.lowpmeg++; 
1992/0619    
 
1990/1226    
	/* 
	 * Make sure cache is turned on for kernel 
1992/0807/sys/src/9/ss/mmu.c:189,2081992/0812/sys/src/9/ss/mmu.c:191,200
1990/1226    
			putsegm(l, INVALIDPMEG); 
1990/1227    
 
1991/0111    
		/* 
1990/1226    
		 * One segment for screen 
1992/0812    
		 * Map ROM 
1990/1226    
		 */ 
		putsegm(SCREENSEGM, SCREENPMEG); 
1992/0812    
		putsegm(ROMSEGM, ROMPMEG); 
1990/1226    
		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++) 
1992/0807/sys/src/9/ss/mmu.c:211,2191992/0812/sys/src/9/ss/mmu.c:203,211
1990/1226    
				putpmeg(IOSEGM0+i*BY2PG, INVALIDPTE); 
		} 
		/* 
		 * Remaining segments for IO and kmap 
1992/0812    
		 * Segments for IO and kmap 
1990/1226    
		 */ 
		for(j=1; j<NIOSEGM; j++){ 
1992/0812    
		for(j=0; j<NIOSEGM; j++){ 
1990/1226    
			putsegm(IOSEGM0+j*BY2SEGM, IOPMEG0+j); 
			if(c == 0) 
				for(i=0; i<PG2SEGM; i++) 
1992/0807/sys/src/9/ss/mmu.c:221,2261992/0812/sys/src/9/ss/mmu.c:213,220
1990/1226    
		} 
	} 
	putcontext(0); 
1992/0812    
	NKLUDGE = ((TOPPMEG-kmapalloc.lowpmeg)/conf.ncontext); 
if(NKLUDGE>11)NKLUDGE=11; 
1990/1223    
} 
 
void 
1992/0807/sys/src/9/ss/mmu.c:331,3381992/0812/sys/src/9/ss/mmu.c:325,332
1990/1223    
 
	kmapalloc.free = 0; 
1990/1226    
	k = kmapalloc.arena; 
	for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ 
		k->va = IOSEGM+i*BY2PG; 
1992/0812    
	for(i=0; i<(IOEND-IOSEGM0)/BY2PG; i++,k++){ 
		k->va = IOSEGM0+i*BY2PG; 
1990/1223    
		kunmap(k); 
	} 
} 
1992/0807/sys/src/9/ss/mmu.c:356,3611992/0812/sys/src/9/ss/mmu.c:350,376
1992/0101    
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag); 
	splx(s); 
	return k; 
1992/0812    
} 
 
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; 
1992/0101    
} 
 
KMap* 
1992/0812/sys/src/9/ss/mmu.c:163,1691992/0813/sys/src/9/ss/mmu.c:163,169 (short | long)
1990/1226    
			putcxsegm(c, KZERO+i*BY2SEGM, i); 
1992/0619    
 
1990/1226    
	kmapalloc.lowpmeg = i; 
1992/0812    
	if(PADDR(ktop) & (BY2SEGM-1)) 
1992/0813    
	if(ktop & (BY2SEGM-1)) 
1992/0812    
		kmapalloc.lowpmeg++; 
1992/0619    
 
1990/1226    
	/* 
1992/0812/sys/src/9/ss/mmu.c:196,2061992/0813/sys/src/9/ss/mmu.c:196,206
1992/0812    
		putsegm(ROMSEGM, ROMPMEG); 
1990/1226    
		if(c == 0){ 
			pte = PTEVALID|PTEKERNEL|PTENOCACHE| 
				PTEIO|((EPROM>>PGSHIFT)&0xFFFF); 
1992/0813    
				PTEIO|PPN(EPROM); 
1990/1226    
			for(i=0; i<PG2ROM; i++) 
				putpmeg(IOSEGM0+i*BY2PG, pte+i); 
1992/0813    
				putpmeg(ROMSEGM+i*BY2PG, pte+i); 
1990/1226    
			for(; i<PG2SEGM; i++) 
				putpmeg(IOSEGM0+i*BY2PG, INVALIDPTE); 
1992/0813    
				putpmeg(ROMSEGM+i*BY2PG, INVALIDPTE); 
1990/1226    
		} 
		/* 
1992/0812    
		 * Segments for IO and kmap 
1992/0812/sys/src/9/ss/mmu.c:214,2201992/0813/sys/src/9/ss/mmu.c:214,219
1990/1226    
	} 
	putcontext(0); 
1992/0812    
	NKLUDGE = ((TOPPMEG-kmapalloc.lowpmeg)/conf.ncontext); 
if(NKLUDGE>11)NKLUDGE=11; 
1990/1223    
} 
 
void 
1992/0813/sys/src/9/ss/mmu.c:1,3311992/0911/sys/src/9/ss/mmu.c:1,569 (short | long)
1990/1223    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/1223    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1990/1226    
#include	"io.h" 
1992/0911    
#include "u.h" 
#include "../port/lib.h" 
#include "mem.h" 
#include "dat.h" 
#include "fns.h" 
#include "io.h" 
1990/1223    
 
1992/0806    
void	compile(void); 
#define	NCODE	1024 
static	ulong	code[NCODE]; 
static	ulong	*codep = code; 
1992/0911    
#define SERIALPORT	0xF0000000	/* MMU bypass */ 
1992/0806    
 
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); 
1992/0911    
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; 
} 
1992/0806    
 
1990/1223    
struct 
1992/0911    
void 
rawputs(char *s) 
1990/1223    
{ 
	Lock; 
1990/1226    
	int	lowpmeg; 
1990/1223    
	KMap	*free; 
1992/0812    
	KMap	arena[(IOEND-IOSEGM0)/BY2PG]; 
1990/1223    
}kmapalloc; 
1992/0911    
	while(*s) 
		rawputc(*s++); 
} 
1990/1223    
 
1992/0812    
int	NKLUDGE; 
1992/0911    
void 
rawprint(char *fmt, ...) 
{ 
	char buf[PRINTSIZE]; 
1991/0110    
 
1992/0911    
	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); 
} 
 
1990/1223    
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
1992/0911    
 *  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. 
1990/1226    
 */ 
1992/0911    
	 
/* 
 *  doubly linked list for LRU algorithm 
 */ 
struct List 
{ 
	List *prev;		/* less recently used */ 
	List *next;		/* more recently used */ 
}; 
1990/1226    
 
int	newpid(Proc*); 
void	purgepid(int); 
1991/0706    
void	flushcontext(void); 
1991/1007    
void	putpmegnf(ulong, ulong); 
1992/0911    
/* 
 *  a Sparc context description 
 */ 
struct Ctx 
{ 
	List;	/* MUST BE FIRST IN STRUCTURE!! */ 
1991/0706    
 
1991/0110    
int	pidtime[NTLBPID];	/* should be per m */ 
1992/0911    
	Proc	*proc;	/* process that owns this context */ 
	Pmeg	*pmeg;	/* list of pmeg's used by this context */ 
	ushort	index;	/* which context this is */ 
}; 
1990/1226    
 
/* 
1990/1223    
 * Called splhi, not in Running state 
1992/0911    
 *  a Sparc PMEG description 
1990/1223    
 */ 
void 
mapstack(Proc *p) 
1992/0911    
struct Pmeg 
1990/1223    
{ 
1990/1226    
	short tp; 
	ulong tlbphys; 
1992/0911    
	List;	/* MUST BE FIRST IN STRUCTURE!! */ 
1990/1223    
 
1991/0706    
	if(p->newtlb) { 
1991/1007    
		mmurelease(p); 
1991/0706    
		p->newtlb = 0; 
1992/0911    
	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;	 
1991/0706    
	} 
 
1990/1226    
	tp = p->pidonmach[m->machno]; 
	if(tp == 0){ 
		tp = newpid(p); 
		p->pidonmach[m->machno] = tp; 
1992/0911    
	/* 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; 
1990/1226    
	} 
1991/0928    
	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)) && p->pid != 0) 
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/1007    
	 * Don't need to flush cache because no other page has been 
	 * mapped at USERADDR in this context; can call putpmegnf. 
1990/1227    
	 */ 
1991/1007    
	putpmegnf(USERADDR, tlbphys); 
1990/1223    
	u = (User*)USERADDR; 
1992/0911    
	*list = entry; 
1990/1226    
} 
1990/1223    
 
1991/0507    
void 
mmurelease(Proc *p) 
1992/0911    
/* 
 *  add a pmeg to the current context for the given address 
 */ 
static Pmeg* 
allocpmeg(ulong virt) 
1991/0507    
{ 
1991/1007    
	int tp; 
1992/0911    
	Pmeg *p; 
	Ctx *c; 
1991/1007    
 
	tp = p->pidonmach[m->machno]; 
	if(tp) 
		pidtime[tp] = 0; 
	/* easiest is to forget what pid we had.... */ 
1991/0507    
	memset(p->pidonmach, 0, sizeof p->pidonmach); 
1992/0911    
	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; 
1991/0507    
} 
 
1992/0911    
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; 
} 
 
1990/1226    
/* 
 * Process must be non-interruptible 
1992/0911    
 *  get a context for a process. 
1990/1226    
 */ 
int 
newpid(Proc *p) 
1992/0911    
static Ctx* 
allocctx(Proc *proc) 
1990/1226    
{ 
1992/0807    
	int i, j, nc; 
1991/0110    
	ulong t; 
1990/1226    
	Proc *sp; 
1992/0911    
	Ctx *c; 
1990/1226    
 
1991/0110    
	t = ~0; 
1992/0807    
	nc = conf.ncontext; 
	i = 1+((m->ticks)&(nc-1));	/* random guess */ 
	nc++; 
	for(j=1; t && j<nc; j++) 
1991/0110    
		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; 
1992/0911    
	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; 
} 
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++) 
1991/1007    
		putpmegnf((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); 
1991/0112    
	return i+1; 
1992/0911    
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; 
1990/1226    
} 
1990/1223    
 
1990/1226    
void 
1991/0110    
flushcontext(void) 
1992/0911    
static void 
putctx(Ctx *c) 
1990/1226    
{ 
1992/0806    
	ulong a; 
1992/0911    
	putcontext(c->index); 
	m->cctx = c; 
} 
1990/1223    
 
1992/0806    
	a = 0; 
1992/0911    
static void 
flushpage(ulong virt) 
{ 
	ulong a, evirt; 
 
	a = virt; 
	evirt = virt+BY2PG; 
1992/0806    
	do 
		a = flushcx(a); 
1992/0807    
	while(a < conf.vacsize); 
1992/0911    
		a = flushpg(a); 
	while(a < evirt); 
1991/0110    
} 
 
1992/0911    
/* 
 *  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 
 */ 
1991/0110    
void 
purgepid(int pid) 
1992/0911    
putmmu(ulong virt, ulong phys, Page *pg) 
1991/0110    
{ 
1990/1226    
	putcontext(pid-1); 
1991/0110    
	flushcontext(); 
1992/0911    
	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); 
1990/1223    
} 
 
1992/0911    
/* 
 * Initialize cache by clearing the valid bit 
 * (along with the others) in all cache entries 
 */ 
1990/1223    
void 
1992/0911    
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 
1990/1226    
mmuinit(void) 
1990/1223    
{ 
1992/0619    
	ulong ktop, l, i, j, c, pte; 
1992/0911    
	int c, i, j; 
	ulong va, ktop, pme; 
	int fp;		/* first free pmeg */ 
	Pmeg *p; 
	Ctx *ctx; 
1990/1226    
 
1992/0911    
conf.ncontext = 1; /**/ 
1992/0806    
	compile(); 
1992/0911    
 
1990/1226    
	/* 
1992/0806    
	 * xinit sets conf.npage0 to maximum kernel address 
1992/0911    
	 *  First map kernel text, data, bss, and xalloc regions. 
	 *  xinit sets conf.npage0 to end of these. 
1992/0619    
	 */ 
1992/0806    
	ktop = PADDR(conf.npage0); 
1992/0911    
	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; 
 
1992/0619    
	/* 
1990/1226    
	 * First map lots of memory as kernel addressable in all contexts 
1992/0911    
	 *  Make sure cache is turned on for kernel 
1990/1226    
	 */ 
	i = 0;		/* used */ 
1992/0807    
	for(c=0; c<conf.ncontext; c++) 
1992/0619    
		for(i=0; i < ktop/BY2SEGM; i++) 
1990/1226    
			putcxsegm(c, KZERO+i*BY2SEGM, i); 
1992/0911    
	pme = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; 
	i = 0; 
	for(va = KZERO; va < ktop; va += BY2PG, i++) 
		putpme(va, pme+i, 1); 
1992/0619    
 
1990/1226    
	kmapalloc.lowpmeg = i; 
1992/0813    
	if(ktop & (BY2SEGM-1)) 
1992/0812    
		kmapalloc.lowpmeg++; 
1992/0619    
                 
1990/1226    
	/* 
	 * Make sure cache is turned on for kernel 
1992/0911    
	 *  invalidate rest of kernel's PMEG 
1990/1226    
	 */ 
	pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; 
1992/0619    
	ktop /= BY2PG; 
	for(i=0; i < ktop; i++) 
1990/1226    
		putpmeg(KZERO+i*BY2PG, pte+i); 
1992/0911    
	va = ROUNDUP(ktop, BY2SEGM); 
	for(; ktop < va; ktop += BY2PG) 
		putpme(ktop, INVALIDPTE, 1); 
1990/1226    
 
	/* 
	 * Create invalid pmeg; use highest segment 
1992/0911    
	 *  allocate pmegs for kmap'ing 
1990/1226    
	 */ 
	putsegm(INVALIDSEGM, INVALIDPMEG); 
	for(i=0; i<PG2SEGM; i++) 
		putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE); 
1992/0619    
                 
1992/0807    
	for(c=0; c<conf.ncontext; c++){ 
1992/0911    
	for(c = 0; c < conf.ncontext; c++){ 
1990/1226    
		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    
		/* 
1992/0812    
		 * Map ROM 
1990/1226    
		 */ 
1992/0812    
		putsegm(ROMSEGM, ROMPMEG); 
1990/1226    
		if(c == 0){ 
			pte = PTEVALID|PTEKERNEL|PTENOCACHE| 
1992/0813    
				PTEIO|PPN(EPROM); 
1990/1226    
			for(i=0; i<PG2ROM; i++) 
1992/0813    
				putpmeg(ROMSEGM+i*BY2PG, pte+i); 
1990/1226    
			for(; i<PG2SEGM; i++) 
1992/0813    
				putpmeg(ROMSEGM+i*BY2PG, INVALIDPTE); 
1990/1226    
		} 
		/* 
1992/0812    
		 * Segments for IO and kmap 
1990/1226    
		 */ 
1992/0812    
		for(j=0; j<NIOSEGM; j++){ 
1990/1226    
			putsegm(IOSEGM0+j*BY2SEGM, IOPMEG0+j); 
			if(c == 0) 
				for(i=0; i<PG2SEGM; i++) 
					putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE); 
		} 
1992/0911    
		i = fp; 
		for(va = IOSEGM; va < IOSEGM+IOSEGSIZE; va += BY2SEGM) 
			putsegspace(va, i++); 
1990/1226    
	} 
	putcontext(0); 
1992/0812    
	NKLUDGE = ((TOPPMEG-kmapalloc.lowpmeg)/conf.ncontext); 
1990/1223    
} 
1992/0911    
	fp = i; 
1990/1223    
 
void 
1991/0706    
putmmu(ulong tlbvirt, ulong tlbphys, Page *pg) 
1990/1223    
{ 
1990/1226    
	short tp; 
	Proc *p; 
1991/0112    
	ulong seg, l; 
	int j, k; 
1990/1223    
                 
1992/0711    
	USED(pg); 
1990/1226    
	splhi(); 
	p = u->p; 
	tp = p->pidonmach[m->machno]; 
	if(tp == 0){ 
		tp = newpid(p); 
		p->pidonmach[m->machno] = tp; 
1992/0911    
	/* 
	 *  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); 
1990/1223    
	} 
1992/0911    
 
1990/1226    
	/* 
	 * kludge part 2: make sure we've got a valid segment 
1992/0911    
	 *  invalidate everything outside the kernel in every context 
1990/1226    
	 */ 
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); 
1992/0911    
	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); 
1991/0110    
	} 
1992/0911    
 
1991/0112    
	/* 
	 * Prepare mmu up to this address 
1992/0911    
	 *  allocate MMU management data for this CPU 
1991/0112    
	 */ 
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) 
1991/1007    
			putpmegnf(l, INVALIDPTE); 
1992/0911    
	m->pmeg = p = xalloc((INVALIDPMEG - fp) * sizeof(Pmeg)); 
	m->pfirst = fp; 
	for(; fp < INVALIDPMEG; fp++, p++){ 
		p->index = fp; 
		add(&m->plist, p); 
1991/0112    
	} 
	p->nmmuseg = seg+1; 
    put: 
1990/1226    
	putpmeg(tlbvirt, tlbphys); 
	spllo(); 
1992/0911    
	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); 
1990/1223    
} 
 
1992/0911    
/* 
 *  give up our mmu context 
 */ 
1990/1223    
void 
1990/1227    
putpmeg(ulong virt, ulong phys) 
1992/0911    
mmurelease(Proc *p) 
1990/1227    
{ 
1992/0806    
	ulong a, evirt; 
1992/0911    
	Ctx *c; 
1990/1227    
 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
	/* 
	 * Flush old entries from cache 
	 */ 
1992/0806    
	a = virt; 
	evirt = virt+BY2PG; 
	do 
		a = flushpg(a); 
	while(a < evirt); 
	putpmegspace(virt, phys); 
1992/0911    
	c = p->ctxonmach[m->machno]; 
	if(c == 0) 
		return; 
 
	freectx(c, 1); 
	mkfirst(&m->clist, c); 
1990/1227    
} 
 
1992/0911    
/* 
 *  set up context for a process 
 */ 
1990/1227    
void 
1991/1007    
putpmegnf(ulong virt, ulong phys)	/* no need to flush */ 
1992/0911    
mapstack(Proc *p) 
1991/1007    
{ 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
1992/0806    
	putpmegspace(virt, phys); 
1992/0911    
	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; 
1991/1007    
} 
 
void 
1990/1223    
flushmmu(void) 
{ 
1992/0911    
	Ctx *c; 
	Pmeg *p; 
 
1990/1226    
	splhi(); 
1991/1007    
	u->p->newtlb = 1; 
1990/1226    
	mapstack(u->p); 
1992/0911    
	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); 
	} 
1990/1226    
	spllo(); 
1990/1223    
} 
 
void 
1990/1226    
cacheinit(void) 
1992/0911    
invalidateu(void) 
1990/1223    
{ 
1992/0806    
	int i; 
1990/1226    
                 
1992/0806    
	putcontext(0); 
1990/1226    
	/* 
	 * Initialize cache by clearing the valid bit 
	 * (along with the others) in all cache entries 
	 */ 
1992/0807    
	for(i=0; i<conf.vacsize; i+=conf.vaclinesize) 
1992/0806    
		putsysspace(CACHETAGS+i, 0); 
1991/0110    
                 
1990/1226    
	/* 
	 * Turn cache on 
	 */ 
1992/0806    
	putenab(getenab()|ENABCACHE); /**/ 
1992/0911    
	putpme(USERADDR, INVALIDPTE, 1); 
1990/1223    
} 
 
1992/0911    
struct 
{ 
	Lock; 
	KMap	*free; 
	KMap	arena[IOSEGSIZE/BY2PG]; 
}kmapalloc; 
 
1990/1223    
void 
kmapinit(void) 
{ 
	KMap *k; 
1990/1226    
	int i; 
1992/0911    
	ulong va; 
1990/1223    
 
	kmapalloc.free = 0; 
1990/1226    
	k = kmapalloc.arena; 
1992/0812    
	for(i=0; i<(IOEND-IOSEGM0)/BY2PG; i++,k++){ 
		k->va = IOSEGM0+i*BY2PG; 
1992/0911    
	for(va = IOSEGM; va < IOSEGM + IOSEGSIZE; va += BY2PG, k++){ 
		k->va = va; 
1990/1223    
		kunmap(k); 
	} 
} 
1992/0813/sys/src/9/ss/mmu.c:346,3561992/0911/sys/src/9/ss/mmu.c:584,606
1990/1223    
	unlock(&kmapalloc); 
1990/1227    
	k->pa = pa; 
1992/0101    
	s = splhi(); 
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag); 
1992/0911    
	putpme(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|flag, 1); 
1992/0101    
	splx(s); 
	return k; 
1992/0812    
} 
 
1992/0911    
 
void 
kunmap(KMap *k) 
{ 
	k->pa = 0; 
	lock(&kmapalloc); 
	k->next = kmapalloc.free; 
	kmapalloc.free = k; 
	putpme(k->va, INVALIDPTE, 1); 
	unlock(&kmapalloc); 
} 
 
1992/0812    
ulong 
kmapregion(ulong pa, ulong n, ulong flag) 
{ 
1992/0813/sys/src/9/ss/mmu.c:383,5671992/0911/sys/src/9/ss/mmu.c:633,635
1992/0101    
	return kmappa(pg->pa, PTEMAINMEM|PTENOCACHE); 
1990/1223    
} 
 
1990/1226    
KMap* 
1992/0101    
kmapperm(Page *pg) 
1990/1226    
{ 
1992/0101    
	/* 
	 * Here we know it's a permanent entry and can be cached. 
	 */ 
1990/1227    
	return kmappa(pg->pa, PTEMAINMEM); 
1990/1226    
} 
                 
1990/1223    
void 
kunmap(KMap *k) 
{ 
	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); 
1992/0806    
} 
                 
/* 
 * 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); 
1992/0807    
		flushcx = compile16(conf.vaclinesize, 7); 
1992/0806    
	}else{ 
1992/0807    
		flushpg = compile16(conf.vaclinesize, 0xD); 
		flushcx = compile16(conf.vaclinesize, 0xE); 
1992/0806    
	} 
} 
                 
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; 
1990/1223    
} 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)