summaryrefslogtreecommitdiff
path: root/os/manga/mmu.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/manga/mmu.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/manga/mmu.c')
-rw-r--r--os/manga/mmu.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/os/manga/mmu.c b/os/manga/mmu.c
new file mode 100644
index 00000000..433289d1
--- /dev/null
+++ b/os/manga/mmu.c
@@ -0,0 +1,244 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+
+/*
+ * Small pages:
+ * L1: 12-bit index -> 4096 descriptors -> 16Kb
+ * L2: 8-bit index -> 256 descriptors -> 1Kb
+ * Each L2 descriptor has access permissions for 4 1Kb sub-pages.
+ *
+ * TTB + L1Tx gives address of L1 descriptor
+ * L1 descriptor gives PTBA
+ * PTBA + L2Tx gives address of L2 descriptor
+ * L2 descriptor gives PBA
+ *
+ * C & B are interpreted as follows:
+ * C=0 B=0 uncached, unbuffered, stall until data access complete
+ * C=0 B=1 uncached, buffered
+ * C=1 B=0 write-through cachable
+ * C=1 B=1 write-back cachable
+ * and the i-cache uses only the C bit (cached if non-zero).
+ */
+#define TTB(pa) ((pa) & ~0x3FFF) /* translation table base */
+#define L1x(pa) (((pa)>>20) & 0xFFF) /* L1 table index */
+#define PTBA(pa) ((pa) & ~0x3FF) /* page table base address */
+#define L2x(pa) (((pa)>>12) & 0xFF) /* L2 table index */
+#define PBA(pa) ((pa) & ~0xFFF) /* page base address */
+#define SBA(pa) ((pa) & ~0xFFFFF) /* section base address */
+
+enum {
+ /* sizes */
+ Section= 1<<20,
+ LargePage= 1<<16,
+ SmallPage= 1<<12,
+ EsmallPage= 1<<10,
+ SectionPages = Section/SmallPage,
+ PtAlign = 1<<10,
+
+ /* L1 descriptor format */
+ L1type= 3<<0, /* mask for type */
+ L1page= 1<<0, /* descriptor is for L2 pages */
+ L1section= 2<<0, /* descriptor is for section */
+ L1fpage= 3<<0, /* descriptor is for fine (1k) L2 pages */
+ L1buffered= 1<<2,
+ L1cached= 1<<3,
+ L1mbo= 1<<4, /* must be one */
+
+ /* L2 descriptor format for coarse page table */
+ L2type= 3<<0, /* mask for type */
+ L2invalid= 0<<0,
+ L2large= 1<<0, /* large page */
+ L2small= 2<<0, /* small page */
+ L2esmall= 3<<0, /* extended small page */
+ L2buffered= 1<<2,
+ L2cached= 1<<3,
+ /* then access permissions */
+ L2smallX= 1<<6,
+ L2largeX= 1<<12,
+
+ /* domains */
+ Dnone= 0,
+ Dclient= 1,
+ Dmanager= 3,
+
+ /* access permissions */
+ APsro= 0, /* supervisor ro if S|R */
+ APsrw= 1, /* supervisor rw */
+ APuro= 2, /* supervisor rw + user ro */
+ APurw= 3, /* supervisor rw + user rw */
+};
+
+#define L1dom(d) (((d) & 0xF)<<5) /* L1 domain */
+#define AP(i, v) ((v)<<(((i)*2)+4)) /* access permissions */
+#define L1AP(v) AP(3, (v))
+#define L2AP(v) AP(3, (v))|AP(2, (v))|AP(1, (v))|AP(0, (v))
+
+#define L1krw (L1AP(APsrw) | L1dom(0))
+
+/*
+ * 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 = L1x((ulong)v);
+ ttb = (ulong*)KTTB;
+ ste = ttb[idx];
+ switch(ste & L1type) {
+ case L1section:
+ return SBA(ste)|((ulong)v & 0x000fffff);
+ case L1page:
+ pte = ((ulong *)PTBA(ste))[L2x((ulong)v)];
+ switch(pte & 3) {
+ case L2large:
+ return (pte & 0xffff0000)|((ulong)v & 0x0000ffff);
+ case L2small:
+ return (pte & 0xfffff000)|((ulong)v & 0x00000fff);
+ }
+ }
+ return 0;
+}
+
+/* for debugging */
+void
+prs(char *s)
+{
+ serialputs(s, strlen(s));
+}
+
+void
+pr16(ulong n)
+{
+ int i, c;
+
+ for(i=28; i>=0; i-=4){
+ c = (n>>i) & 0xF;
+ if(c >= 0 && c <= 9)
+ c += '0';
+ else
+ c += 'A'-10;
+ serialputc(c);
+ }
+}
+
+void
+xdelay(int n)
+{
+ int j;
+
+ for(j=0; j<1000000/4; j++)
+ n++;
+ USED(n);
+}
+
+void*
+mmuphysmap(void *va, ulong pa, ulong nbytes)
+{
+ ulong *ttb;
+ ulong p, o;
+
+ if(va == nil)
+ va = KADDR(pa);
+ p = (ulong)va;
+ if((pa|p) & (Section-1))
+ panic("kmapphys");
+ ttb = (ulong*)KTTB;
+ nbytes = (nbytes+Section-1)&~(Section-1);
+ for(o = 0; o < nbytes; o += Section)
+ ttb[L1x(p+o)] = (pa+o) | (1<<4) | L1krw | L1section;
+ return va;
+}
+
+void*
+mmukaddr(ulong pa)
+{
+ if(pa >= PHYSDRAM0 && pa < conf.topofmem)
+ return (void*)(KZERO+(pa-PHYSDRAM0));
+ return (void*)pa;
+}
+
+/*
+ * Set a 1-1 map of virtual to physical memory, except:
+ * kernel is mapped to KZERO
+ * doubly-map page0 at the alternative interrupt vector address,
+ * doubly-map physical memory at KZERO+256*MB as uncached but buffered,
+ * map flash to virtual space away from 0,
+ * disable access to 0 (nil pointers).
+ *
+ * Other section maps are added later as required by mmuphysmap.
+ */
+void
+mmuinit(void)
+{
+ int i;
+ ulong *ttb, *ptable;
+
+ ttb = (ulong*)KTTB;
+ memset(ttb, 0, 16384);
+
+ /* assume flash is first in special physical space */
+ for(i = L1x(PHYSFLASH0); i < 0x1000; i++)
+ ttb[i] = (i<<20) | L1krw | (1<<4) | L1section;
+
+ /* cached dram at normal kernel addresses */
+ for(i = 0; i < 32*MB; i += MB)
+ ttb[L1x(KZERO+i)] = (PHYSDRAM0+i) | (1<<4) | L1krw | L1section | L1cached | L1buffered;
+
+ /* aliases for uncached dram */
+ for(i = 0; i < 64*MB; i += MB)
+ ttb[L1x(UCDRAMZERO+i)] = (PHYSDRAM0+i) | L1krw | (1<<4) | L1section;
+
+ /* TO DO: make the text read only */
+
+ /* remap flash */
+ for(i=0; i<8*MB; i+=MB)
+ ttb[L1x(FLASHMEM+i)] = (PHYSFLASH0+i) | L1krw | (1<<4) | L1section; /* 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[L2x(AIVECADDR)] = PADDR(page0) | L2AP(APsrw) | L2cached | L2buffered | L2small;
+ ttb[L1x(AIVECADDR)] = PADDR(ptable) | (1<<4) | L1page;
+
+ mmuputttb(KTTB & ~KZERO);
+ mmuputdac(Dclient);
+ mmuputctl(mmugetctl() | CpCaltivec | CpCIcache | CpCsystem | CpCwpd | CpCDcache | CpCmmu);
+ tlbinvalidateall();
+}
+
+/*
+ * 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);
+ icflush(a, n);
+ return 0;
+}
+
+/*
+ * return an uncached alias for the memory at a
+ */
+void*
+mmucacheinhib(void *a, ulong nb)
+{
+ ulong p;
+
+ if(a == nil)
+ return nil;
+ p = PADDR(a);
+ if(p & (CACHELINESZ-1))
+ panic("mmucacheinhib");
+ dcflush(a, nb);
+ return (void*)(UCDRAMZERO|PADDR(a));
+}