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

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

1991/0115/sys/src/9/ss/mmu.c:1,3631991/01151/sys/src/9/ss/mmu.c:1,355 (short | long | prev | next)
1990/1223    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1990/1226    
#include	"io.h" 
1990/1223    
 
struct 
{ 
	Lock; 
	int	init; 
1990/1226    
	int	lowpmeg; 
1990/1223    
	KMap	*free; 
1990/1226    
	KMap	arena[(IOEND-IOSEGM)/BY2PG]; 
1990/1223    
}kmapalloc; 
 
1991/0111    
#define	NKLUDGE	12 
1991/0110    
 
1990/1223    
/* 
1990/1226    
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated 
 */ 
 
int	newpid(Proc*); 
void	purgepid(int); 
1991/0110    
int	pidtime[NTLBPID];	/* should be per m */ 
1990/1226    
 
/* 
1990/1223    
 * Called splhi, not in Running state 
 */ 
void 
mapstack(Proc *p) 
{ 
1990/1226    
	short tp; 
	ulong tlbphys; 
1990/1223    
 
1990/1226    
	tp = p->pidonmach[m->machno]; 
	if(tp == 0){ 
		tp = newpid(p); 
		p->pidonmach[m->machno] = tp; 
	} 
1990/1223    
	if(p->upage->va != (USERADDR|(p->pid&0xFFFF))) 
1991/0110    
		panic("mapstack %s %d %lux 0x%lux 0x%lux", p->text, p->pid, p->upage, p->upage->pa, p->upage->va); 
1990/1226    
	tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; 
	putcontext(tp-1); 
1990/1227    
	/* 
1991/0110    
	 * shouldn't need putpmeg because nothing has been mapped at 
	 * USERADDR in this context except this page.  however, it crashes. 
1990/1227    
	 */ 
1990/1226    
	putpmeg(USERADDR, tlbphys); 
1990/1223    
	u = (User*)USERADDR; 
1990/1226    
} 
1990/1223    
 
1990/1226    
/* 
 * Process must be non-interruptible 
 */ 
int 
newpid(Proc *p) 
{ 
1991/0109    
	int i, j, k; 
1991/0110    
	ulong t; 
1990/1226    
	Proc *sp; 
 
1991/0110    
	t = ~0; 
	i = 1+((m->ticks)&(NCONTEXT-1));	/* random guess */ 
	for(j=1; j<NTLBPID; j++) 
		if(pidtime[j] < t){ 
			i = j; 
			t = pidtime[j]; 
		} 
	 
1990/1226    
	sp = m->pidproc[i]; 
1991/0115    
	if(sp) 
1990/1226    
		sp->pidonmach[m->machno] = 0; 
1991/0115    
	purgepid(i);	/* also does putcontext */ 
1991/0110    
	pidtime[i] = m->ticks; 
1990/1226    
	m->pidproc[i] = p; 
	m->lastpid = i; 
1991/0111    
 
1990/1223    
	/* 
1991/0112    
	 * kludge: each context is allowed NKLUDGE pmegs. 
	 * NKLUDGE-1 for text & data and 1 for stack. 
	 * initialize by giving just a stack segment. 
1990/1223    
	 */ 
1991/0112    
	i--;	/* now i==context */ 
	p->nmmuseg = 0; 
1991/0110    
	for(j=0; j<NKLUDGE-1; j++) 
1991/0112    
		putsegm(UZERO+j*BY2SEGM, INVALIDPMEG); 
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+NKLUDGE*i+(NKLUDGE-1)); 
	for(j=0; j<PG2SEGM; j++) 
1990/1226    
		putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE); 
1991/0112    
	return i+1; 
1990/1226    
} 
1990/1223    
 
1990/1226    
void 
1990/1231    
putcontext(int c) 
{ 
	putcxreg(c); 
} 
 
void 
1991/0110    
flushcontext(void) 
1990/1226    
{ 
1991/0110    
	int i; 
1990/1223    
 
1991/0110    
	/* 
	 * Clear context from cache 
	 */ 
	for(i=0; i<0x1000; i+=16) 
		putwE16((i<<4), 0); 
} 
 
void 
purgepid(int pid) 
{ 
1990/1226    
	putcontext(pid-1); 
1991/0110    
	flushcontext(); 
1990/1223    
} 
 
1990/1226    
 
