summaryrefslogtreecommitdiff
path: root/sys/src/9/cycv/mmu.c
diff options
context:
space:
mode:
authoraiju <devnull@localhost>2020-01-08 02:35:01 +0000
committeraiju <devnull@localhost>2020-01-08 02:35:01 +0000
commit17ebe55031ae6945ad1f671b69267a672328e4b1 (patch)
treef3879436d00a88389d57d549a9b07171206c17c1 /sys/src/9/cycv/mmu.c
parent826c76f90df66a9b20a3cf279bfb47d4d27322af (diff)
add cycv kernel
Diffstat (limited to 'sys/src/9/cycv/mmu.c')
-rw-r--r--sys/src/9/cycv/mmu.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/sys/src/9/cycv/mmu.c b/sys/src/9/cycv/mmu.c
new file mode 100644
index 000000000..d7fef9540
--- /dev/null
+++ b/sys/src/9/cycv/mmu.c
@@ -0,0 +1,376 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+
+void
+mmuinit(void)
+{
+ m->l1.pa = ttbget();
+ m->l1.va = KADDR(m->l1.pa);
+ memset((uchar*)TMAPL2(m->machno), 0, TMAPL2SZ);
+ m->l1.va[L1X(TMAP)] = PADDR(TMAPL2(m->machno)) | L1PT;
+ incref(&m->l1);
+}
+
+void
+l1switch(L1 *p, int flush)
+{
+ assert(!islo());
+
+ ttbput(p->pa);
+ if(flush){
+ if(++m->asid == 0)
+ flushtlb();
+ setasid(m->asid);
+ }
+}
+
+static L1 *
+l1alloc(void)
+{
+ L1 *p;
+ int s;
+
+ s = splhi();
+ p = m->l1free;
+ if(p != nil){
+ m->l1free = p->next;
+ p->next = nil;
+ m->nfree--;
+ splx(s);
+ return p;
+ }
+ splx(s);
+ p = smalloc(sizeof(L1));
+ for(;;){
+ p->va = mallocalign(L1SZ, L1SZ, 0, 0);
+ if(p->va != nil)
+ break;
+ if(!waserror()){
+ resrcwait("no memory for L1 table");
+ poperror();
+ }
+ }
+ p->pa = PADDR(p->va);
+ memmove(p->va, m->l1.va, L1SZ);
+ return p;
+}
+
+static void
+l1free(L1 *l1)
+{
+ if(islo())
+ panic("l1free: islo");
+ if(m->nfree >= 40){
+ free(l1->va);
+ free(l1);
+ }else{
+ l1->next = m->l1free;
+ m->l1free = l1;
+ m->nfree++;
+ }
+}
+
+static void
+upallocl1(void)
+{
+ L1 *p;
+ int s;
+
+ if(up->l1 != nil)
+ return;
+ p = l1alloc();
+ s = splhi();
+ if(up->l1 != nil)
+ panic("upalloc1: up->l1 != nil");
+ up->l1 = p;
+ l1switch(p, 1);
+ splx(s);
+}
+
+static void
+l2free(Proc *proc)
+{
+ ulong *t;
+ Page *p, **l;
+
+ if(proc->l1 == nil || proc->mmuused == nil)
+ return;
+ l = &proc->mmuused;
+ for(p = *l; p != nil; p = p->next){
+ t = proc->l1->va + p->daddr;
+ *t++ = 0;
+ *t++ = 0;
+ *t++ = 0;
+ *t = 0;
+ l = &p->next;
+ }
+ proc->l1->va[L1X(TMAP)] = 0;
+ *l = proc->mmufree;
+ proc->mmufree = proc->mmuused;
+ proc->mmuused = 0;
+}
+
+void
+mmuswitch(Proc *p)
+{
+ if(p->newtlb){
+ p->newtlb = 0;
+ l2free(p);
+ }
+ if(p->l1 != nil)
+ l1switch(p->l1, 1);
+ else
+ l1switch(&m->l1, 1);
+}
+
+void
+putmmu(uintptr va, uintptr pa, Page *pg)
+{
+ Page *p;
+ ulong *e;
+ ulong *l2;
+ ulong old;
+ uintptr l2p;
+ int s;
+
+ if(up->l1 == nil)
+ upallocl1();
+ e = &up->l1->va[L1RX(va)];
+ if((*e & 3) == 0){
+ p = up->mmufree;
+ if(p != nil)
+ up->mmufree = p->next;
+ else
+ p = newpage(0, 0, 0);
+ p->daddr = L1RX(va);
+ p->next = up->mmuused;
+ up->mmuused = p;
+ s = splhi();
+ l2p = p->pa;
+ l2 = tmpmap(l2p);
+ memset(l2, 0, BY2PG);
+ coherence();
+ e[0] = p->pa | L1PT;
+ e[1] = e[0] + L2SZ;
+ e[2] = e[1] + L2SZ;
+ e[3] = e[2] + L2SZ;
+ coherence();
+ }else{
+ s = splhi();
+ l2p = *e & ~(BY2PG - 1);
+ l2 = tmpmap(l2p);
+ }
+ e = &l2[L2RX(va)];
+ old = *e;
+ *e = pa | L2VALID | L2USER | L2LOCAL;
+ tmpunmap(l2);
+ splx(s);
+ if((old & L2VALID) != 0)
+ flushpg((void *) va);
+ if(pg->txtflush & (1<<m->machno)){
+ cleandse((void *) va, (void *) (va + BY2PG));
+ invalise((void *) va, (void *) (va + BY2PG));
+ pg->txtflush &= ~(1<<m->machno);
+ }
+}
+
+void
+checkmmu(uintptr, uintptr)
+{
+}
+
+void
+flushmmu(void)
+{
+ int s;
+
+ s = splhi();
+ up->newtlb = 1;
+ mmuswitch(up);
+ splx(s);
+}
+
+void
+mmurelease(Proc *proc)
+{
+ Page *p, *n;
+
+ if(islo())
+ panic("mmurelease: islo");
+
+ l1switch(&m->l1, 0);
+ if(proc->kmaptable != nil){
+ if(proc->l1 == nil)
+ panic("mmurelease: no l1");
+ if(decref(proc->kmaptable) != 0)
+ panic("mmurelease: kmap ref %ld", proc->kmaptable->ref);
+ if(proc->nkmap)
+ panic("mmurelease: nkmap %d", proc->nkmap);
+ if(PPN(proc->l1->va[L1X(KMAP)]) != proc->kmaptable->pa)
+ panic("mmurelease: bad kmap l2 %#.8lux kmap %#.8lux", proc->l1->va[L1X(KMAP)], proc->kmaptable->pa);
+ proc->l1->va[L1X(KMAP)] = 0;
+ pagechainhead(proc->kmaptable);
+ proc->kmaptable = nil;
+ }
+ if(proc->l1 != nil){
+ l2free(proc);
+ l1free(proc->l1);
+ proc->l1 = nil;
+ }
+ for(p = proc->mmufree; p != nil; p = n){
+ n = p->next;
+ if(decref(p) != 0)
+ panic("mmurelease: p->ref %ld", p->ref);
+ pagechainhead(p);
+ }
+ if(proc->mmufree != nil)
+ pagechaindone();
+ proc->mmufree = nil;
+}
+
+uintptr
+paddr(void *v)
+{
+ if((uintptr)v >= PERIPH)
+ return (uintptr)v;
+ if((uintptr)v >= KZERO)
+ return (uintptr)v-KZERO;
+ panic("paddr: va=%#p pc=%#p", v, getcallerpc(&v));
+ return 0;
+}
+
+void *
+kaddr(uintptr u)
+{
+ if(u >= (uintptr)PERIPH)
+ return (void *)u;
+ if(u < (uintptr)-KZERO)
+ return (void *)(u + KZERO);
+ panic("kaddr: pa=%#p pc=%#p", u, getcallerpc(&u));
+ return nil;
+}
+
+uintptr
+cankaddr(uintptr u)
+{
+ if(u >= (uintptr)PERIPH)
+ return -u;
+ if(u < (uintptr)-KZERO)
+ return PERIPH-KZERO - u;
+ return 0;
+}
+
+KMap *
+kmap(Page *page)
+{
+ ulong *e, *v;
+ int i, s;
+
+ if(cankaddr(page->pa))
+ return (KMap*)KADDR(page->pa);
+ if(up == nil)
+ panic("kmap: up=0 pc=%#.8lux", getcallerpc(&page));
+ if(up->l1 == nil)
+ upallocl1();
+ if(up->nkmap < 0)
+ panic("kmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
+ up->nkmap++;
+ e = &up->l1->va[L1X(KMAP)];
+ if((*e & 3) == 0){
+ if(up->kmaptable != nil)
+ panic("kmaptable != nil");
+ up->kmaptable = newpage(0, 0, 0);
+ s = splhi();
+ v = tmpmap(up->kmaptable->pa);
+ memset(v, 0, BY2PG);
+ v[0] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
+ v[NKMAP] = up->kmaptable->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
+ tmpunmap(v);
+ splx(s);
+ *e = up->kmaptable->pa | L1PT;
+ coherence();
+ return (KMap *) KMAP;
+ }
+ if(up->kmaptable == nil)
+ panic("kmaptable == nil");
+ e = (ulong *) (KMAP + NKMAP * BY2PG);
+ for(i = 0; i < NKMAP; i++)
+ if((e[i] & 3) == 0){
+ e[i] = page->pa | L2KERRW | L2VALID | L2CACHED | L2LOCAL;
+ coherence();
+ return (KMap *) (KMAP + i * BY2PG);
+ }
+ panic("out of kmap");
+ return nil;
+}
+
+void
+kunmap(KMap *arg)
+{
+ uintptr va;
+ ulong *e;
+
+ va = (uintptr) arg;
+ if(va >= KZERO)
+ return;
+ if(up->l1 == nil || (up->l1->va[L1X(KMAP)] & 3) == 0)
+ panic("kunmap: no kmaps");
+ if(va < KMAP || va >= KMAP + NKMAP * BY2PG)
+ panic("kunmap: bad address %#.8lux pc=%#p", va, getcallerpc(&arg));
+ e = (ulong *) (KMAP + NKMAP * BY2PG) + L2X(va);
+ if((*e & 3) == 0)
+ panic("kunmap: not mapped %#.8lux pc=%#p", va, getcallerpc(&arg));
+ up->nkmap--;
+ if(up->nkmap < 0)
+ panic("kunmap %lud %s: nkmap=%d", up->pid, up->text, up->nkmap);
+ *e = 0;
+ coherence();
+ flushpg((void *) va);
+}
+
+void *
+tmpmap(ulong pa)
+{
+ ulong *u, *ub, *ue;
+
+ if(islo())
+ panic("tmpmap: islow %#p", getcallerpc(&pa));
+ if(cankaddr(pa))
+ return KADDR(pa);
+ ub = (ulong *) TMAPL2(m->machno);
+ ue = ub + NL2;
+ for(u = ub; u < ue; u++)
+ if((*u & 3) == 0){
+ *u = pa | L2VALID | L2CACHED | L2KERRW;
+
+ assert(m->l1.va[L1X(TMAP)] != 0);
+ if(up != nil && up->l1 != nil)
+ up->l1->va[L1X(TMAP)] = m->l1.va[L1X(TMAP)];
+
+ coherence();
+ return (void *) ((u - ub) * BY2PG + TMAP);
+ }
+ panic("tmpmap: full (pa=%#.8lux)", pa);
+ return nil;
+}
+
+void
+tmpunmap(void *v)
+{
+ ulong *u;
+
+ if(v >= (void*) KZERO)
+ return;
+ if(v < (void*)TMAP || v >= (void*)(TMAP + TMAPSZ))
+ panic("tmpunmap: invalid address (va=%#.8lux)", (uintptr) v);
+ u = (ulong *) TMAPL2(m->machno) + L2X(v);
+ if((*u & 3) == 0)
+ panic("tmpunmap: double unmap (va=%#.8lux)", (uintptr) v);
+ *u = 0;
+ coherence();
+ flushpg(v);
+}