xref: /plan9-contrib/sys/src/9/bcm/mmu.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
15d9de2d3SDavid du Colombier #include "u.h"
25d9de2d3SDavid du Colombier #include "../port/lib.h"
35d9de2d3SDavid du Colombier #include "mem.h"
45d9de2d3SDavid du Colombier #include "dat.h"
55d9de2d3SDavid du Colombier #include "fns.h"
65d9de2d3SDavid du Colombier 
75d9de2d3SDavid du Colombier #include "arm.h"
85d9de2d3SDavid du Colombier 
9*5c47fe09SDavid du Colombier static KMap* kmapp(ulong pa);
10*5c47fe09SDavid du Colombier 
115d9de2d3SDavid du Colombier #define L1X(va)		FEXT((va), 20, 12)
125d9de2d3SDavid du Colombier #define L2X(va)		FEXT((va), 12, 8)
13*5c47fe09SDavid du Colombier #define L2AP(ap)	l2ap(ap)
14*5c47fe09SDavid du Colombier #define L1ptedramattrs	soc.l1ptedramattrs
15*5c47fe09SDavid du Colombier #define L2ptedramattrs	soc.l2ptedramattrs
165d9de2d3SDavid du Colombier 
175d9de2d3SDavid du Colombier enum {
185d9de2d3SDavid du Colombier 	L1lo		= UZERO/MiB,		/* L1X(UZERO)? */
195d9de2d3SDavid du Colombier 	L1hi		= (USTKTOP+MiB-1)/MiB,	/* L1X(USTKTOP+MiB-1)? */
20*5c47fe09SDavid du Colombier 	L2size		= 256*sizeof(PTE),
21*5c47fe09SDavid du Colombier 	KMAPADDR	= 0xFFF00000,
225d9de2d3SDavid du Colombier };
235d9de2d3SDavid du Colombier 
24*5c47fe09SDavid du Colombier /*
25*5c47fe09SDavid du Colombier  * Set up initial PTEs for cpu0 (called with mmu off)
26*5c47fe09SDavid du Colombier  */
275d9de2d3SDavid du Colombier void
mmuinit(void * a)28*5c47fe09SDavid du Colombier mmuinit(void *a)
295d9de2d3SDavid du Colombier {
305d9de2d3SDavid du Colombier 	PTE *l1, *l2;
31*5c47fe09SDavid du Colombier 	uintptr pa, pe, va;
325d9de2d3SDavid du Colombier 
33*5c47fe09SDavid du Colombier 	l1 = (PTE*)a;
345d9de2d3SDavid du Colombier 	l2 = (PTE*)PADDR(L2);
355d9de2d3SDavid du Colombier 
365d9de2d3SDavid du Colombier 	/*
37*5c47fe09SDavid du Colombier 	 * map ram between KZERO and VIRTIO
385d9de2d3SDavid du Colombier 	 */
395d9de2d3SDavid du Colombier 	va = KZERO;
40*5c47fe09SDavid du Colombier 	pe = VIRTPCI - KZERO;
41*5c47fe09SDavid du Colombier 	if(pe > soc.dramsize)
42*5c47fe09SDavid du Colombier 		pe = soc.dramsize;
43*5c47fe09SDavid du Colombier 	for(pa = PHYSDRAM; pa < PHYSDRAM+pe; pa += MiB){
44*5c47fe09SDavid du Colombier 		l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section|L1ptedramattrs;
455d9de2d3SDavid du Colombier 		va += MiB;
465d9de2d3SDavid du Colombier 	}
475d9de2d3SDavid du Colombier 
485d9de2d3SDavid du Colombier 	/*
495d9de2d3SDavid du Colombier 	 * identity map first MB of ram so mmu can be enabled
505d9de2d3SDavid du Colombier 	 */
51*5c47fe09SDavid du Colombier 	l1[L1X(PHYSDRAM)] = PHYSDRAM|Dom0|L1AP(Krw)|Section|L1ptedramattrs;
525d9de2d3SDavid du Colombier 
535d9de2d3SDavid du Colombier 	/*
545d9de2d3SDavid du Colombier 	 * map i/o registers
555d9de2d3SDavid du Colombier 	 */
565d9de2d3SDavid du Colombier 	va = VIRTIO;
57*5c47fe09SDavid du Colombier 	for(pa = soc.physio; pa < soc.physio+IOSIZE; pa += MiB){
58*5c47fe09SDavid du Colombier 		l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section|L1noexec;
595d9de2d3SDavid du Colombier 		va += MiB;
605d9de2d3SDavid du Colombier 	}
61*5c47fe09SDavid du Colombier 	pa = soc.armlocal;
62*5c47fe09SDavid du Colombier 	if(pa)
63*5c47fe09SDavid du Colombier 		l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section|L1noexec;
64*5c47fe09SDavid du Colombier 	/*
65*5c47fe09SDavid du Colombier 	 * pi4 hack: ether and pcie are in segment 0xFD5xxxxx not 0xFE5xxxxx
66*5c47fe09SDavid du Colombier 	 *           gisb is in segment 0xFC4xxxxx not FE4xxxxx
67*5c47fe09SDavid du Colombier 	 */
68*5c47fe09SDavid du Colombier 	va = VIRTIO + 0x500000;
69*5c47fe09SDavid du Colombier 	pa = soc.physio - 0x1000000 + 0x500000;
70*5c47fe09SDavid du Colombier 	l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section|L1noexec;
71*5c47fe09SDavid du Colombier 	va = VIRTIO + 0x400000;
72*5c47fe09SDavid du Colombier 	pa = soc.physio - 0x2000000 + 0x400000;
73*5c47fe09SDavid du Colombier 	l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section|L1noexec;
745d9de2d3SDavid du Colombier 
755d9de2d3SDavid du Colombier 	/*
76*5c47fe09SDavid du Colombier 	 * double map exception vectors near top of virtual memory
775d9de2d3SDavid du Colombier 	 */
785d9de2d3SDavid du Colombier 	va = HVECTORS;
795d9de2d3SDavid du Colombier 	l1[L1X(va)] = (uintptr)l2|Dom0|Coarse;
80*5c47fe09SDavid du Colombier 	l2[L2X(va)] = PHYSDRAM|L2AP(Krw)|Small|L2ptedramattrs;
815d9de2d3SDavid du Colombier }
825d9de2d3SDavid du Colombier 
835d9de2d3SDavid du Colombier void
mmuinit1()84*5c47fe09SDavid du Colombier mmuinit1()
855d9de2d3SDavid du Colombier {
86*5c47fe09SDavid du Colombier 	PTE *l1, *l2;
87*5c47fe09SDavid du Colombier 	uintptr va;
885d9de2d3SDavid du Colombier 
89*5c47fe09SDavid du Colombier 	l1 = m->mmul1;
905d9de2d3SDavid du Colombier 
915d9de2d3SDavid du Colombier 	/*
925d9de2d3SDavid du Colombier 	 * undo identity map of first MB of ram
935d9de2d3SDavid du Colombier 	 */
945d9de2d3SDavid du Colombier 	l1[L1X(PHYSDRAM)] = 0;
95*5c47fe09SDavid du Colombier 	cachedwbtlb(&l1[L1X(PHYSDRAM)], sizeof(PTE));
96*5c47fe09SDavid du Colombier 	mmuinvalidateaddr(PHYSDRAM);
97*5c47fe09SDavid du Colombier 
98*5c47fe09SDavid du Colombier 	/*
99*5c47fe09SDavid du Colombier 	 * make a local mapping for highest MB of virtual space
100*5c47fe09SDavid du Colombier 	 * containing kmap area and exception vectors
101*5c47fe09SDavid du Colombier 	 */
102*5c47fe09SDavid du Colombier 	if(m->machno == 0)
103*5c47fe09SDavid du Colombier 		m->kmapl2 = (PTE*)L2;
104*5c47fe09SDavid du Colombier 	else{
105*5c47fe09SDavid du Colombier 		va = HVECTORS;
106*5c47fe09SDavid du Colombier 		m->kmapl2 = l2 = mallocalign(L2size, L2size, 0, 0);
107*5c47fe09SDavid du Colombier 		l1[L1X(va)] = PADDR(l2)|Dom0|Coarse;
108*5c47fe09SDavid du Colombier 		l2[L2X(va)] = PHYSDRAM|L2AP(Krw)|Small|L2ptedramattrs;
109*5c47fe09SDavid du Colombier 		cachedwbtlb(&l1[L1X(va)], sizeof(PTE));
110*5c47fe09SDavid du Colombier 		mmuinvalidateaddr(va);
111*5c47fe09SDavid du Colombier 	}
1125d9de2d3SDavid du Colombier }
1135d9de2d3SDavid du Colombier 
1145d9de2d3SDavid du Colombier static void
mmul2empty(Proc * proc,int clear)1155d9de2d3SDavid du Colombier mmul2empty(Proc* proc, int clear)
1165d9de2d3SDavid du Colombier {
1175d9de2d3SDavid du Colombier 	PTE *l1;
1185d9de2d3SDavid du Colombier 	Page **l2, *page;
119*5c47fe09SDavid du Colombier 	KMap *k;
1205d9de2d3SDavid du Colombier 
1215d9de2d3SDavid du Colombier 	l1 = m->mmul1;
1225d9de2d3SDavid du Colombier 	l2 = &proc->mmul2;
1235d9de2d3SDavid du Colombier 	for(page = *l2; page != nil; page = page->next){
124*5c47fe09SDavid du Colombier 		if(clear){
125*5c47fe09SDavid du Colombier 			k = kmap(page);
126*5c47fe09SDavid du Colombier 			memset((void*)VA(k), 0, L2size);
127*5c47fe09SDavid du Colombier 			kunmap(k);
128*5c47fe09SDavid du Colombier 		}
1295d9de2d3SDavid du Colombier 		l1[page->daddr] = Fault;
1305d9de2d3SDavid du Colombier 		l2 = &page->next;
1315d9de2d3SDavid du Colombier 	}
132*5c47fe09SDavid du Colombier 	coherence();
1335d9de2d3SDavid du Colombier 	*l2 = proc->mmul2cache;
1345d9de2d3SDavid du Colombier 	proc->mmul2cache = proc->mmul2;
1355d9de2d3SDavid du Colombier 	proc->mmul2 = nil;
1365d9de2d3SDavid du Colombier }
1375d9de2d3SDavid du Colombier 
1385d9de2d3SDavid du Colombier static void
mmul1empty(void)1395d9de2d3SDavid du Colombier mmul1empty(void)
1405d9de2d3SDavid du Colombier {
1415d9de2d3SDavid du Colombier 	PTE *l1;
1425d9de2d3SDavid du Colombier 
1435d9de2d3SDavid du Colombier 	/* clean out any user mappings still in l1 */
144*5c47fe09SDavid du Colombier 	if(m->mmul1lo > 0){
1455d9de2d3SDavid du Colombier 		if(m->mmul1lo == 1)
1465d9de2d3SDavid du Colombier 			m->mmul1[L1lo] = Fault;
1475d9de2d3SDavid du Colombier 		else
1485d9de2d3SDavid du Colombier 			memset(&m->mmul1[L1lo], 0, m->mmul1lo*sizeof(PTE));
149*5c47fe09SDavid du Colombier 		m->mmul1lo = 0;
1505d9de2d3SDavid du Colombier 	}
151*5c47fe09SDavid du Colombier 	if(m->mmul1hi > 0){
152*5c47fe09SDavid du Colombier 		l1 = &m->mmul1[L1hi - m->mmul1hi];
153*5c47fe09SDavid du Colombier 		if(m->mmul1hi == 1)
1545d9de2d3SDavid du Colombier 			*l1 = Fault;
1555d9de2d3SDavid du Colombier 		else
156*5c47fe09SDavid du Colombier 			memset(l1, 0, m->mmul1hi*sizeof(PTE));
157*5c47fe09SDavid du Colombier 		m->mmul1hi = 0;
1585d9de2d3SDavid du Colombier 	}
159*5c47fe09SDavid du Colombier 	if(m->kmapl2 != nil)
160*5c47fe09SDavid du Colombier 		memset(m->kmapl2, 0, NKMAPS*sizeof(PTE));
1615d9de2d3SDavid du Colombier }
1625d9de2d3SDavid du Colombier 
1635d9de2d3SDavid du Colombier void
mmuswitch(Proc * proc)1645d9de2d3SDavid du Colombier mmuswitch(Proc* proc)
1655d9de2d3SDavid du Colombier {
1665d9de2d3SDavid du Colombier 	int x;
1675d9de2d3SDavid du Colombier 	PTE *l1;
1685d9de2d3SDavid du Colombier 	Page *page;
1695d9de2d3SDavid du Colombier 
170*5c47fe09SDavid du Colombier 	if(proc != nil && proc->newtlb){
1715d9de2d3SDavid du Colombier 		mmul2empty(proc, 1);
1725d9de2d3SDavid du Colombier 		proc->newtlb = 0;
1735d9de2d3SDavid du Colombier 	}
1745d9de2d3SDavid du Colombier 
1755d9de2d3SDavid du Colombier 	mmul1empty();
1765d9de2d3SDavid du Colombier 
1775d9de2d3SDavid du Colombier 	/* move in new map */
1785d9de2d3SDavid du Colombier 	l1 = m->mmul1;
179*5c47fe09SDavid du Colombier 	if(proc != nil){
1805d9de2d3SDavid du Colombier 	  for(page = proc->mmul2; page != nil; page = page->next){
1815d9de2d3SDavid du Colombier 		x = page->daddr;
1825d9de2d3SDavid du Colombier 		l1[x] = PPN(page->pa)|Dom0|Coarse;
183*5c47fe09SDavid du Colombier 		if(x >= L1lo + m->mmul1lo && x < L1hi - m->mmul1hi){
184*5c47fe09SDavid du Colombier 			if(x+1 - L1lo < L1hi - x)
185*5c47fe09SDavid du Colombier 				m->mmul1lo = x+1 - L1lo;
1865d9de2d3SDavid du Colombier 			else
187*5c47fe09SDavid du Colombier 				m->mmul1hi = L1hi - x;
188*5c47fe09SDavid du Colombier 		}
189*5c47fe09SDavid du Colombier 	  }
190*5c47fe09SDavid du Colombier 	  if(proc->nkmap)
191*5c47fe09SDavid du Colombier 		memmove(m->kmapl2, proc->kmaptab, sizeof(proc->kmaptab));
1925d9de2d3SDavid du Colombier 	}
1935d9de2d3SDavid du Colombier 
1945d9de2d3SDavid du Colombier 	/* make sure map is in memory */
1955d9de2d3SDavid du Colombier 	/* could be smarter about how much? */
196*5c47fe09SDavid du Colombier 	cachedwbtlb(&l1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
197*5c47fe09SDavid du Colombier 	if(proc != nil && proc->nkmap)
198*5c47fe09SDavid du Colombier 		cachedwbtlb(m->kmapl2, sizeof(proc->kmaptab));
1995d9de2d3SDavid du Colombier 
2005d9de2d3SDavid du Colombier 	/* lose any possible stale tlb entries */
2015d9de2d3SDavid du Colombier 	mmuinvalidate();
2025d9de2d3SDavid du Colombier }
2035d9de2d3SDavid du Colombier 
2045d9de2d3SDavid du Colombier void
flushmmu(void)2055d9de2d3SDavid du Colombier flushmmu(void)
2065d9de2d3SDavid du Colombier {
2075d9de2d3SDavid du Colombier 	int s;
2085d9de2d3SDavid du Colombier 
2095d9de2d3SDavid du Colombier 	s = splhi();
2105d9de2d3SDavid du Colombier 	up->newtlb = 1;
2115d9de2d3SDavid du Colombier 	mmuswitch(up);
2125d9de2d3SDavid du Colombier 	splx(s);
2135d9de2d3SDavid du Colombier }
2145d9de2d3SDavid du Colombier 
2155d9de2d3SDavid du Colombier void
mmurelease(Proc * proc)2165d9de2d3SDavid du Colombier mmurelease(Proc* proc)
2175d9de2d3SDavid du Colombier {
2185d9de2d3SDavid du Colombier 	Page *page, *next;
2195d9de2d3SDavid du Colombier 
2205d9de2d3SDavid du Colombier 	mmul2empty(proc, 0);
2215d9de2d3SDavid du Colombier 	for(page = proc->mmul2cache; page != nil; page = next){
2225d9de2d3SDavid du Colombier 		next = page->next;
2235d9de2d3SDavid du Colombier 		if(--page->ref)
2245d9de2d3SDavid du Colombier 			panic("mmurelease: page->ref %d", page->ref);
2255d9de2d3SDavid du Colombier 		pagechainhead(page);
2265d9de2d3SDavid du Colombier 	}
2275d9de2d3SDavid du Colombier 	if(proc->mmul2cache && palloc.r.p)
2285d9de2d3SDavid du Colombier 		wakeup(&palloc.r);
2295d9de2d3SDavid du Colombier 	proc->mmul2cache = nil;
2305d9de2d3SDavid du Colombier 
2315d9de2d3SDavid du Colombier 	mmul1empty();
2325d9de2d3SDavid du Colombier 
2335d9de2d3SDavid du Colombier 	/* make sure map is in memory */
2345d9de2d3SDavid du Colombier 	/* could be smarter about how much? */
235*5c47fe09SDavid du Colombier 	cachedwbtlb(&m->mmul1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
2365d9de2d3SDavid du Colombier 
2375d9de2d3SDavid du Colombier 	/* lose any possible stale tlb entries */
2385d9de2d3SDavid du Colombier 	mmuinvalidate();
2395d9de2d3SDavid du Colombier }
2405d9de2d3SDavid du Colombier 
2415d9de2d3SDavid du Colombier void
putmmu(uintptr va,uintptr pa,Page * page)2425d9de2d3SDavid du Colombier putmmu(uintptr va, uintptr pa, Page* page)
2435d9de2d3SDavid du Colombier {
244*5c47fe09SDavid du Colombier 	int x, s;
2455d9de2d3SDavid du Colombier 	Page *pg;
2465d9de2d3SDavid du Colombier 	PTE *l1, *pte;
247*5c47fe09SDavid du Colombier 	KMap *k;
2485d9de2d3SDavid du Colombier 
249*5c47fe09SDavid du Colombier 	/*
250*5c47fe09SDavid du Colombier 	 * disable interrupts to prevent flushmmu (called from hzclock)
251*5c47fe09SDavid du Colombier 	 * from clearing page tables while we are setting them
252*5c47fe09SDavid du Colombier 	 */
253*5c47fe09SDavid du Colombier 	s = splhi();
2545d9de2d3SDavid du Colombier 	x = L1X(va);
2555d9de2d3SDavid du Colombier 	l1 = &m->mmul1[x];
2565d9de2d3SDavid du Colombier 	if(*l1 == Fault){
257*5c47fe09SDavid du Colombier 		/* l2 pages only have 256 entries - wastes 3K per 1M of address space */
2585d9de2d3SDavid du Colombier 		if(up->mmul2cache == nil){
259*5c47fe09SDavid du Colombier 			spllo();
260*5c47fe09SDavid du Colombier 			pg = newpage(0, 0, 0);
261*5c47fe09SDavid du Colombier 			splhi();
262*5c47fe09SDavid du Colombier 			/* if newpage slept, we might be on a different cpu */
263*5c47fe09SDavid du Colombier 			l1 = &m->mmul1[x];
264*5c47fe09SDavid du Colombier 		}else{
2655d9de2d3SDavid du Colombier 			pg = up->mmul2cache;
2665d9de2d3SDavid du Colombier 			up->mmul2cache = pg->next;
2675d9de2d3SDavid du Colombier 		}
2685d9de2d3SDavid du Colombier 		pg->daddr = x;
2695d9de2d3SDavid du Colombier 		pg->next = up->mmul2;
2705d9de2d3SDavid du Colombier 		up->mmul2 = pg;
2715d9de2d3SDavid du Colombier 
2725d9de2d3SDavid du Colombier 		/* force l2 page to memory */
273*5c47fe09SDavid du Colombier 		k = kmap(pg);
274*5c47fe09SDavid du Colombier 		memset((void*)VA(k), 0, L2size);
275*5c47fe09SDavid du Colombier 		cachedwbtlb((void*)VA(k), L2size);
276*5c47fe09SDavid du Colombier 		kunmap(k);
2775d9de2d3SDavid du Colombier 
2785d9de2d3SDavid du Colombier 		*l1 = PPN(pg->pa)|Dom0|Coarse;
279*5c47fe09SDavid du Colombier 		cachedwbtlb(l1, sizeof *l1);
2805d9de2d3SDavid du Colombier 
281*5c47fe09SDavid du Colombier 		if(x >= L1lo + m->mmul1lo && x < L1hi - m->mmul1hi){
282*5c47fe09SDavid du Colombier 			if(x+1 - L1lo < L1hi - x)
283*5c47fe09SDavid du Colombier 				m->mmul1lo = x+1 - L1lo;
2845d9de2d3SDavid du Colombier 			else
285*5c47fe09SDavid du Colombier 				m->mmul1hi = L1hi - x;
2865d9de2d3SDavid du Colombier 		}
2875d9de2d3SDavid du Colombier 	}
288*5c47fe09SDavid du Colombier 	k = kmapp(PPN(*l1));
289*5c47fe09SDavid du Colombier 	pte = (PTE*)VA(k);
2905d9de2d3SDavid du Colombier 
2915d9de2d3SDavid du Colombier 	/* protection bits are
2925d9de2d3SDavid du Colombier 	 *	PTERONLY|PTEVALID;
2935d9de2d3SDavid du Colombier 	 *	PTEWRITE|PTEVALID;
2945d9de2d3SDavid du Colombier 	 *	PTEWRITE|PTEUNCACHED|PTEVALID;
2955d9de2d3SDavid du Colombier 	 */
2965d9de2d3SDavid du Colombier 	x = Small;
2975d9de2d3SDavid du Colombier 	if(!(pa & PTEUNCACHED))
298*5c47fe09SDavid du Colombier 		x |= L2ptedramattrs;
2995d9de2d3SDavid du Colombier 	if(pa & PTEWRITE)
3005d9de2d3SDavid du Colombier 		x |= L2AP(Urw);
3015d9de2d3SDavid du Colombier 	else
3025d9de2d3SDavid du Colombier 		x |= L2AP(Uro);
3035d9de2d3SDavid du Colombier 	pte[L2X(va)] = PPN(pa)|x;
304*5c47fe09SDavid du Colombier 	cachedwbtlb(&pte[L2X(va)], sizeof(PTE));
305*5c47fe09SDavid du Colombier 	kunmap(k);
3065d9de2d3SDavid du Colombier 
3075d9de2d3SDavid du Colombier 	/* clear out the current entry */
3085d9de2d3SDavid du Colombier 	mmuinvalidateaddr(PPN(va));
3095d9de2d3SDavid du Colombier 
310*5c47fe09SDavid du Colombier 	if(page->cachectl[m->machno] == PG_TXTFLUSH){
3115d9de2d3SDavid du Colombier 		/* pio() sets PG_TXTFLUSH whenever a text pg has been written */
312*5c47fe09SDavid du Colombier 		if(cankaddr(page->pa))
313*5c47fe09SDavid du Colombier 			cachedwbse((void*)(page->pa|KZERO), BY2PG);
314*5c47fe09SDavid du Colombier 		cacheiinvse((void*)page->va, BY2PG);
315*5c47fe09SDavid du Colombier 		page->cachectl[m->machno] = PG_NOFLUSH;
3165d9de2d3SDavid du Colombier 	}
317*5c47fe09SDavid du Colombier 	//checkmmu(va, PPN(pa));
318*5c47fe09SDavid du Colombier 	splx(s);
319*5c47fe09SDavid du Colombier }
320*5c47fe09SDavid du Colombier 
321*5c47fe09SDavid du Colombier void*
mmuuncache(void * v,usize size)322*5c47fe09SDavid du Colombier mmuuncache(void* v, usize size)
323*5c47fe09SDavid du Colombier {
324*5c47fe09SDavid du Colombier 	int x;
325*5c47fe09SDavid du Colombier 	PTE *pte;
326*5c47fe09SDavid du Colombier 	uintptr va;
327*5c47fe09SDavid du Colombier 
328*5c47fe09SDavid du Colombier 	/*
329*5c47fe09SDavid du Colombier 	 * Simple helper for ucalloc().
330*5c47fe09SDavid du Colombier 	 * Uncache a Section, must already be
331*5c47fe09SDavid du Colombier 	 * valid in the MMU.
332*5c47fe09SDavid du Colombier 	 */
333*5c47fe09SDavid du Colombier 	va = PTR2UINT(v);
334*5c47fe09SDavid du Colombier 	assert(!(va & (1*MiB-1)) && size == 1*MiB);
335*5c47fe09SDavid du Colombier 
336*5c47fe09SDavid du Colombier 	x = L1X(va);
337*5c47fe09SDavid du Colombier 	pte = &m->mmul1[x];
338*5c47fe09SDavid du Colombier 	if((*pte & (Fine|Section|Coarse)) != Section)
339*5c47fe09SDavid du Colombier 		return nil;
340*5c47fe09SDavid du Colombier 	*pte &= ~L1ptedramattrs;
341*5c47fe09SDavid du Colombier 	mmuinvalidateaddr(va);
342*5c47fe09SDavid du Colombier 	cachedwbinvse(pte, 4);
343*5c47fe09SDavid du Colombier 
344*5c47fe09SDavid du Colombier 	return v;
3455d9de2d3SDavid du Colombier }
3465d9de2d3SDavid du Colombier 
3475d9de2d3SDavid du Colombier /*
3485d9de2d3SDavid du Colombier  * Return the number of bytes that can be accessed via KADDR(pa).
3495d9de2d3SDavid du Colombier  * If pa is not a valid argument to KADDR, return 0.
3505d9de2d3SDavid du Colombier  */
3515d9de2d3SDavid du Colombier uintptr
cankaddr(uintptr pa)3525d9de2d3SDavid du Colombier cankaddr(uintptr pa)
3535d9de2d3SDavid du Colombier {
354*5c47fe09SDavid du Colombier 	if((pa - PHYSDRAM) < VIRTPCI-KZERO)
355*5c47fe09SDavid du Colombier 		return PHYSDRAM + VIRTPCI-KZERO - pa;
3565d9de2d3SDavid du Colombier 	return 0;
3575d9de2d3SDavid du Colombier }
3585d9de2d3SDavid du Colombier 
3595d9de2d3SDavid du Colombier uintptr
mmukmap(uintptr va,uintptr pa,usize size)3605d9de2d3SDavid du Colombier mmukmap(uintptr va, uintptr pa, usize size)
3615d9de2d3SDavid du Colombier {
3625d9de2d3SDavid du Colombier 	int o;
3635d9de2d3SDavid du Colombier 	usize n;
3645d9de2d3SDavid du Colombier 	PTE *pte, *pte0;
3655d9de2d3SDavid du Colombier 
3665d9de2d3SDavid du Colombier 	assert((va & (MiB-1)) == 0);
3675d9de2d3SDavid du Colombier 	o = pa & (MiB-1);
3685d9de2d3SDavid du Colombier 	pa -= o;
3695d9de2d3SDavid du Colombier 	size += o;
3705d9de2d3SDavid du Colombier 	pte = pte0 = &m->mmul1[L1X(va)];
3715d9de2d3SDavid du Colombier 	for(n = 0; n < size; n += MiB)
3725d9de2d3SDavid du Colombier 		if(*pte++ != Fault)
3735d9de2d3SDavid du Colombier 			return 0;
3745d9de2d3SDavid du Colombier 	pte = pte0;
3755d9de2d3SDavid du Colombier 	for(n = 0; n < size; n += MiB){
376*5c47fe09SDavid du Colombier 		*pte++ = (pa+n)|Dom0|L1AP(Krw)|Section|L1noexec;
3775d9de2d3SDavid du Colombier 		mmuinvalidateaddr(va+n);
3785d9de2d3SDavid du Colombier 	}
379*5c47fe09SDavid du Colombier 	cachedwbtlb(pte0, (uintptr)pte - (uintptr)pte0);
3805d9de2d3SDavid du Colombier 	return va + o;
3815d9de2d3SDavid du Colombier }
3825d9de2d3SDavid du Colombier 
383*5c47fe09SDavid du Colombier uintptr
mmukmapx(uintptr va,uvlong pa,usize size)384*5c47fe09SDavid du Colombier mmukmapx(uintptr va, uvlong pa, usize size)
385*5c47fe09SDavid du Colombier {
386*5c47fe09SDavid du Colombier 	int o;
387*5c47fe09SDavid du Colombier 	usize n;
388*5c47fe09SDavid du Colombier 	PTE ptex, *pte, *pte0;
389*5c47fe09SDavid du Colombier 
390*5c47fe09SDavid du Colombier 	assert((va & (16*MiB-1)) == 0);
391*5c47fe09SDavid du Colombier 	assert(size <= 16*MiB);
392*5c47fe09SDavid du Colombier 	o = (int)pa & (16*MiB-1);
393*5c47fe09SDavid du Colombier 	pa -= o;
394*5c47fe09SDavid du Colombier 	ptex = FEXT(pa,24,8)<<24 | FEXT(pa,32,4)<<20 | FEXT(pa,36,4)<<5;
395*5c47fe09SDavid du Colombier 	pte = pte0 = &m->mmul1[L1X(va)];
396*5c47fe09SDavid du Colombier 	for(n = 0; n < 16*MiB; n += MiB)
397*5c47fe09SDavid du Colombier 		if(*pte++ != Fault)
398*5c47fe09SDavid du Colombier 			return 0;
399*5c47fe09SDavid du Colombier 	pte = pte0;
400*5c47fe09SDavid du Colombier 	for(n = 0; n < 16*MiB; n += MiB)
401*5c47fe09SDavid du Colombier 		*pte++ = ptex|L1AP(Krw)|Super|Section|L1noexec;
402*5c47fe09SDavid du Colombier 	mmuinvalidateaddr(va);
403*5c47fe09SDavid du Colombier 	cachedwbtlb(pte0, (uintptr)pte - (uintptr)pte0);
404*5c47fe09SDavid du Colombier 	return va + o;
405*5c47fe09SDavid du Colombier }
4065d9de2d3SDavid du Colombier 
4075d9de2d3SDavid du Colombier void
checkmmu(uintptr va,uintptr pa)4085d9de2d3SDavid du Colombier checkmmu(uintptr va, uintptr pa)
4095d9de2d3SDavid du Colombier {
410*5c47fe09SDavid du Colombier 	int x;
411*5c47fe09SDavid du Colombier 	PTE *l1, *pte;
412*5c47fe09SDavid du Colombier 	KMap *k;
413*5c47fe09SDavid du Colombier 
414*5c47fe09SDavid du Colombier 	x = L1X(va);
415*5c47fe09SDavid du Colombier 	l1 = &m->mmul1[x];
416*5c47fe09SDavid du Colombier 	if(*l1 == Fault){
417*5c47fe09SDavid du Colombier 		iprint("checkmmu cpu%d va=%lux l1 %p=%ux\n", m->machno, va, l1, *l1);
418*5c47fe09SDavid du Colombier 		return;
419*5c47fe09SDavid du Colombier 	}
420*5c47fe09SDavid du Colombier 	k = kmapp(PPN(*l1));
421*5c47fe09SDavid du Colombier 	pte = (PTE*)VA(k);
422*5c47fe09SDavid du Colombier 	pte += L2X(va);
423*5c47fe09SDavid du Colombier 	if(pa == ~0 || (pa != 0 && PPN(*pte) != pa))
424*5c47fe09SDavid du Colombier 		iprint("checkmmu va=%lux pa=%lux l1 %p=%ux pte %p=%ux\n", va, pa, l1, *l1, pte, *pte);
425*5c47fe09SDavid du Colombier 	kunmap(k);
4265d9de2d3SDavid du Colombier }
4275d9de2d3SDavid du Colombier 
428*5c47fe09SDavid du Colombier static KMap*
kmapp(ulong pa)429*5c47fe09SDavid du Colombier kmapp(ulong pa)
430*5c47fe09SDavid du Colombier {
431*5c47fe09SDavid du Colombier 	int s, i;
432*5c47fe09SDavid du Colombier 	uintptr va;
433*5c47fe09SDavid du Colombier 
434*5c47fe09SDavid du Colombier 	if(cankaddr(pa))
435*5c47fe09SDavid du Colombier 		return KADDR(pa);
436*5c47fe09SDavid du Colombier 	if(up == nil)
437*5c47fe09SDavid du Colombier 		panic("kmap without up %#p", getcallerpc(&pa));
438*5c47fe09SDavid du Colombier 	s = splhi();
439*5c47fe09SDavid du Colombier 	if(up->nkmap == NKMAPS)
440*5c47fe09SDavid du Colombier 		panic("kmap overflow %#p", getcallerpc(&pa));
441*5c47fe09SDavid du Colombier 	for(i = 0; i < NKMAPS; i++)
442*5c47fe09SDavid du Colombier 		if(up->kmaptab[i] == 0)
443*5c47fe09SDavid du Colombier 			break;
444*5c47fe09SDavid du Colombier 	if(i == NKMAPS)
445*5c47fe09SDavid du Colombier 		panic("can't happen");
446*5c47fe09SDavid du Colombier 	up->nkmap++;
447*5c47fe09SDavid du Colombier 	va = KMAPADDR + i*BY2PG;
448*5c47fe09SDavid du Colombier 	up->kmaptab[i] = pa | L2AP(Krw)|Small|L2ptedramattrs;
449*5c47fe09SDavid du Colombier 	m->kmapl2[i] = up->kmaptab[i];
450*5c47fe09SDavid du Colombier 	cachedwbtlb(&m->kmapl2[i], sizeof(PTE));
451*5c47fe09SDavid du Colombier 	mmuinvalidateaddr(va);
452*5c47fe09SDavid du Colombier 	splx(s);
453*5c47fe09SDavid du Colombier 	return (KMap*)va;
454*5c47fe09SDavid du Colombier }
455*5c47fe09SDavid du Colombier 
456*5c47fe09SDavid du Colombier KMap*
kmap(Page * p)457*5c47fe09SDavid du Colombier kmap(Page *p)
458*5c47fe09SDavid du Colombier {
459*5c47fe09SDavid du Colombier 	return kmapp(p->pa);
460*5c47fe09SDavid du Colombier }
461*5c47fe09SDavid du Colombier 
462*5c47fe09SDavid du Colombier void
kunmap(KMap * k)463*5c47fe09SDavid du Colombier kunmap(KMap *k)
464*5c47fe09SDavid du Colombier {
465*5c47fe09SDavid du Colombier 	int i;
466*5c47fe09SDavid du Colombier 	uintptr va;
467*5c47fe09SDavid du Colombier 
468*5c47fe09SDavid du Colombier 	coherence();
469*5c47fe09SDavid du Colombier 	va = (uintptr)k;
470*5c47fe09SDavid du Colombier 	if(L1X(va) != L1X(KMAPADDR))
471*5c47fe09SDavid du Colombier 		return;
472*5c47fe09SDavid du Colombier 	/* wasteful: only needed for text pages aliased within data cache */
473*5c47fe09SDavid du Colombier 	cachedwbse((void*)PPN(va), BY2PG);
474*5c47fe09SDavid du Colombier 	i = L2X(va);
475*5c47fe09SDavid du Colombier 	up->kmaptab[i] = 0;
476*5c47fe09SDavid du Colombier 	m->kmapl2[i] = 0;
477*5c47fe09SDavid du Colombier 	up->nkmap--;
478*5c47fe09SDavid du Colombier 	cachedwbtlb(&m->kmapl2[i], sizeof(PTE));
479*5c47fe09SDavid du Colombier 	mmuinvalidateaddr(va);
480*5c47fe09SDavid du Colombier }
481