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

2001/0728/alphapc/mmu.c (diff list | history)

alphapc/mmu.c on 1999/0415
1999/0415    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"/sys/src/boot/alphapc/conf.h" 
 
static uvlong	origlvl1;	/* physical address */ 
static uvlong	klvl2;	/* physical, as created by boot loader */ 
static uchar	*nextio;	/* next virtual address to be allocated by kmapv */ 
extern Bootconf *bootconf; 
 
#define LVL2OFF(v)	((((long)(v))>>(2*PGSHIFT-3))&(PTE2PG-1)) 
#define LVL3OFF(v)	((((long)(v))>>(PGSHIFT))&(PTE2PG-1)) 
 
static void 
setptb(ulong pa) 
{ 
	m->ptbr = (uvlong)pa>>PGSHIFT; 
	swpctx(m); 
} 
 
void 
mmuinit(void) 
{ 
	uvlong *plvl2; 
 
	/* set PCB to new one in mach structure before stomping on old one */ 
	m->usp = 0; 
	m->fen = 1; 
	m->ptbr = bootconf->pcb->ptbr; 
	origlvl1 = (m->ptbr << PGSHIFT); 
	setpcb(m); 
 
	plvl2 = (uvlong*) (KZERO|origlvl1|(BY2PG-8)); 
	klvl2 = (*plvl2 >> 32)<<PGSHIFT; 
 
	nextio = (uchar*) (KZERO|bootconf->maxphys); 
} 
 
2001/0728    
static void 
mmuptefree(Proc* proc) 
1999/0415    
{ 
	uvlong *lvl2; 
2001/0728    
	Page **last, *page; 
1999/0415    
 
2001/0728    
	if(proc->mmutop && proc->mmuused){ 
		lvl2 = (uvlong*)proc->mmulvl2->va; 
		last = &proc->mmuused; 
		for(page = *last; page; page = page->next){ 
			lvl2[page->daddr] = 0; 
			last = &page->next; 
1999/0415    
		} 
2001/0728    
		*last = proc->mmufree; 
		proc->mmufree = proc->mmuused; 
		proc->mmuused = 0; 
1999/0415    
	} 
2001/0728    
} 
1999/0415    
 
2001/0728    
void 
mmuswitch(Proc *proc) 
{ 
	if(proc->newtlb){ 
		mmuptefree(proc); 
		proc->newtlb = 0; 
	} 
 
1999/0415    
	/* tell processor about new page table and flush cached entries */ 
2001/0728    
	if(proc->mmutop == 0) 
1999/0415    
		setptb(origlvl1); 
	else 
2001/0728    
		setptb(proc->mmutop->pa); 
1999/0415    
	tlbflush(-1, 0); 
	icflush(); 
} 
 
/* 
 *  give all page table pages back to the free pool.  This is called in sched() 
 *  with palloc locked. 
 */ 
void 
2001/0728    
mmurelease(Proc *proc) 
1999/0415    
{ 
2001/0728    
	Page *page, *next; 
1999/0415    
 
	/* point to protoype page map */ 
	setptb(origlvl1); 
	icflush(); 
 
2001/0728    
	mmuptefree(proc); 
	proc->mmuused = 0; 
	if(proc->mmutop) { 
		proc->mmutop->next = proc->mmufree; 
		proc->mmufree = proc->mmutop; 
		proc->mmutop = 0; 
1999/0415    
	} 
2001/0728    
	if(proc->mmulvl2) { 
		proc->mmulvl2->next = proc->mmufree; 
		proc->mmufree = proc->mmulvl2; 
		proc->mmulvl2 = 0; 
1999/0415    
	} 
2001/0728    
	for(page = proc->mmufree; page; page = next){ 
		next = page->next; 
		if(--page->ref) 
			panic("mmurelease: page->ref %d\n", page->ref); 
		pagechainhead(page); 
1999/0415    
	} 
2001/0728    
	if(proc->mmufree && palloc.r.p) 
1999/0415    
		wakeup(&palloc.r); 
2001/0728    
	proc->mmufree = 0; 
1999/0415    
} 
 
