diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/cerf405/mmu.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/cerf405/mmu.c')
| -rw-r--r-- | os/cerf405/mmu.c | 122 |
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); +} |