1990/1223    
void 
1990/1226    
mmuinit(void) 
1990/1223    
{ 
1990/1226    
	ulong l, i, j, c, pte; 
 
	/* 
	 * First map lots of memory as kernel addressable in all contexts 
	 */ 
	i = 0;		/* used */ 
	for(c=0; c<NCONTEXT; c++) 
		for(i=0; i<conf.maxialloc/BY2SEGM; i++) 
			putcxsegm(c, KZERO+i*BY2SEGM, i); 
	kmapalloc.lowpmeg = i; 
	/* 
	 * Make sure cache is turned on for kernel 
	 */ 
	pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM; 
	for(i=0; i<conf.maxialloc/BY2PG; i++) 
		putpmeg(KZERO+i*BY2PG, pte+i); 
 
	/* 
	 * Create invalid pmeg; use highest segment 
	 */ 
	putsegm(INVALIDSEGM, INVALIDPMEG); 
	for(i=0; i<PG2SEGM; i++) 
		putpmeg(INVALIDSEGM+i*BY2PG, INVALIDPTE); 
	for(c=0; c<NCONTEXT; c++){ 
		putcontext(c); 
		putsegm(INVALIDSEGM, INVALIDPMEG); 
		/* 
		 * Invalidate user addresses 
		 */ 
1990/1227    
		for(l=UZERO; l<(KZERO&VAMASK); l+=BY2SEGM) 
1990/1226    
			putsegm(l, INVALIDPMEG); 
1990/1227    
 
1991/0111    
#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); 
		if(c == 0){ 
			pte = PTEVALID|PTEWRITE|PTEKERNEL|PTENOCACHE| 
				PTEIO|((DISPLAYRAM>>PGSHIFT)&0xFFFF); 
			for(i=0; i<PG2SEGM; i++) 
				putpmeg(SCREENSEGM+i*BY2PG, pte+i); 
		} 
		/* 
		 * First page of IO space includes ROM; be careful 
		 */ 
		putsegm(IOSEGM0, IOPMEG0);	/* IOSEGM == ROMSEGM */ 
		if(c == 0){ 
			pte = PTEVALID|PTEKERNEL|PTENOCACHE| 
				PTEIO|((EPROM>>PGSHIFT)&0xFFFF); 
			for(i=0; i<PG2ROM; i++) 
				putpmeg(IOSEGM0+i*BY2PG, pte+i); 
			for(; i<PG2SEGM; i++) 
				putpmeg(IOSEGM0+i*BY2PG, INVALIDPTE); 
		} 
		/* 
		 * Remaining segments for IO and kmap 
		 */ 
		for(j=1; j<NIOSEGM; j++){ 
			putsegm(IOSEGM0+j*BY2SEGM, IOPMEG0+j); 
			if(c == 0) 
				for(i=0; i<PG2SEGM; i++) 
					putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE); 
		} 
	} 
	putcontext(0); 
1990/1223    
} 
 
void 
putmmu(ulong tlbvirt, ulong tlbphys) 
{ 
1990/1226    
	short tp; 
	Proc *p; 
1991/0112    
	ulong seg, l; 
	int j, k; 
1990/1223    
 
1990/1226    
	splhi(); 
	p = u->p; 
	tp = p->pidonmach[m->machno]; 
	if(tp == 0){ 
		tp = newpid(p); 
		p->pidonmach[m->machno] = tp; 
1990/1223    
	} 
1990/1226    
	/* 
	 * kludge part 2: make sure we've got a valid segment 
	 */ 
1991/0112    
	if(TSTKTOP-BY2SEGM<=tlbvirt && tlbvirt<TSTKTOP)	/* stack; easy */ 
		goto put; 
	/* UZERO is known to be zero here */ 
	if(tlbvirt < UZERO+p->nmmuseg*BY2SEGM)		/* in range; easy */ 
		goto put; 
	seg = tlbvirt/BY2SEGM; 
	if(seg >= (UZERO/BY2SEGM)+(NKLUDGE-1)){ 
		pprint("putmmu %lux\n", tlbvirt); 
print("putmmu %lux %d %s\n", tlbvirt, seg, p->text); 
1991/0111    
		pexit("Suicide", 1); 
1991/0110    
	} 
1991/0112    
	/* 
	 * Prepare mmu up to this address 
	 */ 
1991/0115    
	tp = (tp-1)*NKLUDGE;	/* now tp==base of pmeg area for this proc */ 
1991/0112    
	l = UZERO+p->nmmuseg*BY2SEGM; 
	for(j=p->nmmuseg; j<=seg; j++){ 
		putsegm(l, kmapalloc.lowpmeg+tp+j); 
		for(k=0; k<PG2SEGM; k++,l+=BY2PG) 
			putpmeg(l, INVALIDPTE); 
	} 
	p->nmmuseg = seg+1; 
    put: 
1990/1226    
	putpmeg(tlbvirt, tlbphys); 
	spllo(); 
1990/1223    
} 
 
