xref: /plan9/sys/src/9/bcm/mmu.c (revision 12009bff671a91993ae58f16dab833e809f4a6f3)
1*5d9de2d3SDavid du Colombier #include "u.h"
2*5d9de2d3SDavid du Colombier #include "../port/lib.h"
3*5d9de2d3SDavid du Colombier #include "mem.h"
4*5d9de2d3SDavid du Colombier #include "dat.h"
5*5d9de2d3SDavid du Colombier #include "fns.h"
6*5d9de2d3SDavid du Colombier 
7*5d9de2d3SDavid du Colombier #include "arm.h"
8*5d9de2d3SDavid du Colombier 
9*5d9de2d3SDavid du Colombier #define L1X(va)		FEXT((va), 20, 12)
10*5d9de2d3SDavid du Colombier #define L2X(va)		FEXT((va), 12, 8)
11*5d9de2d3SDavid du Colombier 
12*5d9de2d3SDavid du Colombier enum {
13*5d9de2d3SDavid du Colombier 	L1lo		= UZERO/MiB,		/* L1X(UZERO)? */
14*5d9de2d3SDavid du Colombier 	L1hi		= (USTKTOP+MiB-1)/MiB,	/* L1X(USTKTOP+MiB-1)? */
15*5d9de2d3SDavid du Colombier };
16*5d9de2d3SDavid du Colombier 
17*5d9de2d3SDavid du Colombier void
mmuinit(void)18*5d9de2d3SDavid du Colombier mmuinit(void)
19*5d9de2d3SDavid du Colombier {
20*5d9de2d3SDavid du Colombier 	PTE *l1, *l2;
21*5d9de2d3SDavid du Colombier 	uintptr pa, va;
22*5d9de2d3SDavid du Colombier 
23*5d9de2d3SDavid du Colombier 	l1 = (PTE*)PADDR(L1);
24*5d9de2d3SDavid du Colombier 	l2 = (PTE*)PADDR(L2);
25*5d9de2d3SDavid du Colombier 
26*5d9de2d3SDavid du Colombier 	/*
27*5d9de2d3SDavid du Colombier 	 * map all of ram at KZERO
28*5d9de2d3SDavid du Colombier 	 */
29*5d9de2d3SDavid du Colombier 	va = KZERO;
30*5d9de2d3SDavid du Colombier 	for(pa = PHYSDRAM; pa < PHYSDRAM+DRAMSIZE; pa += MiB){
31*5d9de2d3SDavid du Colombier 		l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section|Cached|Buffered;
32*5d9de2d3SDavid du Colombier 		va += MiB;
33*5d9de2d3SDavid du Colombier 	}
34*5d9de2d3SDavid du Colombier 
35*5d9de2d3SDavid du Colombier 	/*
36*5d9de2d3SDavid du Colombier 	 * identity map first MB of ram so mmu can be enabled
37*5d9de2d3SDavid du Colombier 	 */
38*5d9de2d3SDavid du Colombier 	l1[L1X(PHYSDRAM)] = PHYSDRAM|Dom0|L1AP(Krw)|Section|Cached|Buffered;
39*5d9de2d3SDavid du Colombier 
40*5d9de2d3SDavid du Colombier 	/*
41*5d9de2d3SDavid du Colombier 	 * map i/o registers
42*5d9de2d3SDavid du Colombier 	 */
43*5d9de2d3SDavid du Colombier 	va = VIRTIO;
44*5d9de2d3SDavid du Colombier 	for(pa = PHYSIO; pa < PHYSIO+IOSIZE; pa += MiB){
45*5d9de2d3SDavid du Colombier 		l1[L1X(va)] = pa|Dom0|L1AP(Krw)|Section;
46*5d9de2d3SDavid du Colombier 		va += MiB;
47*5d9de2d3SDavid du Colombier 	}
48*5d9de2d3SDavid du Colombier 
49*5d9de2d3SDavid du Colombier 	/*
50*5d9de2d3SDavid du Colombier 	 * double map exception vectors at top of virtual memory
51*5d9de2d3SDavid du Colombier 	 */
52*5d9de2d3SDavid du Colombier 	va = HVECTORS;
53*5d9de2d3SDavid du Colombier 	l1[L1X(va)] = (uintptr)l2|Dom0|Coarse;
54*5d9de2d3SDavid du Colombier 	l2[L2X(va)] = PHYSDRAM|L2AP(Krw)|Small;
55*5d9de2d3SDavid du Colombier }
56*5d9de2d3SDavid du Colombier 
57*5d9de2d3SDavid du Colombier void
mmuinit1(void)58*5d9de2d3SDavid du Colombier mmuinit1(void)
59*5d9de2d3SDavid du Colombier {
60*5d9de2d3SDavid du Colombier 	PTE *l1;
61*5d9de2d3SDavid du Colombier 
62*5d9de2d3SDavid du Colombier 	l1 = (PTE*)L1;
63*5d9de2d3SDavid du Colombier 	m->mmul1 = l1;
64*5d9de2d3SDavid du Colombier 
65*5d9de2d3SDavid du Colombier 	/*
66*5d9de2d3SDavid du Colombier 	 * undo identity map of first MB of ram
67*5d9de2d3SDavid du Colombier 	 */
68*5d9de2d3SDavid du Colombier 	l1[L1X(PHYSDRAM)] = 0;
69*5d9de2d3SDavid du Colombier 	cachedwbse(&l1[L1X(PHYSDRAM)], sizeof(PTE));
70*5d9de2d3SDavid du Colombier 	mmuinvalidate();
71*5d9de2d3SDavid du Colombier }
72*5d9de2d3SDavid du Colombier 
73*5d9de2d3SDavid du Colombier static void
mmul2empty(Proc * proc,int clear)74*5d9de2d3SDavid du Colombier mmul2empty(Proc* proc, int clear)
75*5d9de2d3SDavid du Colombier {
76*5d9de2d3SDavid du Colombier 	PTE *l1;
77*5d9de2d3SDavid du Colombier 	Page **l2, *page;
78*5d9de2d3SDavid du Colombier 
79*5d9de2d3SDavid du Colombier 	l1 = m->mmul1;
80*5d9de2d3SDavid du Colombier 	l2 = &proc->mmul2;
81*5d9de2d3SDavid du Colombier 	for(page = *l2; page != nil; page = page->next){
82*5d9de2d3SDavid du Colombier 		if(clear)
83*5d9de2d3SDavid du Colombier 			memset(UINT2PTR(page->va), 0, BY2PG);
84*5d9de2d3SDavid du Colombier 		l1[page->daddr] = Fault;
85*5d9de2d3SDavid du Colombier 		l2 = &page->next;
86*5d9de2d3SDavid du Colombier 	}
87*5d9de2d3SDavid du Colombier 	*l2 = proc->mmul2cache;
88*5d9de2d3SDavid du Colombier 	proc->mmul2cache = proc->mmul2;
89*5d9de2d3SDavid du Colombier 	proc->mmul2 = nil;
90*5d9de2d3SDavid du Colombier }
91*5d9de2d3SDavid du Colombier 
92*5d9de2d3SDavid du Colombier static void
mmul1empty(void)93*5d9de2d3SDavid du Colombier mmul1empty(void)
94*5d9de2d3SDavid du Colombier {
95*5d9de2d3SDavid du Colombier #ifdef notdef
96*5d9de2d3SDavid du Colombier /* there's a bug in here */
97*5d9de2d3SDavid du Colombier 	PTE *l1;
98*5d9de2d3SDavid du Colombier 
99*5d9de2d3SDavid du Colombier 	/* clean out any user mappings still in l1 */
100*5d9de2d3SDavid du Colombier 	if(m->mmul1lo > L1lo){
101*5d9de2d3SDavid du Colombier 		if(m->mmul1lo == 1)
102*5d9de2d3SDavid du Colombier 			m->mmul1[L1lo] = Fault;
103*5d9de2d3SDavid du Colombier 		else
104*5d9de2d3SDavid du Colombier 			memset(&m->mmul1[L1lo], 0, m->mmul1lo*sizeof(PTE));
105*5d9de2d3SDavid du Colombier 		m->mmul1lo = L1lo;
106*5d9de2d3SDavid du Colombier 	}
107*5d9de2d3SDavid du Colombier 	if(m->mmul1hi < L1hi){
108*5d9de2d3SDavid du Colombier 		l1 = &m->mmul1[m->mmul1hi];
109*5d9de2d3SDavid du Colombier 		if((L1hi - m->mmul1hi) == 1)
110*5d9de2d3SDavid du Colombier 			*l1 = Fault;
111*5d9de2d3SDavid du Colombier 		else
112*5d9de2d3SDavid du Colombier 			memset(l1, 0, (L1hi - m->mmul1hi)*sizeof(PTE));
113*5d9de2d3SDavid du Colombier 		m->mmul1hi = L1hi;
114*5d9de2d3SDavid du Colombier 	}
115*5d9de2d3SDavid du Colombier #else
116*5d9de2d3SDavid du Colombier 	memset(&m->mmul1[L1lo], 0, (L1hi - L1lo)*sizeof(PTE));
117*5d9de2d3SDavid du Colombier #endif /* notdef */
118*5d9de2d3SDavid du Colombier }
119*5d9de2d3SDavid du Colombier 
120*5d9de2d3SDavid du Colombier void
mmuswitch(Proc * proc)121*5d9de2d3SDavid du Colombier mmuswitch(Proc* proc)
122*5d9de2d3SDavid du Colombier {
123*5d9de2d3SDavid du Colombier 	int x;
124*5d9de2d3SDavid du Colombier 	PTE *l1;
125*5d9de2d3SDavid du Colombier 	Page *page;
126*5d9de2d3SDavid du Colombier 
127*5d9de2d3SDavid du Colombier 	/* do kprocs get here and if so, do they need to? */
128*5d9de2d3SDavid du Colombier 	if(m->mmupid == proc->pid && !proc->newtlb)
129*5d9de2d3SDavid du Colombier 		return;
130*5d9de2d3SDavid du Colombier 	m->mmupid = proc->pid;
131*5d9de2d3SDavid du Colombier 
132*5d9de2d3SDavid du Colombier 	/* write back dirty and invalidate l1 caches */
133*5d9de2d3SDavid du Colombier 	cacheuwbinv();
134*5d9de2d3SDavid du Colombier 
135*5d9de2d3SDavid du Colombier 	if(proc->newtlb){
136*5d9de2d3SDavid du Colombier 		mmul2empty(proc, 1);
137*5d9de2d3SDavid du Colombier 		proc->newtlb = 0;
138*5d9de2d3SDavid du Colombier 	}
139*5d9de2d3SDavid du Colombier 
140*5d9de2d3SDavid du Colombier 	mmul1empty();
141*5d9de2d3SDavid du Colombier 
142*5d9de2d3SDavid du Colombier 	/* move in new map */
143*5d9de2d3SDavid du Colombier 	l1 = m->mmul1;
144*5d9de2d3SDavid du Colombier 	for(page = proc->mmul2; page != nil; page = page->next){
145*5d9de2d3SDavid du Colombier 		x = page->daddr;
146*5d9de2d3SDavid du Colombier 		l1[x] = PPN(page->pa)|Dom0|Coarse;
147*5d9de2d3SDavid du Colombier 		/* know here that L1lo < x < L1hi */
148*5d9de2d3SDavid du Colombier 		if(x+1 - m->mmul1lo < m->mmul1hi - x)
149*5d9de2d3SDavid du Colombier 			m->mmul1lo = x+1;
150*5d9de2d3SDavid du Colombier 		else
151*5d9de2d3SDavid du Colombier 			m->mmul1hi = x;
152*5d9de2d3SDavid du Colombier 	}
153*5d9de2d3SDavid du Colombier 
154*5d9de2d3SDavid du Colombier 	/* make sure map is in memory */
155*5d9de2d3SDavid du Colombier 	/* could be smarter about how much? */
156*5d9de2d3SDavid du Colombier 	cachedwbse(&l1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
157*5d9de2d3SDavid du Colombier 
158*5d9de2d3SDavid du Colombier 	/* lose any possible stale tlb entries */
159*5d9de2d3SDavid du Colombier 	mmuinvalidate();
160*5d9de2d3SDavid du Colombier }
161*5d9de2d3SDavid du Colombier 
162*5d9de2d3SDavid du Colombier void
flushmmu(void)163*5d9de2d3SDavid du Colombier flushmmu(void)
164*5d9de2d3SDavid du Colombier {
165*5d9de2d3SDavid du Colombier 	int s;
166*5d9de2d3SDavid du Colombier 
167*5d9de2d3SDavid du Colombier 	s = splhi();
168*5d9de2d3SDavid du Colombier 	up->newtlb = 1;
169*5d9de2d3SDavid du Colombier 	mmuswitch(up);
170*5d9de2d3SDavid du Colombier 	splx(s);
171*5d9de2d3SDavid du Colombier }
172*5d9de2d3SDavid du Colombier 
173*5d9de2d3SDavid du Colombier void
mmurelease(Proc * proc)174*5d9de2d3SDavid du Colombier mmurelease(Proc* proc)
175*5d9de2d3SDavid du Colombier {
176*5d9de2d3SDavid du Colombier 	Page *page, *next;
177*5d9de2d3SDavid du Colombier 
178*5d9de2d3SDavid du Colombier 	/* write back dirty and invalidate l1 caches */
179*5d9de2d3SDavid du Colombier 	cacheuwbinv();
180*5d9de2d3SDavid du Colombier 
181*5d9de2d3SDavid du Colombier 	mmul2empty(proc, 0);
182*5d9de2d3SDavid du Colombier 	for(page = proc->mmul2cache; page != nil; page = next){
183*5d9de2d3SDavid du Colombier 		next = page->next;
184*5d9de2d3SDavid du Colombier 		if(--page->ref)
185*5d9de2d3SDavid du Colombier 			panic("mmurelease: page->ref %d", page->ref);
186*5d9de2d3SDavid du Colombier 		pagechainhead(page);
187*5d9de2d3SDavid du Colombier 	}
188*5d9de2d3SDavid du Colombier 	if(proc->mmul2cache && palloc.r.p)
189*5d9de2d3SDavid du Colombier 		wakeup(&palloc.r);
190*5d9de2d3SDavid du Colombier 	proc->mmul2cache = nil;
191*5d9de2d3SDavid du Colombier 
192*5d9de2d3SDavid du Colombier 	mmul1empty();
193*5d9de2d3SDavid du Colombier 
194*5d9de2d3SDavid du Colombier 	/* make sure map is in memory */
195*5d9de2d3SDavid du Colombier 	/* could be smarter about how much? */
196*5d9de2d3SDavid du Colombier 	cachedwbse(&m->mmul1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
197*5d9de2d3SDavid du Colombier 
198*5d9de2d3SDavid du Colombier 	/* lose any possible stale tlb entries */
199*5d9de2d3SDavid du Colombier 	mmuinvalidate();
200*5d9de2d3SDavid du Colombier }
201*5d9de2d3SDavid du Colombier 
202*5d9de2d3SDavid du Colombier void
putmmu(uintptr va,uintptr pa,Page * page)203*5d9de2d3SDavid du Colombier putmmu(uintptr va, uintptr pa, Page* page)
204*5d9de2d3SDavid du Colombier {
205*5d9de2d3SDavid du Colombier 	int x;
206*5d9de2d3SDavid du Colombier 	Page *pg;
207*5d9de2d3SDavid du Colombier 	PTE *l1, *pte;
208*5d9de2d3SDavid du Colombier 
209*5d9de2d3SDavid du Colombier 	x = L1X(va);
210*5d9de2d3SDavid du Colombier 	l1 = &m->mmul1[x];
211*5d9de2d3SDavid du Colombier 	if(*l1 == Fault){
212*5d9de2d3SDavid du Colombier 		/* wasteful - l2 pages only have 256 entries - fix */
213*5d9de2d3SDavid du Colombier 		if(up->mmul2cache == nil){
214*5d9de2d3SDavid du Colombier 			/* auxpg since we don't need much? memset if so */
215*5d9de2d3SDavid du Colombier 			pg = newpage(1, 0, 0);
216*5d9de2d3SDavid du Colombier 			pg->va = VA(kmap(pg));
217*5d9de2d3SDavid du Colombier 		}
218*5d9de2d3SDavid du Colombier 		else{
219*5d9de2d3SDavid du Colombier 			pg = up->mmul2cache;
220*5d9de2d3SDavid du Colombier 			up->mmul2cache = pg->next;
221*5d9de2d3SDavid du Colombier 			memset(UINT2PTR(pg->va), 0, BY2PG);
222*5d9de2d3SDavid du Colombier 		}
223*5d9de2d3SDavid du Colombier 		pg->daddr = x;
224*5d9de2d3SDavid du Colombier 		pg->next = up->mmul2;
225*5d9de2d3SDavid du Colombier 		up->mmul2 = pg;
226*5d9de2d3SDavid du Colombier 
227*5d9de2d3SDavid du Colombier 		/* force l2 page to memory */
228*5d9de2d3SDavid du Colombier 		cachedwbse((void *)pg->va, BY2PG);
229*5d9de2d3SDavid du Colombier 
230*5d9de2d3SDavid du Colombier 		*l1 = PPN(pg->pa)|Dom0|Coarse;
231*5d9de2d3SDavid du Colombier 		cachedwbse(l1, sizeof *l1);
232*5d9de2d3SDavid du Colombier 
233*5d9de2d3SDavid du Colombier 		if(x >= m->mmul1lo && x < m->mmul1hi){
234*5d9de2d3SDavid du Colombier 			if(x+1 - m->mmul1lo < m->mmul1hi - x)
235*5d9de2d3SDavid du Colombier 				m->mmul1lo = x+1;
236*5d9de2d3SDavid du Colombier 			else
237*5d9de2d3SDavid du Colombier 				m->mmul1hi = x;
238*5d9de2d3SDavid du Colombier 		}
239*5d9de2d3SDavid du Colombier 	}
240*5d9de2d3SDavid du Colombier 	pte = UINT2PTR(KADDR(PPN(*l1)));
241*5d9de2d3SDavid du Colombier 
242*5d9de2d3SDavid du Colombier 	/* protection bits are
243*5d9de2d3SDavid du Colombier 	 *	PTERONLY|PTEVALID;
244*5d9de2d3SDavid du Colombier 	 *	PTEWRITE|PTEVALID;
245*5d9de2d3SDavid du Colombier 	 *	PTEWRITE|PTEUNCACHED|PTEVALID;
246*5d9de2d3SDavid du Colombier 	 */
247*5d9de2d3SDavid du Colombier 	x = Small;
248*5d9de2d3SDavid du Colombier 	if(!(pa & PTEUNCACHED))
249*5d9de2d3SDavid du Colombier 		x |= Cached|Buffered;
250*5d9de2d3SDavid du Colombier 	if(pa & PTEWRITE)
251*5d9de2d3SDavid du Colombier 		x |= L2AP(Urw);
252*5d9de2d3SDavid du Colombier 	else
253*5d9de2d3SDavid du Colombier 		x |= L2AP(Uro);
254*5d9de2d3SDavid du Colombier 	pte[L2X(va)] = PPN(pa)|x;
255*5d9de2d3SDavid du Colombier 	cachedwbse(&pte[L2X(va)], sizeof pte[0]);
256*5d9de2d3SDavid du Colombier 
257*5d9de2d3SDavid du Colombier 	/* clear out the current entry */
258*5d9de2d3SDavid du Colombier 	mmuinvalidateaddr(PPN(va));
259*5d9de2d3SDavid du Colombier 
260*5d9de2d3SDavid du Colombier 	/*  write back dirty entries - we need this because the pio() in
261*5d9de2d3SDavid du Colombier 	 *  fault.c is writing via a different virt addr and won't clean
262*5d9de2d3SDavid du Colombier 	 *  its changes out of the dcache.  Page coloring doesn't work
263*5d9de2d3SDavid du Colombier 	 *  on this mmu because the virtual cache is set associative
264*5d9de2d3SDavid du Colombier 	 *  rather than direct mapped.
265*5d9de2d3SDavid du Colombier 	 */
266*5d9de2d3SDavid du Colombier 	cachedwbinv();
267*5d9de2d3SDavid du Colombier 	if(page->cachectl[0] == PG_TXTFLUSH){
268*5d9de2d3SDavid du Colombier 		/* pio() sets PG_TXTFLUSH whenever a text pg has been written */
269*5d9de2d3SDavid du Colombier 		cacheiinv();
270*5d9de2d3SDavid du Colombier 		page->cachectl[0] = PG_NOFLUSH;
271*5d9de2d3SDavid du Colombier 	}
272*5d9de2d3SDavid du Colombier 	checkmmu(va, PPN(pa));
273*5d9de2d3SDavid du Colombier }
274*5d9de2d3SDavid du Colombier 
275*5d9de2d3SDavid du Colombier /*
276*5d9de2d3SDavid du Colombier  * Return the number of bytes that can be accessed via KADDR(pa).
277*5d9de2d3SDavid du Colombier  * If pa is not a valid argument to KADDR, return 0.
278*5d9de2d3SDavid du Colombier  */
279*5d9de2d3SDavid du Colombier uintptr
cankaddr(uintptr pa)280*5d9de2d3SDavid du Colombier cankaddr(uintptr pa)
281*5d9de2d3SDavid du Colombier {
282*5d9de2d3SDavid du Colombier 	if(pa < PHYSDRAM + memsize)		/* assumes PHYSDRAM is 0 */
283*5d9de2d3SDavid du Colombier 		return PHYSDRAM + memsize - pa;
284*5d9de2d3SDavid du Colombier 	return 0;
285*5d9de2d3SDavid du Colombier }
286*5d9de2d3SDavid du Colombier 
287*5d9de2d3SDavid du Colombier uintptr
mmukmap(uintptr va,uintptr pa,usize size)288*5d9de2d3SDavid du Colombier mmukmap(uintptr va, uintptr pa, usize size)
289*5d9de2d3SDavid du Colombier {
290*5d9de2d3SDavid du Colombier 	int o;
291*5d9de2d3SDavid du Colombier 	usize n;
292*5d9de2d3SDavid du Colombier 	PTE *pte, *pte0;
293*5d9de2d3SDavid du Colombier 
294*5d9de2d3SDavid du Colombier 	assert((va & (MiB-1)) == 0);
295*5d9de2d3SDavid du Colombier 	o = pa & (MiB-1);
296*5d9de2d3SDavid du Colombier 	pa -= o;
297*5d9de2d3SDavid du Colombier 	size += o;
298*5d9de2d3SDavid du Colombier 	pte = pte0 = &m->mmul1[L1X(va)];
299*5d9de2d3SDavid du Colombier 	for(n = 0; n < size; n += MiB)
300*5d9de2d3SDavid du Colombier 		if(*pte++ != Fault)
301*5d9de2d3SDavid du Colombier 			return 0;
302*5d9de2d3SDavid du Colombier 	pte = pte0;
303*5d9de2d3SDavid du Colombier 	for(n = 0; n < size; n += MiB){
304*5d9de2d3SDavid du Colombier 		*pte++ = (pa+n)|Dom0|L1AP(Krw)|Section;
305*5d9de2d3SDavid du Colombier 		mmuinvalidateaddr(va+n);
306*5d9de2d3SDavid du Colombier 	}
307*5d9de2d3SDavid du Colombier 	cachedwbse(pte0, pte - pte0);
308*5d9de2d3SDavid du Colombier 	return va + o;
309*5d9de2d3SDavid du Colombier }
310*5d9de2d3SDavid du Colombier 
311*5d9de2d3SDavid du Colombier 
312*5d9de2d3SDavid du Colombier void
checkmmu(uintptr va,uintptr pa)313*5d9de2d3SDavid du Colombier checkmmu(uintptr va, uintptr pa)
314*5d9de2d3SDavid du Colombier {
315*5d9de2d3SDavid du Colombier 	USED(va);
316*5d9de2d3SDavid du Colombier 	USED(pa);
317*5d9de2d3SDavid du Colombier }
318*5d9de2d3SDavid du Colombier 
319