void 
mmunewtop(void) 
{ 
	Page *top, *lvl2; 
	uvlong *ppte; 
 
	top = newpage(1, 0, 0); 
	top->va = VA(kmap(top)); 
	lvl2 = newpage(1, 0, 0); 
	lvl2->va = VA(kmap(lvl2)); 
 
	ppte = (uvlong *)top->va; 
	ppte[0] = PTEPFN(lvl2->pa) | PTEKVALID; 
	ppte[PTE2PG-2] = PTEPFN(top->pa) | PTEKVALID; 
	ppte[PTE2PG-1] = PTEPFN(klvl2) | PTEKVALID; 
 
	up->mmutop = top; 
	up->mmulvl2 = lvl2; 
	setptb(top->pa); 
	tlbflush(-1, 0); 
	icflush(); 
} 
 
void 
putmmu(ulong va, ulong pa, Page *pg) 
{ 
	int lvl2off; 
	uvlong *lvl2, *pt; 
	int s; 
 
	if(up->mmutop == 0) 
		mmunewtop(); 
 
	lvl2 = (uvlong*)up->mmulvl2->va; 
	lvl2off = LVL2OFF(va); 
 
	/* 
	 *  if bottom level page table missing, allocate one  
	 *  and point the top level page at it. 
	 */ 
	s = splhi(); 
	if(lvl2[lvl2off] == 0){ 
		if(up->mmufree == 0){ 
			spllo(); 
			pg = newpage(1, 0, 0); 
			pg->va = VA(kmap(pg)); 
			splhi(); 
		} else { 
			pg = up->mmufree; 
			up->mmufree = pg->next; 
			memset((void*)pg->va, 0, BY2PG); 
		} 
		lvl2[lvl2off] = PTEPFN(pg->pa) | PTEVALID; 
		pg->daddr = lvl2off; 
		pg->next = up->mmuused; 
		up->mmuused = pg; 
	} 
 
	/* 
	 *  put in new mmu entry 
	 */ 
	pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO); 
	pt[LVL3OFF(va)] = FIXPTE(pa); 
 
	/* flush cached mmu entries */ 
	tlbflush(3, va); 
	icflush(); 
	splx(s); 
} 
 
void * 
kmapv(uvlong pa, int size) 
{ 
	void *va, *new; 
	int lvl2off, i, npage, offset; 
	uvlong *lvl2, *pt; 
 
	offset = pa&(BY2PG-1); 
	npage = ((size+offset+BY2PG-1)>>PGSHIFT); 
 
	va = nextio+offset; 
	lvl2 = (uvlong*)(KZERO|klvl2); 
	for (i = 0; i < npage; i++) { 
		lvl2off = LVL2OFF(nextio); 
		if (lvl2[lvl2off] == 0) { 
			new = xspanalloc(BY2PG, BY2PG, 0); 
			memset(new, 0, BY2PG); 
			lvl2[lvl2off] = PTEPFN(PADDR(new)) | PTEKVALID | PTEASM; 
		} 
		pt = (uvlong*)(((lvl2[lvl2off] >> 32)<<PGSHIFT)|KZERO); 
		pt[LVL3OFF(nextio)] = PTEPFN(pa) | PTEKVALID | PTEASM; 
		nextio += BY2PG; 
		pa += BY2PG; 
	} 
	return va; 
} 
 
void 
flushmmu(void) 
{ 
	int s; 
 
	s = splhi(); 
	up->newtlb = 1; 
	mmuswitch(up); 
	splx(s); 
 
} 
 
ulong 
1999/0511    
upamalloc(ulong pa, int size, int align) 
1999/0415    
{ 
1999/0511    
	void *va; 
 
	/* 
2000/0517    
	 * Viability hack. Only for PCI framebuffers. 
1999/0511    
	 */ 
1999/0512    
	if(pa == 0) 
		return 0; 
1999/0511    
	USED(align); 
	va = kmapv(((uvlong)0x88<<32LL)|pa, size); 
	if(va == nil) 
		return 0; 
	return PADDR(va); 
1999/0415    
} 
 
void 
2000/0401    
upafree(ulong, int) 
1999/0415    
{ 
2000/0401    
	print("upafree: virtual mapping not freed\n"); 
1999/0415    
} 
2001/0727    
 
void 
mmudump(void) 
{ 
	Page *top, *lvl2; 
 
	iprint("ptbr %lux up %lux\n", (ulong)m->ptbr, up); 
	if(up) { 
		top = up->mmutop; 
		if(top != nil) 
			iprint("top %lux top[N-1] %lux\n", top->va, ((uvlong *)top->va)[PTE2PG-1]); 
		lvl2 = up->mmulvl2; 
		if(lvl2 != nil) 
			iprint("lvl2 %lux\n", lvl2->va); 
	} 
} 


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