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

2000/1002/bitsy/mmu.c (diff list | history)

bitsy/mmu.c on 2000/0902
2000/0902    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
#include	"ureg.h" 
#include	"../port/error.h" 
 
2000/0906    
/* real protection bits */ 
enum 
{ 
2000/0907    
	/* level 1 descriptor bits */ 
	L1TypeMask=	(3<<0), 
	L1Invalid=	(0<<0), 
	L1PageTable=	(1<<0), 
	L1Section=	(2<<0), 
	L1Cached=	(1<<3), 
	L1Buffered=	(1<<2), 
	L1Domain0=	(0<<5), 
	L1KernelRW=	(0x1<<10), 
	L1UserRO=	(0x2<<10), 
	L1UserRW=	(0x3<<10), 
	L1SectBaseMask=	(0xFFF<<20), 
	L1PTBaseMask=	(0x3FFFFF<<10), 
	 
	/* level 2 descriptor bits */ 
	L2TypeMask=	(3<<0), 
	L2SmallPage=	(2<<0), 
	L2LargePage=	(1<<0), 
	L2Cached=	(1<<3), 
	L2Buffered=	(1<<2), 
	L2KernelRW=	(0x55<<4), 
	L2UserRO=	(0xAA<<4), 
	L2UserRW=	(0xFF<<4), 
	L2PageBaseMask=	(0xFFFFF<<12), 
2000/0906    
}; 
 
/* 
 *  table to map fault.c bits to physical bits 
 */ 
2000/0907    
static ulong phystrans[16] = 
2000/0906    
{ 
2000/0907    
	[PTEVALID]				L2SmallPage|L2Cached|L2Buffered|L2UserRO, 
	[PTEVALID|PTEWRITE]			L2SmallPage|L2Cached|L2Buffered|L2UserRW, 
	[PTEVALID|PTEUNCACHED]			L2SmallPage|L2UserRO, 
	[PTEVALID|PTEUNCACHED|PTEWRITE]		L2SmallPage|L2UserRW, 
 
	[PTEKERNEL|PTEVALID]			L2SmallPage|L2Cached|L2Buffered|L2KernelRW, 
	[PTEKERNEL|PTEVALID|PTEWRITE]		L2SmallPage|L2Cached|L2Buffered|L2KernelRW, 
	[PTEKERNEL|PTEVALID|PTEUNCACHED]		L2SmallPage|L2KernelRW, 
	[PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE]	L2SmallPage|L2KernelRW, 
2000/0906    
}; 
 
2000/0907    
ulong *l1table; 
2000/0906    
 
/* 
 *  We map all of memory, flash, and the zeros area with sections. 
 *  Special use space is mapped on the fly with regmap. 
 */ 
2000/0902    
void 
2000/0905    
mmuinit(void) 
{ 
2000/0906    
	ulong a, e; 
2000/0929    
	ulong *t; 
2000/0906    
 
	/* get a prototype level 1 page */ 
2000/0907    
	l1table = xspanalloc(BY2PG, 16*1024, 0); 
	memset(l1table, 0, BY2PG); 
2000/0906    
 
2000/0907    
	/* direct map DRAM */ 
2000/0928    
	e = conf.base1 + BY2PG*conf.npage1; 
2000/0907    
	for(a = PHYSDRAM0; a < e; a += OneMeg) 
2000/0929    
		l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask) | 
				L1Cached | L1Buffered; 
2000/0907    
 
	/* direct map zeros area */ 
	for(a = PHYSNULL0; a < PHYSNULL0 + 128 * OneMeg; a += OneMeg) 
2000/0929    
		l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask); 
2000/0907    
 
	/* direct map flash */ 
2000/0928    
	for(a = PHYSFLASH0; a < PHYSFLASH0 + 128 * OneMeg; a += OneMeg) 
2000/0929    
		l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask) | 
				L1Cached | L1Buffered; 
2000/0907    
 
2000/0929    
	/* map first page of DRAM also into 0xFFFF0000 for the interrupt vectors */ 
	t = xspanalloc(BY2PG, 16*1024, 0); 
	memset(t, 0, BY2PG); 
	l1table[0xFFFF0000>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); 
	t[0xF0000>>PGSHIFT] = L2SmallPage | L2KernelRW | PHYSDRAM0; 
