summaryrefslogtreecommitdiff
path: root/os/cerf405/mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/cerf405/mmu.c')
-rw-r--r--os/cerf405/mmu.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/os/cerf405/mmu.c b/os/cerf405/mmu.c
new file mode 100644
index 00000000..ae0e0be9
--- /dev/null
+++ b/os/cerf405/mmu.c
@@ -0,0 +1,122 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+extern ulong tlbtab[], tlbtabe[];
+static int tlbx; /* index of next free entry in TLB */
+
+enum
+{
+ /* on-chip memory dcr */
+ Isarc= 0x018, /* instruction-side address range compare */
+ Iscntl= 0x019, /* instruction-side control register */
+ Isen= 1<<31, /* enable */
+ Dsarc= 0x01A, /* data-side address range compare register */
+ Dscntl= 0x01B, /* data-side control register */
+ Dsen= 1<<31, /* enable */
+ Dof= 1<<30, /* must be one (p. 5-7) */
+};
+
+void
+mmuinit(void)
+{
+ int i;
+
+ /*
+ * the l.s initial TLB settings do nearly all that is needed initially.
+ * clear invalid entries (just for clarity) and record the address
+ * of the first available
+ */
+ tlbx = -1;
+ for(i = 0; i < 64; i++)
+ if((tlbrehi(i) & TLBVALID) == 0){
+ if(tlbx < 0)
+ tlbx = i;
+ tlbwelo(i, 0);
+ tlbwehi(i, 0);
+ }
+
+ iprint("ccr0=%8.8lux\n", getccr0());
+
+ /*
+ * set OCM mapping, assuming:
+ * caches were invalidated earlier;
+ * and we aren't currently using it
+ * must also set a tlb entry that validates the virtual address but
+ * the translation is not used (see p. 5-2)
+ */
+ putdcr(Isarc, OCMZERO);
+ putdcr(Dsarc, OCMZERO);
+ putdcr(Iscntl, Isen);
+ putdcr(Iscntl, Dsen|Dof);
+ tlbwelo(tlbx, OCMZERO|TLBZONE(0)|TLBWR|TLBEX|TLBI);
+ tlbwehi(tlbx, OCMZERO|TLB4K|TLBVALID);
+ tlbx++;
+}
+
+int
+segflush(void *a, ulong n)
+{
+ /* flush dcache then invalidate icache */
+ dcflush(a, n);
+ icflush(a, n);
+ return 0;
+}
+
+/*
+ * return required size and alignment to map n bytes in a tlb entry
+ */
+ulong
+mmumapsize(ulong n)
+{
+ ulong size;
+ int i;
+
+ size = 1024;
+ for(i = 0; i < 8 && size < n; i++)
+ size <<= 2;
+ return size;
+}
+
+/*
+ * map a physical addresses at pa to va, with the given attributes.
+ * the virtual address must not be mapped already.
+ * if va is nil, map it at pa in virtual space.
+ */
+void*
+kmapphys(void *va, ulong pa, ulong nb, ulong attr, ulong le)
+{
+ int s, i;
+ ulong size;
+
+ if(va == nil)
+ va = (void*)pa; /* simplest is to use a 1-1 map */
+ size = 1024;
+ for(i = 0; i < 8 && size < nb; i++)
+ size <<= 2;
+ if(i >= 8)
+ return nil;
+ s = splhi();
+ tlbwelo(tlbx, pa | TLBZONE(0) | attr);
+ tlbwehi(tlbx, (ulong)va | (i<<7) | TLBVALID | le);
+ tlbx++;
+ splx(s);
+ return va;
+}
+
+/*
+ * return an uncached alias for the memory at a
+ */
+void*
+mmucacheinhib(void *a, ulong nb)
+{
+ ulong p;
+
+ if(a == nil)
+ return nil;
+ dcflush(a, nb);
+ p = PADDR(a);
+ return kmapphys((void*)(KSEG1|p), p, nb, TLBWR | TLBI | TLBG, 0);
+}