void 
1990/1227    
putpmeg(ulong virt, ulong phys) 
{ 
	int i; 
1990/1231    
	int tp; 
1990/1227    
 
	virt &= VAMASK; 
	virt &= ~(BY2PG-1); 
	/* 
	 * Flush old entries from cache 
	 */ 
1991/0110    
	for(i=0; i<0x100; i+=16) 
		putwD16(virt+(i<<4), 0); 
1990/1227    
	putw4(virt, phys); 
} 
 
void 
1990/1223    
flushmmu(void) 
{ 
1991/0110    
	int tp; 
 
1990/1226    
	splhi(); 
1991/0110    
	flushcontext(); 
	tp = u->p->pidonmach[m->machno]; 
	if(tp) 
		pidtime[tp] = 0; 
1990/1226    
	/* easiest is to forget what pid we had.... */ 
	memset(u->p->pidonmach, 0, sizeof u->p->pidonmach); 
	/* ....then get a new one by trying to map our stack */ 
	mapstack(u->p); 
	spllo(); 
1990/1223    
} 
 
void 
1990/1226    
cacheinit(void) 
1990/1223    
{ 
1991/0110    
	int c, i; 
1990/1226    
 
	/* 
	 * Initialize cache by clearing the valid bit 
	 * (along with the others) in all cache entries 
	 */ 
1991/0110    
	for(c=0; c<NCONTEXT; c++){	/* necessary? */ 
		putcontext(c); 
		for(i=0; i<0x1000; i++) 
			putw2(CACHETAGS+(i<<4), 0); 
	} 
	putcontext(0); 
 
1990/1226    
	/* 
	 * Turn cache on 
	 */ 
	putb2(ENAB, getb2(ENAB)|ENABCACHE); /**/ 
1990/1223    
} 
 
void 
kmapinit(void) 
{ 
	KMap *k; 
1990/1226    
	int i; 
1990/1223    
 
1991/0110    
print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG); 
1990/1223    
	kmapalloc.free = 0; 
1990/1226    
	k = kmapalloc.arena; 
	for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){ 
		k->va = IOSEGM+i*BY2PG; 
1990/1223    
		kunmap(k); 
	} 
} 
 
KMap* 
1990/1227    
kmappa(ulong pa, ulong flag) 
1990/1223    
{ 
	KMap *k; 
1991/0110    
	ulong s; 
1990/1223    
 
	lock(&kmapalloc); 
	k = kmapalloc.free; 
	if(k == 0){ 
		dumpstack(); 
		panic("kmap"); 
	} 
	kmapalloc.free = k->next; 
	unlock(&kmapalloc); 
1990/1227    
	k->pa = pa; 
1990/1226    
	/* 
	 * Cache is virtual and a pain to deal with. 
	 * Must avoid having the same entry in the cache twice, so 
	 * must use NOCACHE or else extreme cleverness elsewhere. 
	 */ 
1991/0110    
	s = splhi(); 
1990/1227    
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag); 
1991/0110    
	splx(s); 
1990/1223    
	return k; 
} 
 
1990/1226    
KMap* 
kmap(Page *pg) 
{ 
1990/1227    
	return kmappa(pg->pa, PTEMAINMEM); 
1990/1226    
} 
 
1990/1223    
void 
kunmap(KMap *k) 
{ 
1990/1226    
	ulong pte; 
	int i; 
 
1990/1223    
	k->pa = 0; 
	lock(&kmapalloc); 
	k->next = kmapalloc.free; 
	kmapalloc.free = k; 
1990/1226    
	putpmeg(k->va, INVALIDPTE); 
1990/1223    
	unlock(&kmapalloc); 
} 
 
void 
invalidateu(void) 
{ 
1990/1226    
	putpmeg(USERADDR, INVALIDPTE); 
1990/1223    
} 


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