2 #include "../port/lib.h"
11 uintptr va, pa, pe, attr;
14 attr = PTEWRITE | PTEAF | PTEKERNEL | PTESH(SHARE_INNER);
15 pe = PHYSDRAM + soc.dramsize;
16 if(pe > (uintptr)-KZERO)
18 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
19 if(pe - pa < PGLSZ(1)){
20 l1[PTL1X(va, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
21 l1[PTL1X(pa, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
22 for(; pa < pe; pa += PGLSZ(0), va += PGLSZ(0))
23 l1[PTLX(va, 0)] = pa | PTEVALID | PTEPAGE | attr;
26 l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
27 l1[PTL1X(pa, 1)] = pa | PTEVALID | PTEBLOCK | attr;
29 pe = (uintptr)-KZERO; /* populate top levels for mmukmap() */
31 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2)){
32 l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
33 l1[PTL1X(pa, 2)] = (uintptr)&l1[L1TABLEX(pa, 1)] | PTEVALID | PTETABLE;
36 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3)){
37 l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
38 l1[PTL1X(pa, 3)] = (uintptr)&l1[L1TABLEX(pa, 2)] | PTEVALID | PTETABLE;
42 attr = PTEWRITE | PTEAF | PTEKERNEL | PTESH(SHARE_OUTER) | PTEDEVICE;
43 pe = soc.physio + IOSIZE;
44 for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1)){
45 if(pe - pa < PGLSZ(1)){
46 l1[PTL1X(va, 1)] = (uintptr)l1 | PTEVALID | PTETABLE;
47 for(; pa < pe; pa += PGLSZ(0), va += PGLSZ(0))
48 l1[PTLX(va, 0)] = pa | PTEVALID | PTEPAGE | attr;
51 l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
54 for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
55 l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
57 for(pa = soc.physio, va = VIRTIO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
58 l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
61 pe = soc.armlocal + MB;
62 for(pa = soc.armlocal, va = ARMLOCAL; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
63 l1[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | attr;
65 for(pa = soc.armlocal, va = ARMLOCAL; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
66 l1[PTL1X(va, 2)] = (uintptr)&l1[L1TABLEX(va, 1)] | PTEVALID | PTETABLE;
68 for(pa = soc.armlocal, va = ARMLOCAL; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
69 l1[PTL1X(va, 3)] = (uintptr)&l1[L1TABLEX(va, 2)] | PTEVALID | PTETABLE;
73 mmu0clear(uintptr *l1)
77 pe = PHYSDRAM + soc.dramsize;
78 if(pe > (uintptr)-KZERO)
80 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
81 if(PTL1X(pa, 1) != PTL1X(va, 1))
84 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
85 if(PTL1X(pa, 2) != PTL1X(va, 2))
88 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
89 if(PTL1X(pa, 3) != PTL1X(va, 3))
98 pe = PHYSDRAM + soc.dramsize;
99 if(pe > (uintptr)-KZERO)
100 pe = (uintptr)-KZERO;
101 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(1), va += PGLSZ(1))
102 l1[PTL1X(pa, 1)] = l1[PTL1X(va, 1)];
104 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(2), va += PGLSZ(2))
105 l1[PTL1X(pa, 2)] = l1[PTL1X(va, 2)];
107 for(pa = PHYSDRAM, va = KZERO; pa < pe; pa += PGLSZ(3), va += PGLSZ(3))
108 l1[PTL1X(pa, 3)] = l1[PTL1X(va, 3)];
109 setttbr(PADDR(&l1[L1TABLEX(0, PTLEVELS-1)]));
115 m->mmutop = mallocalign(L1TOPSIZE, BY2PG, 0, 0);
117 panic("mmu1init: no memory for mmutop");
118 memset(m->mmutop, 0, L1TOPSIZE);
125 if((uintptr)va >= KZERO)
126 return (uintptr)va-KZERO;
127 panic("paddr: va=%#p pc=%#p", va, getcallerpc(&va));
134 if(pa < (uintptr)-KZERO)
142 if(pa < (uintptr)-KZERO)
143 return (void*)(pa + KZERO);
144 panic("kaddr: pa=%#p pc=%#p", pa, getcallerpc(&pa));
165 mmukmap(uintptr va, uintptr pa, usize size)
167 uintptr a, pe, off, attr;
172 attr = va & PTEMA(7);
176 pe = (pa + size + (PGLSZ(1)-1)) & -PGLSZ(1);
178 ((uintptr*)L1)[PTL1X(va, 1)] = pa | PTEVALID | PTEBLOCK | PTEWRITE | PTEAF
179 | PTEKERNEL | PTESH(SHARE_OUTER) | attr;
188 mmuwalk(uintptr va, int level)
194 x = PTLX(va, PTLEVELS-1);
196 for(i = PTLEVELS-2; i >= level; i--){
199 if(pte & (0xFFFFULL<<48))
200 iprint("strange pte %#p va %#p\n", pte, va);
201 pte &= ~(0xFFFFULL<<48 | BY2PG-1);
207 up->mmufree = pg->next;
208 pg->va = va & -PGLSZ(i+1);
209 if((pg->next = up->mmuhead[i+1]) == nil)
210 up->mmutail[i+1] = pg;
211 up->mmuhead[i+1] = pg;
212 memset(KADDR(pg->pa), 0, BY2PG);
214 table[x] = pg->pa | PTEVALID | PTETABLE;
215 table = KADDR(pg->pa);
217 x = PTLX(va, (uintptr)i);
222 static Proc *asidlist[256];
238 a %= nelem(asidlist);
240 continue; // reserved
242 if(x == p || x == nil || (x->asid < 0 && x->mach == nil))
260 if(a > 0 && asidlist[a] == p)
269 * Prevent the following scenario:
270 * pX sleeps on cpuA, leaving its page tables in mmutop
271 * pX wakes up on cpuB, and exits, freeing its page tables
272 * pY on cpuB allocates a freed page table page and overwrites with data
273 * cpuA takes an interrupt, and is now running with bad page tables
274 * In theory this shouldn't hurt because only user address space tables
275 * are affected, and mmuswitch will clear mmutop before a user process is
276 * dispatched. But empirically it correlates with weird problems, eg
277 * resetting of the core clock at 0x4000001C which confuses local timers.
287 putmmu(uintptr va, uintptr pa, Page *pg)
293 while((pte = mmuwalk(va, 0)) == nil){
295 up->mmufree = newpage(0, nil, 0);
300 if((old & PTEVALID) != 0)
301 flushasidvall((uvlong)up->asid<<48 | va>>12);
303 flushasidva((uvlong)up->asid<<48 | va>>12);
304 *pte = pa | PTEPAGE | PTEUSER | PTENG | PTEAF | PTESH(SHARE_INNER);
305 if(pg->txtflush & (1UL<<m->machno)){
306 /* pio() sets PG_TXTFLUSH whenever a text pg has been written */
307 cachedwbinvse((void*)KADDR(pg->pa), BY2PG);
308 cacheiinvse((void*)va, BY2PG);
309 pg->txtflush &= ~(1UL<<m->machno);
321 for(i=1; i<PTLEVELS; i++){
322 if(p->mmuhead[i] == nil)
324 p->mmutail[i]->next = p->mmufree;
325 p->mmufree = p->mmuhead[i];
326 p->mmuhead[i] = p->mmutail[i] = nil;
336 for(va = UZERO; va < USTKTOP; va += PGLSZ(PTLEVELS-1))
337 m->mmutop[PTLX(va, PTLEVELS-1)] = 0;
340 setttbr(PADDR(m->mmutop));
349 for(t = p->mmuhead[PTLEVELS-1]; t != nil; t = t->next){
351 m->mmutop[PTLX(va, PTLEVELS-1)] = t->pa | PTEVALID | PTETABLE;
355 flushasid((uvlong)p->asid<<48);
357 setttbr((uvlong)p->asid<<48 | PADDR(m->mmutop));
368 if((t = p->mmufree) != nil){
370 p->mmufree = t->next;
372 panic("mmurelease: bad page ref");
374 } while((t = p->mmufree) != nil);
391 checkmmu(uintptr, uintptr)