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