2000/0928    
 
	/* set up the domain register to cause all domains to obey pte access bits */ 
	iprint("setting up domain access\n"); 
2000/0929    
	putdac(0xFFFFFFFF); 
2000/0928    
 
	/* point to map */ 
	iprint("setting tlb map %lux\n", (ulong)l1table); 
	putttb((ulong)l1table); 
2000/0929    
 
	/* map the uart so that we can continue using iprint */ 
2000/1002    
	uart3regs = mapspecial(UART3REGS, 64); 
2000/0929    
 
	/* enable mmu, and make 0xFFFF0000 the virtual address of the exception vecs */ 
	mmuenable(); 
 
	iprint("uart3regs now at %lux\n", uart3regs); 
2000/0907    
} 
 
/* 
2000/0923    
 *  map special space uncached, assume that the space isn't already mapped 
2000/0907    
 */ 
2000/1002    
void* 
2000/0924    
mapspecial(ulong pa, int len) 
2000/0907    
{ 
	ulong *t; 
2000/0928    
	ulong va, i, base, end, off, entry; 
2000/0924    
	int livelarge; 
	ulong* rv; 
2000/0907    
 
2000/0924    
	rv = nil; 
	livelarge = len >= 128*1024; 
	if(livelarge){ 
		base = pa & ~(OneMeg-1); 
		end = (pa+len-1) & ~(OneMeg-1); 
	} else { 
		base = pa & ~(BY2PG-1); 
		end = (pa+len-1) & ~(BY2PG-1); 
	} 
	off = pa - base; 
2000/0921    
 
2000/0929    
	for(va = REGZERO; va < REGTOP && base <= end; va += OneMeg){ 
		switch(l1table[va>>20] & L1TypeMask){ 
		default: 
2000/0924    
			/* found unused entry on level 1 table */ 
			if(livelarge){ 
				if(rv == nil) 
2000/0929    
					rv = (ulong*)(va+off); 
2000/0924    
				l1table[va>>20] = L1Section | L1KernelRW | 
2000/0929    
							(base & L1SectBaseMask); 
2000/0924    
				base += OneMeg; 
				continue; 
2000/0929    
			} else { 
2000/0924    
 
2000/0929    
				/* create an L2 page table and keep going */ 
				t = xspanalloc(BY2PG, 1024, 0); 
				memset(t, 0, BY2PG); 
				l1table[va>>20] = L1PageTable | L1Domain0 | 
							(((ulong)t) & L1PTBaseMask); 
			} 
			break; 
		case L1Section: 
			continue; 
		case L1PageTable: 
			if(livelarge) 
				continue; 
			break; 
2000/0907    
		} 
2000/0924    
 
2000/0929    
		/* here if we're using page maps instead of sections */ 
2000/0924    
		t = (ulong*)(l1table[va>>20] & L1PTBaseMask); 
2000/0907    
		for(i = 0; i < OneMeg; i += BY2PG){ 
2000/0924    
			entry = t[i>>PGSHIFT]; 
2000/0921    
 
2000/0924    
			/* found unused entry on level 2 table */ 
			if((entry & L2TypeMask) != L2SmallPage){ 
				if(rv == nil) 
2000/0929    
					rv = (ulong*)(va+i+off); 
2000/0924    
				t[i>>PGSHIFT] = L2SmallPage | L2KernelRW |  
						(base & L2PageBaseMask); 
				base += BY2PG; 
				continue; 
2000/0921    
			} 
2000/0907    
		} 
	} 
2000/0909    
 
2000/0924    
	/* didn't fit */ 
	if(base <= end) 
		return nil; 
 
	return rv; 
2000/0905    
} 
 
void 
2000/0902    
putmmu(ulong va, ulong pa, Page*) 
{ 
	USED(va, pa); 
} 
 
void 
mmurelease(Proc* proc) 
{ 
	USED(proc); 
} 
 
void 
mmuswitch(Proc* proc) 
{ 
	USED(proc); 
} 


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