xref: /plan9-contrib/sys/src/9/kw/mmu.c (revision b649930dd34d6bab2bb3fa27632347c57745aead)
1154abd99SDavid du Colombier #include "u.h"
2154abd99SDavid du Colombier #include "../port/lib.h"
3154abd99SDavid du Colombier #include "mem.h"
4154abd99SDavid du Colombier #include "dat.h"
5154abd99SDavid du Colombier #include "fns.h"
6a7a38e3eSDavid du Colombier #include "io.h"
7154abd99SDavid du Colombier 
8154abd99SDavid du Colombier #include "arm.h"
9154abd99SDavid du Colombier 
10154abd99SDavid du Colombier #define L1X(va)		FEXT((va), 20, 12)
11154abd99SDavid du Colombier #define L2X(va)		FEXT((va), 12, 8)
12154abd99SDavid du Colombier 
13154abd99SDavid du Colombier enum {
14154abd99SDavid du Colombier 	L1lo		= UZERO/MiB,		/* L1X(UZERO)? */
15154abd99SDavid du Colombier 	L1hi		= (USTKTOP+MiB-1)/MiB,	/* L1X(USTKTOP+MiB-1)? */
16154abd99SDavid du Colombier };
17154abd99SDavid du Colombier 
18154abd99SDavid du Colombier #define ISHOLE(pte)	((pte) == 0)
19154abd99SDavid du Colombier 
20154abd99SDavid du Colombier /* dump level 1 page table at virtual addr l1 */
21154abd99SDavid du Colombier void
mmudump(PTE * l1)22154abd99SDavid du Colombier mmudump(PTE *l1)
23154abd99SDavid du Colombier {
24154abd99SDavid du Colombier 	int i, type, rngtype;
25154abd99SDavid du Colombier 	uintptr pa, startva, startpa;
26154abd99SDavid du Colombier 	uvlong va, endva;
27154abd99SDavid du Colombier 	PTE pte;
28154abd99SDavid du Colombier 
29a7a38e3eSDavid du Colombier 	iprint("\n");
30154abd99SDavid du Colombier 	endva = startva = startpa = 0;
31154abd99SDavid du Colombier 	rngtype = 0;
32154abd99SDavid du Colombier 	/* dump first level of ptes */
33154abd99SDavid du Colombier 	for (va = i = 0; i < 4096; i++) {
34154abd99SDavid du Colombier 		pte = l1[i];
35154abd99SDavid du Colombier 		pa = pte & ~(MB - 1);
36154abd99SDavid du Colombier 		type = pte & (Fine|Section|Coarse);
37154abd99SDavid du Colombier 		if (ISHOLE(pte)) {
38154abd99SDavid du Colombier 			if (endva != 0) {	/* open range? close it */
39a7a38e3eSDavid du Colombier 				iprint("l1 maps va (%#lux-%#llux) -> pa %#lux type %#ux\n",
40154abd99SDavid du Colombier 					startva, endva-1, startpa, rngtype);
41154abd99SDavid du Colombier 				endva = 0;
42154abd99SDavid du Colombier 			}
43154abd99SDavid du Colombier 		} else {
44154abd99SDavid du Colombier 			if (endva == 0) {	/* no open range? start one */
45154abd99SDavid du Colombier 				startva = va;
46154abd99SDavid du Colombier 				startpa = pa;
47154abd99SDavid du Colombier 				rngtype = type;
48154abd99SDavid du Colombier 			}
49154abd99SDavid du Colombier 			endva = va + MB;	/* continue the open range */
50154abd99SDavid du Colombier 		}
51154abd99SDavid du Colombier 		va += MB;
52154abd99SDavid du Colombier 	}
53154abd99SDavid du Colombier 	if (endva != 0)			/* close an open range */
54a7a38e3eSDavid du Colombier 		iprint("l1 maps va (%#lux-%#llux) -> pa %#lux type %#ux\n",
55154abd99SDavid du Colombier 			startva, endva-1, startpa, rngtype);
56154abd99SDavid du Colombier }
57154abd99SDavid du Colombier 
58047f1f95SDavid du Colombier #ifdef CRYPTOSANDBOX
59047f1f95SDavid du Colombier extern uchar sandbox[64*1024+BY2PG];
60047f1f95SDavid du Colombier #endif
61047f1f95SDavid du Colombier 
6228620197SDavid du Colombier /* identity map `mbs' megabytes from phys */
63154abd99SDavid du Colombier void
mmuidmap(uintptr phys,int mbs)64897ae9c1SDavid du Colombier mmuidmap(uintptr phys, int mbs)
65154abd99SDavid du Colombier {
66897ae9c1SDavid du Colombier 	PTE *l1;
67897ae9c1SDavid du Colombier 	uintptr pa, fpa;
68154abd99SDavid du Colombier 
69154abd99SDavid du Colombier 	pa = ttbget();
70154abd99SDavid du Colombier 	l1 = KADDR(pa);
71154abd99SDavid du Colombier 
72897ae9c1SDavid du Colombier 	for (fpa = phys; mbs-- > 0; fpa += MiB)
73897ae9c1SDavid du Colombier 		l1[L1X(fpa)] = fpa|Dom0|L1AP(Krw)|Section;
74897ae9c1SDavid du Colombier 	coherence();
75897ae9c1SDavid du Colombier 
76897ae9c1SDavid du Colombier 	mmuinvalidate();
77897ae9c1SDavid du Colombier 	cacheuwbinv();
78897ae9c1SDavid du Colombier 	l2cacheuwbinv();
79897ae9c1SDavid du Colombier }
80897ae9c1SDavid du Colombier 
81897ae9c1SDavid du Colombier void
mmuinit(void)82897ae9c1SDavid du Colombier mmuinit(void)
83897ae9c1SDavid du Colombier {
84897ae9c1SDavid du Colombier 	PTE *l1, *l2;
85897ae9c1SDavid du Colombier 	uintptr pa, i;
86897ae9c1SDavid du Colombier 
87897ae9c1SDavid du Colombier 	pa = ttbget();
88897ae9c1SDavid du Colombier 	l1 = KADDR(pa);
89897ae9c1SDavid du Colombier 
9056713243SDavid du Colombier 	/*
9156713243SDavid du Colombier 	 * map high vectors to start of dram, but only 4K, not 1MB.
9256713243SDavid du Colombier 	 */
93154abd99SDavid du Colombier 	pa -= MACHSIZE+2*1024;
94154abd99SDavid du Colombier 	l2 = KADDR(pa);
95154abd99SDavid du Colombier 	memset(l2, 0, 1024);
96154abd99SDavid du Colombier 	/* vectors step on u-boot, but so do page tables */
97154abd99SDavid du Colombier 	l2[L2X(HVECTORS)] = PHYSDRAM|L2AP(Krw)|Small;
98154abd99SDavid du Colombier 	l1[L1X(HVECTORS)] = pa|Dom0|Coarse;	/* vectors -> ttb-machsize-2k */
99154abd99SDavid du Colombier 
10056713243SDavid du Colombier 	/* double map vectors at virtual 0 so reset will see them */
10156713243SDavid du Colombier 	pa -= 1024;
10256713243SDavid du Colombier 	l2 = KADDR(pa);
10356713243SDavid du Colombier 	memset(l2, 0, 1024);
10456713243SDavid du Colombier 	l2[L2X(0)] = PHYSDRAM|L2AP(Krw)|Small;
10556713243SDavid du Colombier 	l1[L1X(0)] = pa|Dom0|Coarse;
10656713243SDavid du Colombier 
107a7a38e3eSDavid du Colombier 	/*
108a7a38e3eSDavid du Colombier 	 * set up L2 ptes for PHYSIO (i/o registers), with smaller pages to
109a7a38e3eSDavid du Colombier 	 * enable user-mode access to a few devices.
110a7a38e3eSDavid du Colombier 	 */
111a7a38e3eSDavid du Colombier 	pa -= 1024;
112a7a38e3eSDavid du Colombier 	l2 = KADDR(pa);
113a7a38e3eSDavid du Colombier 	/* identity map by default */
114a7a38e3eSDavid du Colombier 	for (i = 0; i < 1024/4; i++)
115a7a38e3eSDavid du Colombier 		l2[L2X(VIRTIO + i*BY2PG)] = (PHYSIO + i*BY2PG)|L2AP(Krw)|Small;
1167365b686SDavid du Colombier 
117047f1f95SDavid du Colombier #ifdef CRYPTOSANDBOX
118047f1f95SDavid du Colombier 	/*
119047f1f95SDavid du Colombier 	 * rest is to let rae experiment with the crypto hardware
120047f1f95SDavid du Colombier 	 */
121047f1f95SDavid du Colombier 	/* access to cycle counter */
1227365b686SDavid du Colombier 	l2[L2X(soc.clock)] = soc.clock | L2AP(Urw)|Small;
123047f1f95SDavid du Colombier 	/* cesa registers; also visible in user space */
124047f1f95SDavid du Colombier 	for (i = 0; i < 16; i++)
1257365b686SDavid du Colombier 		l2[L2X(soc.cesa + i*BY2PG)] = (soc.cesa + i*BY2PG) |
126047f1f95SDavid du Colombier 			L2AP(Urw)|Small;
127047f1f95SDavid du Colombier 	/* crypto sram; remapped to unused space and visible in user space */
128047f1f95SDavid du Colombier 	l2[L2X(PHYSIO + 0xa0000)] = PHYSCESASRAM | L2AP(Urw)|Small;
129047f1f95SDavid du Colombier 	/* 64k of scratch dram */
130047f1f95SDavid du Colombier 	for (i = 0; i < 16; i++)
131047f1f95SDavid du Colombier 		l2[L2X(PHYSIO + 0xb0000 + i*BY2PG)] =
132047f1f95SDavid du Colombier 			(PADDR((uintptr)sandbox & ~(BY2PG-1)) + i*BY2PG) |
133047f1f95SDavid du Colombier 			 L2AP(Urw) | Small;
134047f1f95SDavid du Colombier #endif
1357365b686SDavid du Colombier 
136a7a38e3eSDavid du Colombier 	l1[L1X(VIRTIO)] = pa|Dom0|Coarse;
137a7a38e3eSDavid du Colombier 	coherence();
138a7a38e3eSDavid du Colombier 
139154abd99SDavid du Colombier 	mmuinvalidate();
140154abd99SDavid du Colombier 	cacheuwbinv();
141a7a38e3eSDavid du Colombier 	l2cacheuwbinv();
142154abd99SDavid du Colombier 
143154abd99SDavid du Colombier 	m->mmul1 = l1;
144a7a38e3eSDavid du Colombier //	mmudump(l1);			/* DEBUG.  too early to print */
145154abd99SDavid du Colombier }
146154abd99SDavid du Colombier 
147154abd99SDavid du Colombier static void
mmul2empty(Proc * proc,int clear)148154abd99SDavid du Colombier mmul2empty(Proc* proc, int clear)
149154abd99SDavid du Colombier {
150154abd99SDavid du Colombier 	PTE *l1;
151154abd99SDavid du Colombier 	Page **l2, *page;
152154abd99SDavid du Colombier 
153154abd99SDavid du Colombier 	l1 = m->mmul1;
154154abd99SDavid du Colombier 	l2 = &proc->mmul2;
155154abd99SDavid du Colombier 	for(page = *l2; page != nil; page = page->next){
156154abd99SDavid du Colombier 		if(clear)
157154abd99SDavid du Colombier 			memset(UINT2PTR(page->va), 0, BY2PG);
158154abd99SDavid du Colombier 		l1[page->daddr] = Fault;
159154abd99SDavid du Colombier 		l2 = &page->next;
160154abd99SDavid du Colombier 	}
161154abd99SDavid du Colombier 	*l2 = proc->mmul2cache;
162154abd99SDavid du Colombier 	proc->mmul2cache = proc->mmul2;
163154abd99SDavid du Colombier 	proc->mmul2 = nil;
164154abd99SDavid du Colombier }
165154abd99SDavid du Colombier 
166154abd99SDavid du Colombier static void
mmul1empty(void)167154abd99SDavid du Colombier mmul1empty(void)
168154abd99SDavid du Colombier {
16956713243SDavid du Colombier #ifdef notdef			/* there's a bug in here */
170154abd99SDavid du Colombier 	PTE *l1;
171154abd99SDavid du Colombier 
172154abd99SDavid du Colombier 	/* clean out any user mappings still in l1 */
173154abd99SDavid du Colombier 	if(m->mmul1lo > L1lo){
174154abd99SDavid du Colombier 		if(m->mmul1lo == 1)
175154abd99SDavid du Colombier 			m->mmul1[L1lo] = Fault;
176154abd99SDavid du Colombier 		else
177154abd99SDavid du Colombier 			memset(&m->mmul1[L1lo], 0, m->mmul1lo*sizeof(PTE));
178154abd99SDavid du Colombier 		m->mmul1lo = L1lo;
179154abd99SDavid du Colombier 	}
180154abd99SDavid du Colombier 	if(m->mmul1hi < L1hi){
181154abd99SDavid du Colombier 		l1 = &m->mmul1[m->mmul1hi];
182154abd99SDavid du Colombier 		if((L1hi - m->mmul1hi) == 1)
183154abd99SDavid du Colombier 			*l1 = Fault;
184154abd99SDavid du Colombier 		else
185154abd99SDavid du Colombier 			memset(l1, 0, (L1hi - m->mmul1hi)*sizeof(PTE));
186154abd99SDavid du Colombier 		m->mmul1hi = L1hi;
187154abd99SDavid du Colombier 	}
188154abd99SDavid du Colombier #else
189154abd99SDavid du Colombier 	memset(&m->mmul1[L1lo], 0, (L1hi - L1lo)*sizeof(PTE));
190154abd99SDavid du Colombier #endif /* notdef */
191154abd99SDavid du Colombier }
192154abd99SDavid du Colombier 
193154abd99SDavid du Colombier void
mmuswitch(Proc * proc)194154abd99SDavid du Colombier mmuswitch(Proc* proc)
195154abd99SDavid du Colombier {
196154abd99SDavid du Colombier 	int x;
197154abd99SDavid du Colombier 	PTE *l1;
198154abd99SDavid du Colombier 	Page *page;
199154abd99SDavid du Colombier 
200154abd99SDavid du Colombier 	/* do kprocs get here and if so, do they need to? */
201154abd99SDavid du Colombier 	if(m->mmupid == proc->pid && !proc->newtlb)
202154abd99SDavid du Colombier 		return;
203154abd99SDavid du Colombier 	m->mmupid = proc->pid;
204154abd99SDavid du Colombier 
205a7a38e3eSDavid du Colombier 	/* write back dirty and invalidate l1 caches */
206154abd99SDavid du Colombier 	cacheuwbinv();
207154abd99SDavid du Colombier 
208154abd99SDavid du Colombier 	if(proc->newtlb){
209154abd99SDavid du Colombier 		mmul2empty(proc, 1);
210154abd99SDavid du Colombier 		proc->newtlb = 0;
211154abd99SDavid du Colombier 	}
212154abd99SDavid du Colombier 
213154abd99SDavid du Colombier 	mmul1empty();
214154abd99SDavid du Colombier 
215154abd99SDavid du Colombier 	/* move in new map */
216154abd99SDavid du Colombier 	l1 = m->mmul1;
217154abd99SDavid du Colombier 	for(page = proc->mmul2; page != nil; page = page->next){
218154abd99SDavid du Colombier 		x = page->daddr;
219154abd99SDavid du Colombier 		l1[x] = PPN(page->pa)|Dom0|Coarse;
220154abd99SDavid du Colombier 		/* know here that L1lo < x < L1hi */
221154abd99SDavid du Colombier 		if(x+1 - m->mmul1lo < m->mmul1hi - x)
222154abd99SDavid du Colombier 			m->mmul1lo = x+1;
223154abd99SDavid du Colombier 		else
224154abd99SDavid du Colombier 			m->mmul1hi = x;
225154abd99SDavid du Colombier 	}
226154abd99SDavid du Colombier 
227154abd99SDavid du Colombier 	/* make sure map is in memory */
228154abd99SDavid du Colombier 	/* could be smarter about how much? */
229154abd99SDavid du Colombier 	cachedwbse(&l1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
230a7a38e3eSDavid du Colombier 	l2cacheuwbse(&l1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
231154abd99SDavid du Colombier 
232154abd99SDavid du Colombier 	/* lose any possible stale tlb entries */
233154abd99SDavid du Colombier 	mmuinvalidate();
234154abd99SDavid du Colombier 
235154abd99SDavid du Colombier //	mmudump(l1);
236154abd99SDavid du Colombier 	//print("mmuswitch l1lo %d l1hi %d %d\n",
237154abd99SDavid du Colombier 	//	m->mmul1lo, m->mmul1hi, proc->kp);
238a7a38e3eSDavid du Colombier //print("\n");
239154abd99SDavid du Colombier }
240154abd99SDavid du Colombier 
241154abd99SDavid du Colombier void
flushmmu(void)242154abd99SDavid du Colombier flushmmu(void)
243154abd99SDavid du Colombier {
244154abd99SDavid du Colombier 	int s;
245154abd99SDavid du Colombier 
246154abd99SDavid du Colombier 	s = splhi();
247154abd99SDavid du Colombier 	up->newtlb = 1;
248154abd99SDavid du Colombier 	mmuswitch(up);
249154abd99SDavid du Colombier 	splx(s);
250154abd99SDavid du Colombier }
251154abd99SDavid du Colombier 
252154abd99SDavid du Colombier void
mmurelease(Proc * proc)253154abd99SDavid du Colombier mmurelease(Proc* proc)
254154abd99SDavid du Colombier {
255154abd99SDavid du Colombier 	Page *page, *next;
256154abd99SDavid du Colombier 
257a7a38e3eSDavid du Colombier 	/* write back dirty and invalidate l1 caches */
258154abd99SDavid du Colombier 	cacheuwbinv();
259154abd99SDavid du Colombier 
260154abd99SDavid du Colombier 	mmul2empty(proc, 0);
261154abd99SDavid du Colombier 	for(page = proc->mmul2cache; page != nil; page = next){
262154abd99SDavid du Colombier 		next = page->next;
263154abd99SDavid du Colombier 		if(--page->ref)
264154abd99SDavid du Colombier 			panic("mmurelease: page->ref %d", page->ref);
265154abd99SDavid du Colombier 		pagechainhead(page);
266154abd99SDavid du Colombier 	}
267154abd99SDavid du Colombier 	if(proc->mmul2cache && palloc.r.p)
268154abd99SDavid du Colombier 		wakeup(&palloc.r);
269154abd99SDavid du Colombier 	proc->mmul2cache = nil;
270154abd99SDavid du Colombier 
271154abd99SDavid du Colombier 	mmul1empty();
272154abd99SDavid du Colombier 
273154abd99SDavid du Colombier 	/* make sure map is in memory */
274154abd99SDavid du Colombier 	/* could be smarter about how much? */
275154abd99SDavid du Colombier 	cachedwbse(&m->mmul1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
276a7a38e3eSDavid du Colombier 	l2cacheuwbse(&m->mmul1[L1X(UZERO)], (L1hi - L1lo)*sizeof(PTE));
277154abd99SDavid du Colombier 
278154abd99SDavid du Colombier 	/* lose any possible stale tlb entries */
279154abd99SDavid du Colombier 	mmuinvalidate();
280154abd99SDavid du Colombier }
281154abd99SDavid du Colombier 
282154abd99SDavid du Colombier void
putmmu(uintptr va,uintptr pa,Page * page)283154abd99SDavid du Colombier putmmu(uintptr va, uintptr pa, Page* page)
284154abd99SDavid du Colombier {
285154abd99SDavid du Colombier 	int x;
286154abd99SDavid du Colombier 	Page *pg;
287154abd99SDavid du Colombier 	PTE *l1, *pte;
288154abd99SDavid du Colombier 
289154abd99SDavid du Colombier 	x = L1X(va);
290154abd99SDavid du Colombier 	l1 = &m->mmul1[x];
291154abd99SDavid du Colombier 	//print("putmmu(%#p, %#p, %#p) ", va, pa, page->pa);
292154abd99SDavid du Colombier 	//print("mmul1 %#p l1 %#p *l1 %#ux x %d pid %d\n",
293154abd99SDavid du Colombier 	//	m->mmul1, l1, *l1, x, up->pid);
294154abd99SDavid du Colombier 	if(*l1 == Fault){
295154abd99SDavid du Colombier 		/* wasteful - l2 pages only have 256 entries - fix */
296154abd99SDavid du Colombier 		if(up->mmul2cache == nil){
297154abd99SDavid du Colombier 			/* auxpg since we don't need much? memset if so */
298154abd99SDavid du Colombier 			pg = newpage(1, 0, 0);
299154abd99SDavid du Colombier 			pg->va = VA(kmap(pg));
300154abd99SDavid du Colombier 		}
301154abd99SDavid du Colombier 		else{
302154abd99SDavid du Colombier 			pg = up->mmul2cache;
303154abd99SDavid du Colombier 			up->mmul2cache = pg->next;
304154abd99SDavid du Colombier 			memset(UINT2PTR(pg->va), 0, BY2PG);
305154abd99SDavid du Colombier 		}
306154abd99SDavid du Colombier 		pg->daddr = x;
307154abd99SDavid du Colombier 		pg->next = up->mmul2;
308154abd99SDavid du Colombier 		up->mmul2 = pg;
309154abd99SDavid du Colombier 
310a7a38e3eSDavid du Colombier 		/* force l2 page to memory */
311a7a38e3eSDavid du Colombier 		cachedwbse((void *)pg->va, BY2PG);
312a7a38e3eSDavid du Colombier 		l2cacheuwbse((void *)pg->va, BY2PG);
313a7a38e3eSDavid du Colombier 
314154abd99SDavid du Colombier 		*l1 = PPN(pg->pa)|Dom0|Coarse;
315a7a38e3eSDavid du Colombier 		cachedwbse(l1, sizeof *l1);
316a7a38e3eSDavid du Colombier 		l2cacheuwbse(l1, sizeof *l1);
317154abd99SDavid du Colombier 		//print("l1 %#p *l1 %#ux x %d pid %d\n", l1, *l1, x, up->pid);
318154abd99SDavid du Colombier 
319154abd99SDavid du Colombier 		if(x >= m->mmul1lo && x < m->mmul1hi){
320154abd99SDavid du Colombier 			if(x+1 - m->mmul1lo < m->mmul1hi - x)
321154abd99SDavid du Colombier 				m->mmul1lo = x+1;
322154abd99SDavid du Colombier 			else
323154abd99SDavid du Colombier 				m->mmul1hi = x;
324154abd99SDavid du Colombier 		}
325154abd99SDavid du Colombier 	}
326154abd99SDavid du Colombier 	pte = UINT2PTR(KADDR(PPN(*l1)));
327154abd99SDavid du Colombier 	//print("pte %#p index %ld %#ux\n", pte, L2X(va), *(pte+L2X(va)));
328154abd99SDavid du Colombier 
329154abd99SDavid du Colombier 	/* protection bits are
330154abd99SDavid du Colombier 	 *	PTERONLY|PTEVALID;
331154abd99SDavid du Colombier 	 *	PTEWRITE|PTEVALID;
332154abd99SDavid du Colombier 	 *	PTEWRITE|PTEUNCACHED|PTEVALID;
333154abd99SDavid du Colombier 	 */
334154abd99SDavid du Colombier 	x = Small;
335154abd99SDavid du Colombier 	if(!(pa & PTEUNCACHED))
336154abd99SDavid du Colombier 		x |= Cached|Buffered;
337154abd99SDavid du Colombier 	if(pa & PTEWRITE)
338154abd99SDavid du Colombier 		x |= L2AP(Urw);
339154abd99SDavid du Colombier 	else
340154abd99SDavid du Colombier 		x |= L2AP(Uro);
341154abd99SDavid du Colombier 	pte[L2X(va)] = PPN(pa)|x;
342a7a38e3eSDavid du Colombier 	cachedwbse(&pte[L2X(va)], sizeof pte[0]);
343a7a38e3eSDavid du Colombier 	l2cacheuwbse(&pte[L2X(va)], sizeof pte[0]);
344154abd99SDavid du Colombier 
345154abd99SDavid du Colombier 	/* clear out the current entry */
346154abd99SDavid du Colombier 	mmuinvalidateaddr(PPN(va));
347154abd99SDavid du Colombier 
348a7a38e3eSDavid du Colombier 	/*
349a7a38e3eSDavid du Colombier 	 *  write back dirty entries - we need this because pio() in
350154abd99SDavid du Colombier 	 *  fault.c is writing via a different virt addr and won't clean
351154abd99SDavid du Colombier 	 *  its changes out of the dcache.  Page coloring doesn't work
352a7a38e3eSDavid du Colombier 	 *  on this mmu because the l1 virtual cache is set associative
353154abd99SDavid du Colombier 	 *  rather than direct mapped.
354154abd99SDavid du Colombier 	 */
355154abd99SDavid du Colombier 	cachedwbinv();
356154abd99SDavid du Colombier 	if(page->cachectl[0] == PG_TXTFLUSH){
357154abd99SDavid du Colombier 		/* pio() sets PG_TXTFLUSH whenever a text pg has been written */
358154abd99SDavid du Colombier 		cacheiinv();
359154abd99SDavid du Colombier 		page->cachectl[0] = PG_NOFLUSH;
360154abd99SDavid du Colombier 	}
361154abd99SDavid du Colombier 	//print("putmmu %#p %#p %#p\n", va, pa, PPN(pa)|x);
362154abd99SDavid du Colombier }
363154abd99SDavid du Colombier 
364154abd99SDavid du Colombier void*
mmuuncache(void * v,usize size)365154abd99SDavid du Colombier mmuuncache(void* v, usize size)
366154abd99SDavid du Colombier {
367154abd99SDavid du Colombier 	int x;
368154abd99SDavid du Colombier 	PTE *pte;
369154abd99SDavid du Colombier 	uintptr va;
370154abd99SDavid du Colombier 
371154abd99SDavid du Colombier 	/*
372154abd99SDavid du Colombier 	 * Simple helper for ucalloc().
373154abd99SDavid du Colombier 	 * Uncache a Section, must already be
374154abd99SDavid du Colombier 	 * valid in the MMU.
375154abd99SDavid du Colombier 	 */
376154abd99SDavid du Colombier 	va = PTR2UINT(v);
377154abd99SDavid du Colombier 	assert(!(va & (1*MiB-1)) && size == 1*MiB);
378154abd99SDavid du Colombier 
379154abd99SDavid du Colombier 	x = L1X(va);
380154abd99SDavid du Colombier 	pte = &m->mmul1[x];
381154abd99SDavid du Colombier 	if((*pte & (Fine|Section|Coarse)) != Section)
382154abd99SDavid du Colombier 		return nil;
383154abd99SDavid du Colombier 	*pte &= ~(Cached|Buffered);
384154abd99SDavid du Colombier 	mmuinvalidateaddr(va);
385a7a38e3eSDavid du Colombier 	cachedwbse(pte, 4);
386a7a38e3eSDavid du Colombier 	l2cacheuwbse(pte, 4);
387154abd99SDavid du Colombier 
388154abd99SDavid du Colombier 	return v;
389154abd99SDavid du Colombier }
390154abd99SDavid du Colombier 
391154abd99SDavid du Colombier uintptr
mmukmap(uintptr va,uintptr pa,usize size)392154abd99SDavid du Colombier mmukmap(uintptr va, uintptr pa, usize size)
393154abd99SDavid du Colombier {
394154abd99SDavid du Colombier 	int x;
395154abd99SDavid du Colombier 	PTE *pte;
396154abd99SDavid du Colombier 
397154abd99SDavid du Colombier 	/*
398154abd99SDavid du Colombier 	 * Stub.
399154abd99SDavid du Colombier 	 */
400154abd99SDavid du Colombier 	assert(!(va & (1*MiB-1)) && !(pa & (1*MiB-1)) && size == 1*MiB);
401154abd99SDavid du Colombier 
402154abd99SDavid du Colombier 	x = L1X(va);
403154abd99SDavid du Colombier 	pte = &m->mmul1[x];
404154abd99SDavid du Colombier 	if(*pte != Fault)
405154abd99SDavid du Colombier 		return 0;
406154abd99SDavid du Colombier 	*pte = pa|Dom0|L1AP(Krw)|Section;
407154abd99SDavid du Colombier 	mmuinvalidateaddr(va);
408a7a38e3eSDavid du Colombier 	cachedwbse(pte, 4);
409a7a38e3eSDavid du Colombier 	l2cacheuwbse(pte, 4);
410154abd99SDavid du Colombier 
411154abd99SDavid du Colombier 	return va;
412154abd99SDavid du Colombier }
413154abd99SDavid du Colombier 
414154abd99SDavid du Colombier uintptr
mmukunmap(uintptr va,uintptr pa,usize size)415154abd99SDavid du Colombier mmukunmap(uintptr va, uintptr pa, usize size)
416154abd99SDavid du Colombier {
417154abd99SDavid du Colombier 	int x;
418154abd99SDavid du Colombier 	PTE *pte;
419154abd99SDavid du Colombier 
420154abd99SDavid du Colombier 	/*
421154abd99SDavid du Colombier 	 * Stub.
422154abd99SDavid du Colombier 	 */
423154abd99SDavid du Colombier 	assert(!(va & (1*MiB-1)) && !(pa & (1*MiB-1)) && size == 1*MiB);
424154abd99SDavid du Colombier 
425154abd99SDavid du Colombier 	x = L1X(va);
426154abd99SDavid du Colombier 	pte = &m->mmul1[x];
427154abd99SDavid du Colombier 	if(*pte != (pa|Dom0|L1AP(Krw)|Section))
428154abd99SDavid du Colombier 		return 0;
429154abd99SDavid du Colombier 	*pte = Fault;
430154abd99SDavid du Colombier 	mmuinvalidateaddr(va);
431a7a38e3eSDavid du Colombier 	cachedwbse(pte, 4);
432a7a38e3eSDavid du Colombier 	l2cacheuwbse(pte, 4);
433154abd99SDavid du Colombier 
434154abd99SDavid du Colombier 	return va;
435154abd99SDavid du Colombier }
436154abd99SDavid du Colombier 
437154abd99SDavid du Colombier /*
438154abd99SDavid du Colombier  * Return the number of bytes that can be accessed via KADDR(pa).
439154abd99SDavid du Colombier  * If pa is not a valid argument to KADDR, return 0.
440154abd99SDavid du Colombier  */
441154abd99SDavid du Colombier uintptr
cankaddr(uintptr pa)442154abd99SDavid du Colombier cankaddr(uintptr pa)
443154abd99SDavid du Colombier {
444*b649930dSDavid du Colombier 	if(pa < PHYSDRAM + memsize)		/* assumes PHYSDRAM is 0 */
445*b649930dSDavid du Colombier 		return PHYSDRAM + memsize - pa;
446154abd99SDavid du Colombier 	return 0;
447154abd99SDavid du Colombier }
448154abd99SDavid du Colombier 
449154abd99SDavid du Colombier /* from 386 */
450154abd99SDavid du Colombier void*
vmap(uintptr pa,usize size)451154abd99SDavid du Colombier vmap(uintptr pa, usize size)
452154abd99SDavid du Colombier {
453154abd99SDavid du Colombier 	uintptr pae, va;
454154abd99SDavid du Colombier 	usize o, osize;
455154abd99SDavid du Colombier 
456154abd99SDavid du Colombier 	/*
457154abd99SDavid du Colombier 	 * XXX - replace with new vm stuff.
458154abd99SDavid du Colombier 	 * Crock after crock - the first 4MB is mapped with 2MB pages
459154abd99SDavid du Colombier 	 * so catch that and return good values because the current mmukmap
460154abd99SDavid du Colombier 	 * will fail.
461154abd99SDavid du Colombier 	 */
462154abd99SDavid du Colombier 	if(pa+size < 4*MiB)
463154abd99SDavid du Colombier 		return UINT2PTR(kseg0|pa);
464154abd99SDavid du Colombier 
465154abd99SDavid du Colombier 	osize = size;
466154abd99SDavid du Colombier 	o = pa & (BY2PG-1);
467154abd99SDavid du Colombier 	pa -= o;
468154abd99SDavid du Colombier 	size += o;
469b1c4f505SDavid du Colombier 	size = ROUNDUP(size, BY2PG);
470154abd99SDavid du Colombier 
471154abd99SDavid du Colombier 	va = kseg0|pa;
472154abd99SDavid du Colombier 	pae = mmukmap(va, pa, size);
473154abd99SDavid du Colombier 	if(pae == 0 || pae-size != pa)
474154abd99SDavid du Colombier 		panic("vmap(%#p, %ld) called from %#p: mmukmap fails %#p",
475154abd99SDavid du Colombier 			pa+o, osize, getcallerpc(&pa), pae);
476154abd99SDavid du Colombier 
477154abd99SDavid du Colombier 	return UINT2PTR(va+o);
478154abd99SDavid du Colombier }
479154abd99SDavid du Colombier 
480154abd99SDavid du Colombier /* from 386 */
481154abd99SDavid du Colombier void
vunmap(void * v,usize size)482154abd99SDavid du Colombier vunmap(void* v, usize size)
483154abd99SDavid du Colombier {
484154abd99SDavid du Colombier 	/*
485154abd99SDavid du Colombier 	 * XXX - replace with new vm stuff.
486154abd99SDavid du Colombier 	 * Can't do this until do real vmap for all space that
487154abd99SDavid du Colombier 	 * might be used, e.g. stuff below 1MB which is currently
488154abd99SDavid du Colombier 	 * mapped automagically at boot but that isn't used (or
489154abd99SDavid du Colombier 	 * at least shouldn't be used) by the kernel.
490154abd99SDavid du Colombier 	upafree(PADDR(v), size);
491154abd99SDavid du Colombier 	 */
492154abd99SDavid du Colombier 	USED(v, size);
493154abd99SDavid du Colombier }
494154abd99SDavid du Colombier 
495154abd99SDavid du Colombier /*
496154abd99SDavid du Colombier  * Notes.
497154abd99SDavid du Colombier  * Everything is in domain 0;
498154abd99SDavid du Colombier  * domain 0 access bits in the DAC register are set
499154abd99SDavid du Colombier  * to Client, which means access is controlled by the
500154abd99SDavid du Colombier  * permission values set in the PTE.
501154abd99SDavid du Colombier  *
502154abd99SDavid du Colombier  * L1 access control for the kernel is set to 1 (RW,
503154abd99SDavid du Colombier  * no user mode access);
504154abd99SDavid du Colombier  * L2 access control for the kernel is set to 1 (ditto)
505154abd99SDavid du Colombier  * for all 4 AP sets;
506154abd99SDavid du Colombier  * L1 user mode access is never set;
507154abd99SDavid du Colombier  * L2 access control for user mode is set to either
508154abd99SDavid du Colombier  * 2 (RO) or 3 (RW) depending on whether text or data,
509154abd99SDavid du Colombier  * for all 4 AP sets.
510154abd99SDavid du Colombier  * (To get kernel RO set AP to 0 and S bit in control
511154abd99SDavid du Colombier  * register c1).
512154abd99SDavid du Colombier  * Coarse L1 page-tables are used. They have 256 entries
513154abd99SDavid du Colombier  * and so consume 1024 bytes per table.
514154abd99SDavid du Colombier  * Small L2 page-tables are used. They have 1024 entries
515154abd99SDavid du Colombier  * and so consume 4096 bytes per table.
516154abd99SDavid du Colombier  *
517154abd99SDavid du Colombier  * 4KiB. That's the size of 1) a page, 2) the
518154abd99SDavid du Colombier  * size allocated for an L2 page-table page (note only 1KiB
519154abd99SDavid du Colombier  * is needed per L2 page - to be dealt with later) and
520154abd99SDavid du Colombier  * 3) the size of the area in L1 needed to hold the PTEs
521154abd99SDavid du Colombier  * to map 1GiB of user space (0 -> 0x3fffffff, 1024 entries).
522154abd99SDavid du Colombier  */
523