summaryrefslogtreecommitdiff
path: root/os/sa1110/mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/sa1110/mmu.c')
-rw-r--r--os/sa1110/mmu.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/os/sa1110/mmu.c b/os/sa1110/mmu.c
new file mode 100644
index 00000000..1dab239a
--- /dev/null
+++ b/os/sa1110/mmu.c
@@ -0,0 +1,140 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+/*
+ * return physical address corresponding to a given virtual address,
+ * or 0 if there is no such address
+ */
+ulong
+va2pa(void *v)
+{
+ int idx;
+ ulong pte, ste, *ttb;
+
+ idx = MmuL1x((ulong)v);
+ ttb = (ulong*)KTTB;
+ ste = ttb[idx];
+ switch(ste & MmuL1type) {
+ case MmuL1section:
+ return MmuSBA(ste)|((ulong)v & 0x000fffff);
+ case MmuL1page:
+ pte = ((ulong *)MmuPTBA(ste))[MmuL2x((ulong)v)];
+ switch(pte & 3) {
+ case MmuL2large:
+ return (pte & 0xffff0000)|((ulong)v & 0x0000ffff);
+ case MmuL2small:
+ return (pte & 0xfffff000)|((ulong)v & 0x00000fff);
+ }
+ }
+ return 0;
+}
+
+enum {
+ SectionPages = MmuSection/MmuSmallPage,
+ PtAlign = 1<<10,
+
+ MINICACHED = 0x10000000,
+};
+
+/* for debugging */
+void
+prs(char *s)
+{
+ for(; *s; s++)
+ uartputc(*s);
+}
+
+void
+pr16(ulong n)
+{
+ int i;
+
+ for(i=28; i>=0; i-=4)
+ uartputc("0123456789ABCDEF"[(n>>i)&0xF]);
+}
+
+void*
+mmuphysmap(ulong phys, ulong)
+{
+ ulong *ttb;
+ void *va;
+
+ ttb = (ulong*)KTTB;
+ va = KADDR(phys);
+ ttb[MmuL1x((ulong)va)] = phys | 0xC10 | MmuL1section;
+ return va;
+}
+
+/*
+ * Set a 1-1 map of virtual to physical memory, except:
+ * doubly-map page0 at the alternative interrupt vector address,
+ * doubly-map physical memory at KZERO+256*MB as uncached but buffered, and
+ * disable access to 0 (nil pointers).
+ */
+void
+mmuinit(void)
+{
+ int i;
+ ulong *ttb, *ptable, va;
+
+ ttb = (ulong*)KTTB;
+ for(i=0; i<MmuL1x(0x10000000); i++)
+ ttb[i] = 0;
+ for(; i < 0x1000; i++)
+ ttb[i] = (i<<20) | 0xC10 | MmuL1section;
+ for(va = KZERO; va < KZERO+64*MB; va += MB)
+ ttb[MmuL1x(va)] |= MmuWB | MmuIDC; /* DRAM is cacheable */
+ for(i = 0; i < 64*MB; i += MB)
+ ttb[MmuL1x(UCDRAMZERO+i)] = (PHYSMEM0+i) | 0xC10 | MmuL1section;
+ /* TO DO: make the text read only */
+ for(va = KZERO; va < KZERO+64*MB; va += MB)
+ ttb[MmuL1x(va|MINICACHED)] = va | 0xC10 | MmuIDC | MmuL1section; /* cached but unbuffered (thus minicache) for frame buffer */
+ ttb[MmuL1x(DCFADDR)] |= MmuIDC | MmuWB; /* cached and buffered for cache writeback */
+ ttb[MmuL1x(MCFADDR)] |= MmuIDC; /* cached and unbuffered for minicache writeback */
+ /* remap flash */
+ for(i=0; i<32*MB; i+=MB)
+ ttb[MmuL1x(FLASHMEM+i)] = (PHYSFLASH0+i) | 0xC10 | MmuL1section; /* we'll make flash uncached for now */
+
+ /*
+ * build page table for alternative vector page, mapping trap vectors in *page0
+ */
+ ptable = xspanalloc(SectionPages*sizeof(*ptable), PtAlign, 0);
+ ptable[MmuL2x(AIVECADDR)] = PADDR(page0) | MmuL2AP(MmuAPsrw) | MmuWB | MmuIDC | MmuL2small;
+ ttb[MmuL1x(AIVECADDR)] = PADDR(ptable) | MmuL1page;
+ mmuputttb(KTTB);
+ mmuputdac(1); /* client */
+ mmuenable(CpCaltivec | CpCIcache | CpCsystem | (1<<6) | CpCd32 | CpCi32 | CpCwb | CpCDcache | CpCmmu);
+}
+
+/*
+ * flush data in a given address range to memory
+ * and invalidate the region in the instruction cache.
+ */
+int
+segflush(void *a, ulong n)
+{
+ dcflush(a, n);
+ icflushall(); /* can't be more precise */
+ return 0;
+}
+
+/*
+ * map an address to cached but unbuffered memory
+ * forcing load allocations to the mini data cache.
+ * the address a must be in a region that is cache line aligned
+ * with a length that is a multiple of the cache line size
+ */
+void *
+minicached(void *a)
+{
+ if(conf.useminicache == 0)
+ return a;
+ /* must flush and invalidate any data lingering in main cache */
+ dcflushall();
+ minidcflush();
+ dcinval();
+ return (void*)((ulong)a | MINICACHED);
+}