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/manga/mmu.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/manga/mmu.c')
| -rw-r--r-- | os/manga/mmu.c | 244 |
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)); +} |
