| plan 9 kernel history: overview | file list | diff list |
2000/1006/bitsy/mmu.c (diff list | history)
| 2000/0902/sys/src/9/bitsy/mmu.c:8,13 – 2000/0905/sys/src/9/bitsy/mmu.c:8,18 (short | long) | ||
| 2000/0902 | #include "../port/error.h" void | |
| 2000/0905 | mmuinit(void) { } void | |
| 2000/0902 | putmmu(ulong va, ulong pa, Page*) { USED(va, pa); | |
| 2000/0905/sys/src/9/bitsy/mmu.c:7,15 – 2000/0906/sys/src/9/bitsy/mmu.c:7,59 (short | long) | ||
| 2000/0902 | #include "ureg.h" #include "../port/error.h" | |
| 2000/0906 | /* real protection bits */ enum { Small_Page= (2<<0), Large_Page= (1<<0), Cached= (1<<3), Buffered= (1<<2), UserRO= (0xAA<<4), UserRW= (0xFF<<4), KernelRW= (0x55<<4), }; /* * table to map fault.c bits to physical bits */ static ulong phystrans[8] = { [PTEVALID] Small_Page|Cached|Buffered|UserRO, [PTEVALID|PTEWRITE] Small_Page|Cached|Buffered|UserRW, [PTEVALID|UNCACHED] Small_Page|UserRO, [PTEVALID|UNCACHED|PTEWRITE] Small_Page|UserRW, }; ulong *l1page; /* * We map all of memory, flash, and the zeros area with sections. * Special use space is mapped on the fly with regmap. */ | |
| 2000/0902 | void | |
| 2000/0905 | mmuinit(void) { | |
| 2000/0906 | ulong a, e; /* set up the domain register to cause all domains to obey pte access bits */ putdac(0x55555555); /* get a prototype level 1 page */ l1page = xspanalloc(BY2PG, 16*1024, 0); memset(l1page, 0, BY2PG); /* map DRAM */ e = PHYSDRAM0 + BY2PG*con for( /* map zeros */ /* map flash */ | |
| 2000/0905 | } void | |
| 2000/0906/sys/src/9/bitsy/mmu.c:10,37 – 2000/0907/sys/src/9/bitsy/mmu.c:10,58 (short | long) | ||
| 2000/0906 | /* real protection bits */ enum { | |
| 2000/0907 | /* level 1 descriptor bits */ L1TypeMask= (3<<0), L1Invalid= (0<<0), L1PageTable= (1<<0), L1Section= (2<<0), L1Cached= (1<<3), L1Buffered= (1<<2), L1Domain0= (0<<5), L1KernelRW= (0x1<<10), L1UserRO= (0x2<<10), L1UserRW= (0x3<<10), L1SectBaseMask= (0xFFF<<20), L1PTBaseMask= (0x3FFFFF<<10), /* level 2 descriptor bits */ L2TypeMask= (3<<0), L2SmallPage= (2<<0), L2LargePage= (1<<0), L2Cached= (1<<3), L2Buffered= (1<<2), L2KernelRW= (0x55<<4), L2UserRO= (0xAA<<4), L2UserRW= (0xFF<<4), L2PageBaseMask= (0xFFFFF<<12), | |
| 2000/0906 | }; | |
| 2000/0907 | static ulong phystrans[16] = | |
| 2000/0906 | { | |
| 2000/0907 | [PTEVALID] L2SmallPage|L2Cached|L2Buffered|L2UserRO, [PTEVALID|PTEWRITE] L2SmallPage|L2Cached|L2Buffered|L2UserRW, [PTEVALID|PTEUNCACHED] L2SmallPage|L2UserRO, [PTEVALID|PTEUNCACHED|PTEWRITE] L2SmallPage|L2UserRW, [PTEKERNEL|PTEVALID] L2SmallPage|L2Cached|L2Buffered|L2KernelRW, [PTEKERNEL|PTEVALID|PTEWRITE] L2SmallPage|L2Cached|L2Buffered|L2KernelRW, [PTEKERNEL|PTEVALID|PTEUNCACHED] L2SmallPage|L2KernelRW, [PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE] L2SmallPage|L2KernelRW, | |
| 2000/0906 | }; | |
| 2000/0907 | ulong *l1table; | |
| 2000/0906 | /* * We map all of memory, flash, and the zeros area with sections. | |
| 2000/0906/sys/src/9/bitsy/mmu.c:46,59 – 2000/0907/sys/src/9/bitsy/mmu.c:67,123 | ||
| 2000/0906 | putdac(0x55555555); /* get a prototype level 1 page */ | |
| 2000/0907 | l1table = xspanalloc(BY2PG, 16*1024, 0); memset(l1table, 0, BY2PG); | |
| 2000/0906 |
| |
| 2000/0907 | /* direct map DRAM */ e = conf.base1 + BY2PG*conf.npage2; for(a = PHYSDRAM0; a < e; a += OneMeg) l1table[a>>20] = L1Section | L1KernelRW | L1Cached | L1Buffered | (a&L1SectBaseMask); /* direct map zeros area */ for(a = PHYSNULL0; a < PHYSNULL0 + 128 * OneMeg; a += OneMeg) l1table[a>>20] = L1Section | L1KernelRW | L1Cached | L1Buffered | (a&L1SectBaseMask); /* direct map flash */ for(a = PHYFLASH0; a < PHYFLASH0 + 128 * OneMeg; a += OneMeg) l1table[a>>20] = L1Section | L1KernelRW | L1Cached | L1Buffered | (a&L1SectBaseMask); /* map the uart so that we can continue using iprint */ uart3regs = mapspecial(UART3REGS, 64); } /* * map special use space */ ulong* mapspecial(ulong addr, int len) { ulong *t; ulong a, i; /* first see if we've mapped it somewhere, the first hole means we're done */ for(a = REGZERO; a < REGTOP; a += OneMeg){ if((l1table[a>>20] & L1TypeMask) != L1PageTable){ /* create a page table and break */ t = xspanalloc(BY2PG, 1024, 0); memzero(t, BY2PG, 0); l1table[a>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); break; } t = (ulong*)(l1table[a>>20] & L1PTBaseMask); for(i = 0; i < OneMeg; i += BY2PG){ if((t[a>>20] & L2TypeMask) != L2SmallPage) break; } if(i < OneMeg){ a += i; break; } } | |
| 2000/0905 | } void | |
| 2000/0907/sys/src/9/bitsy/mmu.c:94,123 – 2000/0909/sys/src/9/bitsy/mmu.c:94,126 (short | long) | ||
| 2000/0907 | * map special use space */ ulong* | |
| 2000/0909 | mapspecial(ulong physaddr, int len) | |
| 2000/0907 | { ulong *t; | |
| 2000/0909 | ulong virtaddr, i; | |
| 2000/0907 | /* first see if we've mapped it somewhere, the first hole means we're done */ | |
| 2000/0909 | for(virtaddr = REGZERO; virtaddr < REGTOP; virtaddr += OneMeg){ if((l1table[virtaddr>>20] & L1TypeMask) != L1PageTable){ | |
| 2000/0907 | /* create a page table and break */ t = xspanalloc(BY2PG, 1024, 0); memzero(t, BY2PG, 0); | |
| 2000/0909 | l1table[virtaddr>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); | |
| 2000/0907 | break; } | |
| 2000/0909 | t = (ulong*)(l1table[virtaddr>>20] & L1PTBaseMask); | |
| 2000/0907 | for(i = 0; i < OneMeg; i += BY2PG){ | |
| 2000/0909 | if((t[virtaddr>>20] & L2TypeMask) != L2SmallPage) | |
| 2000/0907 | break; } if(i < OneMeg){ | |
| 2000/0909 | virtaddr += i; | |
| 2000/0907 | break; } } | |
| 2000/0909 | /* we get here if no entry was found mapping this physical address */ | |
| 2000/0905 | } void | |
| 2000/0909/sys/src/9/bitsy/mmu.c:91,97 – 2000/0920/sys/src/9/bitsy/mmu.c:91,97 (short | long) | ||
| 2000/0907 | } /* | |
| 2000/0920 | * map special use space | |
| 2000/0907 | */ ulong* | |
| 2000/0909 | mapspecial(ulong physaddr, int len) | |
| 2000/0909/sys/src/9/bitsy/mmu.c:110,117 – 2000/0920/sys/src/9/bitsy/mmu.c:110,118 | ||
| 2000/0907 | } | |
| 2000/0909 | t = (ulong*)(l1table[virtaddr>>20] & L1PTBaseMask); | |
| 2000/0907 | for(i = 0; i < OneMeg; i += BY2PG){ | |
| 2000/0909 |
| |
| 2000/0920 | if((t[(virtaddr+i)>>20] & L2TypeMask) != L2SmallPage) | |
| 2000/0907 | break; | |
| 2000/0920 | ||
| 2000/0907 | } if(i < OneMeg){ | |
| 2000/0909 | virtaddr += i; | |
| 2000/0909/sys/src/9/bitsy/mmu.c:119,126 – 2000/0920/sys/src/9/bitsy/mmu.c:120,126 | ||
| 2000/0907 | } } | |
| 2000/0909 |
| |
| 2000/0920 | /* we get here if no entry was found mapping this physical range */ | |
| 2000/0905 | } void | |
| 2000/0920/sys/src/9/bitsy/mmu.c:91,104 – 2000/0921/sys/src/9/bitsy/mmu.c:91,111 (short | long) | ||
| 2000/0907 | } /* | |
| 2000/0920 |
| |
| 2000/0921 | * map special space, assume that the space isn't already mapped | |
| 2000/0907 | */ ulong* | |
| 2000/0909 | mapspecial(ulong physaddr, int len) | |
| 2000/0907 | { ulong *t; | |
| 2000/0909 |
| |
| 2000/0921 | ulong virtaddr, i, base, end, off, entry, candidate; | |
| 2000/0907 | ||
| 2000/0921 | base = physaddr & ~(BY2PG-1); end = (physaddr+len-1) & ~(BY2PG-1); if(len > 128*1024) usemeg = 1; off = 0; candidate = 0; | |
| 2000/0907 | /* first see if we've mapped it somewhere, the first hole means we're done */ | |
| 2000/0909 | for(virtaddr = REGZERO; virtaddr < REGTOP; virtaddr += OneMeg){ if((l1table[virtaddr>>20] & L1TypeMask) != L1PageTable){ | |
| 2000/0920/sys/src/9/bitsy/mmu.c:105,118 – 2000/0921/sys/src/9/bitsy/mmu.c:112,145 | ||
| 2000/0907 | /* create a page table and break */ t = xspanalloc(BY2PG, 1024, 0); memzero(t, BY2PG, 0); | |
| 2000/0909 |
| |
| 2000/0921 | l1table[virtaddr>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); | |
| 2000/0907 | break; } | |
| 2000/0909 | t = (ulong*)(l1table[virtaddr>>20] & L1PTBaseMask); | |
| 2000/0907 | for(i = 0; i < OneMeg; i += BY2PG){ | |
| 2000/0920 |
| |
| 2000/0921 | entry = t[(virtaddr+i)>>20]; /* first hole means nothing left, add map */ if((entry & L2TypeMask) != L2SmallPage) | |
| 2000/0907 | break; | |
| 2000/0920 | ||
| 2000/0921 | if(candidate == 0){ /* look for start of range */ if((entry & L2PageBaseMask) != base) continue; candidate = virtaddr+i; } else { /* look for contiunued range */ if((entry & L2PageBaseMask) != base + off) candidate = 0; continue; } } /* if we're at the end of the range, area is already mapped */ if((entry & L2PageBaseMask) == end) return candidate + (physaddr-base); | |
| 2000/0907 | } if(i < OneMeg){ | |
| 2000/0909 | virtaddr += i; | |
| 2000/0921/sys/src/9/bitsy/mmu.c:91,99 – 2000/0923/sys/src/9/bitsy/mmu.c:91,101 (short | long) | ||
| 2000/0907 | } /* | |
| 2000/0921 |
| |
| 2000/0923 | * map special space uncached, assume that the space isn't already mapped | |
| 2000/0907 | */ ulong* | |
| 2000/0923 | mapspecmeg(ulong physaddr, int len) ulong* | |
| 2000/0909 | mapspecial(ulong physaddr, int len) | |
| 2000/0907 | { ulong *t; | |
| 2000/0921/sys/src/9/bitsy/mmu.c:131,137 – 2000/0923/sys/src/9/bitsy/mmu.c:133,139 | ||
| 2000/0921 | candidate = virtaddr+i; } else { /* look for contiunued range */ | |
| 2000/0923 | if((entry & L2PageBaseMask) != base + off){ | |
| 2000/0921 | candidate = 0; continue; } | |
| 2000/0923/sys/src/9/bitsy/mmu.c:94,155 – 2000/0924/sys/src/9/bitsy/mmu.c:94,158 (short | long) | ||
| 2000/0923 | * map special space uncached, assume that the space isn't already mapped | |
| 2000/0907 | */ ulong* | |
| 2000/0923 |
| |
| 2000/0909 |
| |
| 2000/0924 | mapspecial(ulong pa, int len) | |
| 2000/0907 | { ulong *t; | |
| 2000/0921 |
| |
| 2000/0924 | ulong va, i, base, end, off; int livelarge; ulong* rv; | |
| 2000/0907 | ||
| 2000/0921 |
| |
| 2000/0924 | rv = nil; livelarge = len >= 128*1024; if(livelarge){ base = pa & ~(OneMeg-1); end = (pa+len-1) & ~(OneMeg-1); } else { base = pa & ~(BY2PG-1); end = (pa+len-1) & ~(BY2PG-1); } off = pa - base; | |
| 2000/0921 | ||
| 2000/0907 |
| |
| 2000/0909 |
| |
| 2000/0907 |
| |
| 2000/0924 | for(va = REGZERO; va < REGTOP && base >= end; va += OneMeg){ if((l1table[va>>20] & L1TypeMask) != L1PageTable){ /* found unused entry on level 1 table */ if(livelarge){ if(rv == nil) rv = (ulong*)(va+i*BY2PG+off); l1table[va>>20] = L1Section | L1KernelRW | (base&L1SectBaseMask); base += OneMeg; continue; } /* create a page table and keep going */ | |
| 2000/0907 | t = xspanalloc(BY2PG, 1024, 0); memzero(t, BY2PG, 0); | |
| 2000/0921 |
| |
| 2000/0924 | l1table[va>>20] = L1PageTable | L1Domain0 | | |
| 2000/0921 | (((ulong)t) & L1PTBaseMask); | |
| 2000/0907 |
| |
| 2000/0909 |
| |
| 2000/0924 | t = (ulong*)(l1table[va>>20] & L1PTBaseMask); | |
| 2000/0907 | for(i = 0; i < OneMeg; i += BY2PG){ | |
| 2000/0921 |
| |
| 2000/0924 | entry = t[i>>PGSHIFT]; | |
| 2000/0921 |
| |
| 2000/0907 |
| |
| 2000/0921 |
| |
| 2000/0923 |
| |
| 2000/0921 |
| |
| 2000/0924 | /* found unused entry on level 2 table */ if((entry & L2TypeMask) != L2SmallPage){ if(rv == nil) rv = (ulong*)(va+i*BY2PG+off); t[i>>PGSHIFT] = L2SmallPage | L2KernelRW | (base & L2PageBaseMask); base += BY2PG; continue; | |
| 2000/0921 | } | |
| 2000/0907 | } | |
| 2000/0909 |
| |
| 2000/0907 |
| |
| 2000/0909 | ||
| 2000/0920 |
| |
| 2000/0924 | /* didn't fit */ if(base <= end) return nil; return rv; | |
| 2000/0905 | } void | |
| 2000/0924/sys/src/9/bitsy/mmu.c:63,81 – 2000/0928/sys/src/9/bitsy/mmu.c:63,82 (short | long) | ||
| 2000/0905 | { | |
| 2000/0906 | ulong a, e; | |
| 2000/0907 | l1table = xspanalloc(BY2PG, 16*1024, 0); memset(l1table, 0, BY2PG); | |
| 2000/0906 | ||
| 2000/0907 | /* direct map DRAM */ | |
| 2000/0928 | e = conf.base1 + BY2PG*conf.npage1; | |
| 2000/0907 | for(a = PHYSDRAM0; a < e; a += OneMeg) l1table[a>>20] = L1Section | L1KernelRW | L1Cached | L1Buffered | (a&L1SectBaseMask); | |
| 2000/0928 | /* direct map devs */ for(a = REGZERO; a < REGTOP; a += OneMeg) l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask); | |
| 2000/0907 | /* direct map zeros area */ for(a = PHYSNULL0; a < PHYSNULL0 + 128 * OneMeg; a += OneMeg) l1table[a>>20] = L1Section | L1KernelRW | | |
| 2000/0924/sys/src/9/bitsy/mmu.c:82,93 – 2000/0928/sys/src/9/bitsy/mmu.c:83,102 | ||
| 2000/0907 | L1Cached | L1Buffered | (a&L1SectBaseMask); /* direct map flash */ | |
| 2000/0928 | for(a = PHYSFLASH0; a < PHYSFLASH0 + 128 * OneMeg; a += OneMeg) | |
| 2000/0907 | l1table[a>>20] = L1Section | L1KernelRW | L1Cached | L1Buffered | (a&L1SectBaseMask); /* map the uart so that we can continue using iprint */ | |
| 2000/0928 | // uart3regs = mapspecial(UART3REGS, 64); /* set up the domain register to cause all domains to obey pte access bits */ iprint("setting up domain access\n"); putdac(0x55555555); /* point to map */ iprint("setting tlb map %lux\n", (ulong)l1table); putttb((ulong)l1table); | |
| 2000/0907 | } /* | |
| 2000/0924/sys/src/9/bitsy/mmu.c:97,103 – 2000/0928/sys/src/9/bitsy/mmu.c:106,112 | ||
| 2000/0924 | mapspecial(ulong pa, int len) | |
| 2000/0907 | { ulong *t; | |
| 2000/0924 |
| |
| 2000/0928 | ulong va, i, base, end, off, entry; | |
| 2000/0924 | int livelarge; ulong* rv; | |
| 2000/0907 | ||
| 2000/0924/sys/src/9/bitsy/mmu.c:127,133 – 2000/0928/sys/src/9/bitsy/mmu.c:136,142 | ||
| 2000/0924 | /* create a page table and keep going */ | |
| 2000/0907 | t = xspanalloc(BY2PG, 1024, 0); | |
| 2000/0928 | memset(t, 0, BY2PG); | |
| 2000/0924 | l1table[va>>20] = L1PageTable | L1Domain0 | | |
| 2000/0921 | (((ulong)t) & L1PTBaseMask); | |
| 2000/0907 | } | |
| 2000/0928/sys/src/9/bitsy/mmu.c:62,67 – 2000/0929/sys/src/9/bitsy/mmu.c:62,68 (short | long) | ||
| 2000/0905 | mmuinit(void) { | |
| 2000/0906 | ulong a, e; | |
| 2000/0929 | ulong *t; | |
| 2000/0906 | /* get a prototype level 1 page */ | |
| 2000/0907 | l1table = xspanalloc(BY2PG, 16*1024, 0); | |
| 2000/0928/sys/src/9/bitsy/mmu.c:70,102 – 2000/0929/sys/src/9/bitsy/mmu.c:71,109 | ||
| 2000/0907 | /* direct map DRAM */ | |
| 2000/0928 | e = conf.base1 + BY2PG*conf.npage1; | |
| 2000/0907 | for(a = PHYSDRAM0; a < e; a += OneMeg) | |
| 2000/0929 | l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask) | L1Cached | L1Buffered; | |
| 2000/0907 | ||
| 2000/0928 |
| |
| 2000/0907 | /* direct map zeros area */ for(a = PHYSNULL0; a < PHYSNULL0 + 128 * OneMeg; a += OneMeg) | |
| 2000/0929 | l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask); | |
| 2000/0907 | /* direct map flash */ | |
| 2000/0928 | for(a = PHYSFLASH0; a < PHYSFLASH0 + 128 * OneMeg; a += OneMeg) | |
| 2000/0907 |
| |
| 2000/0929 | l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask) | L1Cached | L1Buffered; | |
| 2000/0907 |
| |
| 2000/0928 |
| |
| 2000/0929 | /* map first page of DRAM also into 0xFFFF0000 for the interrupt vectors */ t = xspanalloc(BY2PG, 16*1024, 0); memset(t, 0, BY2PG); l1table[0xFFFF0000>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); t[0xF0000>>PGSHIFT] = L2SmallPage | L2KernelRW | PHYSDRAM0; | |
| 2000/0928 | /* set up the domain register to cause all domains to obey pte access bits */ iprint("setting up domain access\n"); | |
| 2000/0929 | putdac(0xFFFFFFFF); | |
| 2000/0928 | /* point to map */ iprint("setting tlb map %lux\n", (ulong)l1table); putttb((ulong)l1table); | |
| 2000/0929 | /* map the uart so that we can continue using iprint */ uart3regs = (Uartregs*)mapspecial(UART3REGS, 64); /* enable mmu, and make 0xFFFF0000 the virtual address of the exception vecs */ mmuenable(); iprint("uart3regs now at %lux\n", uart3regs); | |
| 2000/0907 | } /* | |
| 2000/0928/sys/src/9/bitsy/mmu.c:121,146 – 2000/0929/sys/src/9/bitsy/mmu.c:128,162 | ||
| 2000/0924 | } off = pa - base; | |
| 2000/0921 | ||
| 2000/0924 |
| |
| 2000/0929 | for(va = REGZERO; va < REGTOP && base <= end; va += OneMeg){ switch(l1table[va>>20] & L1TypeMask){ default: | |
| 2000/0924 | /* found unused entry on level 1 table */ if(livelarge){ if(rv == nil) | |
| 2000/0929 | rv = (ulong*)(va+off); | |
| 2000/0924 | l1table[va>>20] = L1Section | L1KernelRW | | |
| 2000/0929 | (base & L1SectBaseMask); | |
| 2000/0924 | base += OneMeg; continue; | |
| 2000/0929 | } else { | |
| 2000/0924 |
| |
| 2000/0907 |
| |
| 2000/0928 |
| |
| 2000/0924 |
| |
| 2000/0921 |
| |
| 2000/0929 | /* create an L2 page table and keep going */ t = xspanalloc(BY2PG, 1024, 0); memset(t, 0, BY2PG); l1table[va>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); } break; case L1Section: continue; case L1PageTable: if(livelarge) continue; break; | |
| 2000/0907 | } | |
| 2000/0924 | ||
| 2000/0929 | /* here if we're using page maps instead of sections */ | |
| 2000/0924 | t = (ulong*)(l1table[va>>20] & L1PTBaseMask); | |
| 2000/0907 | for(i = 0; i < OneMeg; i += BY2PG){ | |
| 2000/0924 | entry = t[i>>PGSHIFT]; | |
| 2000/0928/sys/src/9/bitsy/mmu.c:148,154 – 2000/0929/sys/src/9/bitsy/mmu.c:164,170 | ||
| 2000/0924 | /* found unused entry on level 2 table */ if((entry & L2TypeMask) != L2SmallPage){ if(rv == nil) | |
| 2000/0929 | rv = (ulong*)(va+i+off); | |
| 2000/0924 | t[i>>PGSHIFT] = L2SmallPage | L2KernelRW | (base & L2PageBaseMask); base += BY2PG; | |
| 2000/0929/sys/src/9/bitsy/mmu.c:98,104 – 2000/1002/sys/src/9/bitsy/mmu.c:98,104 (short | long) | ||
| 2000/0928 | putttb((ulong)l1table); | |
| 2000/0929 | /* map the uart so that we can continue using iprint */ | |
| 2000/1002 | uart3regs = mapspecial(UART3REGS, 64); | |
| 2000/0929 | /* enable mmu, and make 0xFFFF0000 the virtual address of the exception vecs */ mmuenable(); | |
| 2000/0929/sys/src/9/bitsy/mmu.c:109,115 – 2000/1002/sys/src/9/bitsy/mmu.c:109,115 | ||
| 2000/0907 | /* | |
| 2000/0923 | * map special space uncached, assume that the space isn't already mapped | |
| 2000/0907 | */ | |
| 2000/1002 | void* | |
| 2000/0924 | mapspecial(ulong pa, int len) | |
| 2000/0907 | { ulong *t; | |
| 2000/1002/sys/src/9/bitsy/mmu.c:97,109 – 2000/1006/sys/src/9/bitsy/mmu.c:97,104 (short | long) | ||
| 2000/0928 | iprint("setting tlb map %lux\n", (ulong)l1table); putttb((ulong)l1table); | |
| 2000/0929 |
| |
| 2000/1002 |
| |
| 2000/0929 |
| |
| 2000/0907 | } /* | |
| 2000/1006/sys/src/9/bitsy/mmu.c:54,59 – 2000/1007/sys/src/9/bitsy/mmu.c:54,60 (short | long) | ||
| 2000/0906 | ||
| 2000/0907 | ulong *l1table; | |
| 2000/0906 | ||
| 2000/1007 | ||
| 2000/0906 | /* * We map all of memory, flash, and the zeros area with sections. * Special use space is mapped on the fly with regmap. | |
| 2000/1006/sys/src/9/bitsy/mmu.c:65,72 – 2000/1007/sys/src/9/bitsy/mmu.c:66,73 | ||
| 2000/0929 | ulong *t; | |
| 2000/0906 | /* get a prototype level 1 page */ | |
| 2000/0907 |
| |
| 2000/1007 | l1table = xspanalloc(16*1024, 16*1024, 0); memset(l1table, 0, 16*1024); | |
| 2000/0906 | ||
| 2000/0907 | /* direct map DRAM */ | |
| 2000/0928 | e = conf.base1 + BY2PG*conf.npage1; | |
| 2000/1006/sys/src/9/bitsy/mmu.c:83,93 – 2000/1007/sys/src/9/bitsy/mmu.c:84,97 | ||
| 2000/0929 | l1table[a>>20] = L1Section | L1KernelRW | (a&L1SectBaseMask) | L1Cached | L1Buffered; | |
| 2000/0907 | ||
| 2000/0929 |
| |
| 2000/1007 | /* * double map start of ram to exception vectors */ a = EVECTORS; t = xspanalloc(BY2PG, 1024, 0); | |
| 2000/0929 | memset(t, 0, BY2PG); | |
| 2000/1007 | l1table[a>>20] = L1PageTable | L1Domain0 | (((ulong)t) & L1PTBaseMask); t[(a&0xfffff)>>PGSHIFT] = L2SmallPage | L2KernelRW | (PHYSDRAM0 & L2PageBaseMask); | |
| 2000/0928 | /* set up the domain register to cause all domains to obey pte access bits */ iprint("setting up domain access\n"); | |
| 2000/1006/sys/src/9/bitsy/mmu.c:97,103 – 2000/1007/sys/src/9/bitsy/mmu.c:101,110 | ||
| 2000/0928 | iprint("setting tlb map %lux\n", (ulong)l1table); putttb((ulong)l1table); | |
| 2000/0929 |
| |
| 2000/1007 | /* enable mmu */ wbflush(); flushcache(); flushmmu(); | |
| 2000/0929 | mmuenable(); | |
| 2000/0907 | } | |
| 2000/1007/sys/src/9/bitsy/mmu.c:7,12 – 2000/1011/sys/src/9/bitsy/mmu.c:7,20 (short | long) | ||
| 2000/0902 | #include "ureg.h" #include "../port/error.h" | |
| 2000/1011 | /* * to avoid mmu and cash flushing, we use the pid register in the MMU * to map all user addresses. Although there are 64 possible pids, we * can only use 31 because there are only 32 protection domains and we * need one for the kernel. Pid i is thus associated with domain i. * Domain 0 is used for the kernel. */ | |
| 2000/0906 | /* real protection bits */ enum { | |
| 2000/1007/sys/src/9/bitsy/mmu.c:17,23 – 2000/1011/sys/src/9/bitsy/mmu.c:25,32 | ||
| 2000/0907 | L1Section= (2<<0), L1Cached= (1<<3), L1Buffered= (1<<2), | |
| 2000/1011 | L1DomShift= 5, L1Domain0= (0<<L1DomShift), | |
| 2000/0907 | L1KernelRW= (0x1<<10), L1UserRO= (0x2<<10), L1UserRW= (0x3<<10), | |
| 2000/1007/sys/src/9/bitsy/mmu.c:34,55 – 2000/1011/sys/src/9/bitsy/mmu.c:43,53 | ||
| 2000/0907 | L2UserRO= (0xAA<<4), L2UserRW= (0xFF<<4), L2PageBaseMask= (0xFFFFF<<12), | |
| 2000/0906 |
| |
| 2000/0907 |
| |
| 2000/0906 |
| |
| 2000/0907 |
| |
| 2000/1011 | /* domain values */ Dnoaccess= 0, Dclient= 1, Dmanager= 3, | |
| 2000/0906 | }; | |
| 2000/0907 | ulong *l1table; | |
| 2000/1007/sys/src/9/bitsy/mmu.c:62,68 – 2000/1011/sys/src/9/bitsy/mmu.c:60,66 | ||
| 2000/0902 | void | |
| 2000/0905 | mmuinit(void) { | |
| 2000/0906 |
| |
| 2000/1011 | ulong a, o; | |
| 2000/0929 | ulong *t; | |
| 2000/0906 | /* get a prototype level 1 page */ | |
| 2000/1007/sys/src/9/bitsy/mmu.c:69,89 – 2000/1011/sys/src/9/bitsy/mmu.c:67,95 | ||
| 2000/1007 | l1table = xspanalloc(16*1024, 16*1024, 0); memset(l1table, 0, 16*1024); | |
| 2000/0906 | ||
| 2000/0907 |
| |
| 2000/0928 |
| |
| 2000/0907 |
| |
| 2000/0929 |
| |
| 2000/1011 | /* map DRAM */ for(o = 0; o < DRAMTOP; o += OneMeg) l1table[(DRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | ((PHYSDRAM0+o)&L1SectBaseMask); | |
| 2000/0907 |
| |
| 2000/0929 |
| |
| 2000/1011 | /* map zeros area */ for(o = 0; o < 128 * OneMeg; o += OneMeg) l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | ((PHYSNULL0+o)&L1SectBaseMask); | |
| 2000/0907 |
| |
| 2000/0928 |
| |
| 2000/0929 |
| |
| 2000/1011 | /* map flash */ for(o = 0; o < 128 * OneMeg; o += OneMeg) l1table[(FLASHZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | L1Cached | L1Buffered | ((PHYSFLASH0+o)&L1SectBaseMask); | |
| 2000/0907 | ||
| 2000/1011 | /* map peripheral control module regs */ mapspecial(0x80000000, OneMeg); /* map system control module regs */ mapspecial(0x90000000, OneMeg); | |
| 2000/1007 | /* * double map start of ram to exception vectors */ | |
| 2000/1007/sys/src/9/bitsy/mmu.c:95,101 – 2000/1011/sys/src/9/bitsy/mmu.c:101,107 | ||
| 2000/0928 | /* set up the domain register to cause all domains to obey pte access bits */ iprint("setting up domain access\n"); | |
| 2000/0929 |
| |
| 2000/1011 | putdac(Dclient); | |
| 2000/0928 | /* point to map */ iprint("setting tlb map %lux\n", (ulong)l1table); | |
| 2000/1007/sys/src/9/bitsy/mmu.c:137,143 – 2000/1011/sys/src/9/bitsy/mmu.c:143,149 | ||
| 2000/0924 | if(livelarge){ if(rv == nil) | |
| 2000/0929 | rv = (ulong*)(va+off); | |
| 2000/0924 |
| |
| 2000/1011 | l1table[va>>20] = L1Section | L1KernelRW | L1Domain0 | | |
| 2000/0929 | (base & L1SectBaseMask); | |
| 2000/0924 | base += OneMeg; continue; | |
| 2000/1007/sys/src/9/bitsy/mmu.c:151,156 – 2000/1011/sys/src/9/bitsy/mmu.c:157,169 | ||
| 2000/0929 | } break; case L1Section: | |
| 2000/1011 | /* if it's already mapped in a one meg area, don't remap */ entry = l1table[va>>20]; i = entry & L1SectBaseMask; if(pa >= i && (pa+len) <= i + OneMeg) if((entry & ~L1SectBaseMask) == (L1Section | L1KernelRW | L1Domain0)) return (void*)(va + (pa & (OneMeg-1))); | |
| 2000/0929 | continue; case L1PageTable: if(livelarge) | |
| 2000/1007/sys/src/9/bitsy/mmu.c:182,201 – 2000/1011/sys/src/9/bitsy/mmu.c:195,290 | ||
| 2000/0924 | return rv; | |
| 2000/0905 | } | |
| 2000/1011 | /* * find a new pid. If none exist, flush all pids, mmu, and caches. */ static Lock pidlock; int newtlbpid(Proc *p) { return p->pid; } /* * table to map fault.c bits to physical bits */ static ulong mmubits[16] = { [PTEVALID] L2SmallPage|L2Cached|L2Buffered|L2UserRO, [PTEVALID|PTEWRITE] L2SmallPage|L2Cached|L2Buffered|L2UserRW, [PTEVALID|PTEUNCACHED] L2SmallPage|L2UserRO, [PTEVALID|PTEUNCACHED|PTEWRITE] L2SmallPage|L2UserRW, [PTEKERNEL|PTEVALID] L2SmallPage|L2Cached|L2Buffered|L2KernelRW, [PTEKERNEL|PTEVALID|PTEWRITE] L2SmallPage|L2Cached|L2Buffered|L2KernelRW, [PTEKERNEL|PTEVALID|PTEUNCACHED] L2SmallPage|L2KernelRW, [PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE] L2SmallPage|L2KernelRW, }; /* * add an entry to the current map */ | |
| 2000/0905 | void | |
| 2000/0902 | putmmu(ulong va, ulong pa, Page*) { | |
| 2000/1011 | ulong pva; Page *p; ulong *t; /* if user memory, offset by pid value */ if((va & 0xfe000000) == 0) pva = va | (up->pid << 25); else pva = va; /* always point L1 entry to L2 page, can't hurt */ p = up->l1[va>>20]; if(p == nil){ p = auxpage(); if(p == nil) pexit("out of memory", 1); p->va = VA(kmap(p)); up->l1[va>>20] = p; } l1table[pva>>20] = L1PageTable | L1Domain0 | (p->pa & L1PTBaseMask); t = (ulong*)p->va; /* set L2 entry */ t[(pva & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)] | (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)); wbflush(); | |
| 2000/0902 | } | |
| 2000/1011 | /* * this is called with palloc locked so the pagechainhead is kosher */ | |
| 2000/0902 | void | |
| 2000/1011 | mmurelease(Proc* p) | |
| 2000/0902 | { | |
| 2000/1011 | Page *pg; int i; for(i = 0; i < nelem(p->l1); i++){ pg = p->l1[i]; if(pg == nil) continue; if(--pg->ref) panic("mmurelease: pg->ref %d\n", pg->ref); pagechainhead(pg); p->l1[i] = nil; } | |
| 2000/0902 | } void | |
| 2000/1011 | mmuswitch(Proc* p) | |
| 2000/0902 | { | |
| 2000/1011 | /* set pid */ if(p->pid <= 0) p->pid = newtlbpid(p); putpid(p->pid<<25); /* set domain register to this + the kernel's domains */ putdac((Dclient<<(2*p->pid)) | Dclient); | |
| 2000/0902 | } | |
| 2000/1011/sys/src/9/bitsy/mmu.c:100,110 – 2000/1012/sys/src/9/bitsy/mmu.c:100,108 (short | long) | ||
| 2000/1007 | t[(a&0xfffff)>>PGSHIFT] = L2SmallPage | L2KernelRW | (PHYSDRAM0 & L2PageBaseMask); | |
| 2000/0928 | /* set up the domain register to cause all domains to obey pte access bits */ | |
| 2000/1011 | putdac(Dclient); | |
| 2000/0928 | /* point to map */ | |
| 2000/0929 | ||
| 2000/1007 | /* enable mmu */ | |
| 2000/1011/sys/src/9/bitsy/mmu.c:196,209 – 2000/1012/sys/src/9/bitsy/mmu.c:194,227 | ||
| 2000/0905 | } | |
| 2000/1011 | /* | |
| 2000/1012 | * maintain pids | |
| 2000/1011 | */ static Lock pidlock; | |
| 2000/1012 | void flushpids(void) { memset(l1table, 0, BY2WD*nelem(m->pid2proc)*32); memset(m->pid2proc, 0, sizeof(m->pid2proc)); flushcache(); flushmmu(); } | |
| 2000/1011 | int newtlbpid(Proc *p) { | |
| 2000/1012 | int i; ilock(&pidlock); i = ++(m->lastpid); if(i >= nelem(m->pid2proc)){ flushpids(); i = m->lastpid = 0; } m->pid2proc[i] = p; p->tlbpid = i+1; iunlock(&pidlock); return p->tlbpid; | |
| 2000/1011 | } /* | |
| 2000/1011/sys/src/9/bitsy/mmu.c:232,240 – 2000/1012/sys/src/9/bitsy/mmu.c:250,259 | ||
| 2000/1011 | Page *p; ulong *t; | |
| 2000/1012 | iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa); /* if user memory, add pid value */ | |
| 2000/1011 | if((va & 0xfe000000) == 0) | |
| 2000/1012 | pva = va | (up->tlbpid << 25); | |
| 2000/1011 | else pva = va; | |
| 2000/1011/sys/src/9/bitsy/mmu.c:281,290 – 2000/1012/sys/src/9/bitsy/mmu.c:300,310 | ||
| 2000/1011 | mmuswitch(Proc* p) | |
| 2000/0902 | { | |
| 2000/1011 | /* set pid */ | |
| 2000/1012 | if(p->tlbpid <= 0) p->tlbpid = newtlbpid(p); iprint("using tlbpid %d\n", p->tlbpid); putpid(p->tlbpid<<25); | |
| 2000/1011 | /* set domain register to this + the kernel's domains */ | |
| 2000/1012 | putdac((Dclient<<(2*p->tlbpid)) | Dclient); | |
| 2000/0902 | } | |
| 2000/1012/sys/src/9/bitsy/mmu.c:67,74 – 2000/1013/sys/src/9/bitsy/mmu.c:67,80 (short | long) | ||
| 2000/1007 | l1table = xspanalloc(16*1024, 16*1024, 0); memset(l1table, 0, 16*1024); | |
| 2000/0906 | ||
| 2000/1013 | /* map low mem */ for(o = 0; o < 1*OneMeg; o += OneMeg) l1table[(0+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | ((0+o)&L1SectBaseMask); | |
| 2000/1011 | /* map DRAM */ | |
| 2000/1013 | for(o = 0; o < 128*OneMeg; o += OneMeg) | |
| 2000/1011 | l1table[(DRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | ((PHYSDRAM0+o)&L1SectBaseMask); | |
| 2000/1012/sys/src/9/bitsy/mmu.c:194,230 – 2000/1013/sys/src/9/bitsy/mmu.c:200,205 | ||
| 2000/0905 | } | |
| 2000/1011 | /* | |
| 2000/1012 |
| |
| 2000/1011 |
| |
| 2000/1012 |
| |
| 2000/1011 |
| |
| 2000/1012 |
| |
| 2000/1011 |
| |
| 2000/1012/sys/src/9/bitsy/mmu.c:246,279 – 2000/1013/sys/src/9/bitsy/mmu.c:221,250 | ||
| 2000/0905 | void | |
| 2000/0902 | putmmu(ulong va, ulong pa, Page*) { | |
| 2000/1011 |
| |
| 2000/1012 | iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa); | |
| 2000/1011 |
| |
| 2000/1012 |
| |
| 2000/1011 |
| |
| 2000/1013 | p = up->l1page[va>>20]; | |
| 2000/1011 | if(p == nil){ p = auxpage(); if(p == nil) pexit("out of memory", 1); p->va = VA(kmap(p)); | |
| 2000/1013 | up->l1page[va>>20] = p; | |
| 2000/1011 | } | |
| 2000/1013 | l1table[va>>20] = L1PageTable | L1Domain0 | (p->pa & L1PTBaseMask); iprint("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]); up->l1table[va>>20] = l1table[va>>20]; | |
| 2000/1011 | t = (ulong*)p->va; /* set L2 entry */ | |
| 2000/1013 | t[(va & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)] | |
| 2000/1011 | | (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)); | |
| 2000/1013 | iprint("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]); | |
| 2000/1011 |
| |
| 2000/1013 | flushmmu(); | |
| 2000/0902 | } | |
| 2000/1011 | /* | |
| 2000/1012/sys/src/9/bitsy/mmu.c:285,298 – 2000/1013/sys/src/9/bitsy/mmu.c:256,269 | ||
| 2000/1011 | Page *pg; int i; | |
| 2000/1013 | for(i = 0; i < nelem(p->l1page); i++){ pg = p->l1page[i]; | |
| 2000/1011 | if(pg == nil) continue; if(--pg->ref) panic("mmurelease: pg->ref %d\n", pg->ref); pagechainhead(pg); | |
| 2000/1013 | p->l1page[i] = nil; | |
| 2000/1011 | } | |
| 2000/0902 | } | |
| 2000/1012/sys/src/9/bitsy/mmu.c:299,310 – 2000/1013/sys/src/9/bitsy/mmu.c:270,276 | ||
| 2000/0902 | void | |
| 2000/1011 | mmuswitch(Proc* p) | |
| 2000/0902 | { | |
| 2000/1011 |
| |
| 2000/1012 |
| |
| 2000/1011 |
| |
| 2000/1012 |
| |
| 2000/1013 | // flushcache(); /* drain and flush the cache */ // flushmmu(); // memmove(l1table, p->l1table, sizeof(p->l1table)); | |
| 2000/0902 | } | |
| 2000/1013/sys/src/9/bitsy/mmu.c:233,240 – 2000/1014/sys/src/9/bitsy/mmu.c:233,242 (short | long) | ||
| 2000/1011 | pexit("out of memory", 1); p->va = VA(kmap(p)); | |
| 2000/1013 | up->l1page[va>>20] = p; | |
| 2000/1014 | memset((uchar*)(p->va), 0, BY2PG); | |
| 2000/1011 | } | |
| 2000/1013 | l1table[va>>20] = L1PageTable | L1Domain0 | (p->pa & L1PTBaseMask); | |
| 2000/1014 | cleanaddr((ulong)&l1table[va>>20]); | |
| 2000/1013 | iprint("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]); up->l1table[va>>20] = l1table[va>>20]; | |
| 2000/1011 | t = (ulong*)p->va; | |
| 2000/1013/sys/src/9/bitsy/mmu.c:243,250 – 2000/1014/sys/src/9/bitsy/mmu.c:245,253 | ||
| 2000/1013 | t[(va & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)] | |
| 2000/1011 | | (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)); | |
| 2000/1013 | iprint("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]); | |
| 2000/1014 | cleanaddr((ulong)&t[(va & (OneMeg-1))>>PGSHIFT]); | |
| 2000/1011 | ||
| 2000/1013 |
| |
| 2000/1014 | wbflush(); | |
| 2000/0902 | } | |
| 2000/1011 | /* | |
| 2000/1013/sys/src/9/bitsy/mmu.c:270,276 – 2000/1014/sys/src/9/bitsy/mmu.c:273,304 | ||
| 2000/0902 | void | |
| 2000/1011 | mmuswitch(Proc* p) | |
| 2000/0902 | { | |
| 2000/1013 |
| |
| 2000/1014 | iprint("switching to proc %d\n", p->pid); memmove(l1table, p->l1table, sizeof(p->l1table)); cleanaddr((ulong)l1table); wbflush(); } void peekmmu(ulong va) { ulong e; e = l1table[va>>20]; switch(e & L1TypeMask){ default: iprint("l1: %lux invalid\n", e); break; case L1PageTable: iprint("l1: %lux pt\n", e); va &= OneMeg-1; va >>= PGSHIFT; e &= L1PTBaseMask; e = ((ulong*)e)[va]; iprint("l2: %lux\n", e); break; case L1Section: iprint("l1: %lux section\n", e); break; } | |
| 2000/0902 | } | |
| 2000/1014/sys/src/9/bitsy/mmu.c:82,87 – 2000/1015/sys/src/9/bitsy/mmu.c:82,88 (short | long) | ||
| 2000/1011 | /* map zeros area */ for(o = 0; o < 128 * OneMeg; o += OneMeg) l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | |
| 2000/1015 | | L1Cached | L1Buffered | |
| 2000/1011 | | ((PHYSNULL0+o)&L1SectBaseMask); | |
| 2000/0907 | ||
| 2000/1011 | /* map flash */ | |
| 2000/1014/sys/src/9/bitsy/mmu.c:113,121 – 2000/1015/sys/src/9/bitsy/mmu.c:114,122 | ||
| 2000/0929 | ||
| 2000/1007 | /* enable mmu */ wbflush(); | |
| 2000/1015 | mmuinvalidate(); | |
| 2000/0929 | mmuenable(); | |
| 2000/1015 | cacheflush(); | |
| 2000/0907 | } /* | |
| 2000/1014/sys/src/9/bitsy/mmu.c:224,230 – 2000/1015/sys/src/9/bitsy/mmu.c:225,231 | ||
| 2000/1011 | Page *p; ulong *t; | |
| 2000/1012 |
| |
| 2000/1015 | //iprint("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa); | |
| 2000/1011 | /* always point L1 entry to L2 page, can't hurt */ | |
| 2000/1013 | p = up->l1page[va>>20]; | |
| 2000/1011 | if(p == nil){ | |
| 2000/1014/sys/src/9/bitsy/mmu.c:236,243 – 2000/1015/sys/src/9/bitsy/mmu.c:237,244 | ||
| 2000/1014 | memset((uchar*)(p->va), 0, BY2PG); | |
| 2000/1011 | } | |
| 2000/1013 | l1table[va>>20] = L1PageTable | L1Domain0 | (p->pa & L1PTBaseMask); | |
| 2000/1014 |
| |
| 2000/1013 |
| |
| 2000/1015 | cacheflushaddr((ulong)&l1table[va>>20]); //iprint("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]); | |
| 2000/1013 | up->l1table[va>>20] = l1table[va>>20]; | |
| 2000/1011 | t = (ulong*)p->va; | |
| 2000/1014/sys/src/9/bitsy/mmu.c:244,282 – 2000/1015/sys/src/9/bitsy/mmu.c:245,333 | ||
| 2000/1011 | /* set L2 entry */ | |
| 2000/1013 | t[(va & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)] | |
| 2000/1011 | | (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)); | |
| 2000/1013 |
| |
| 2000/1014 |
| |
| 2000/1015 | //iprint("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]); cacheflushaddr((ulong)&t[(va & (OneMeg-1))>>PGSHIFT]); | |
| 2000/1011 | ||
| 2000/1014 | wbflush(); | |
| 2000/0902 | } | |
| 2000/1011 | /* | |
| 2000/1015 | * free up all page tables for this proc | |
| 2000/1011 | */ | |
| 2000/0902 | void | |
| 2000/1011 |
| |
| 2000/1015 | mmuptefree(Proc *p) | |
| 2000/0902 | { | |
| 2000/1011 | Page *pg; int i; | |
| 2000/1013 |
| |
| 2000/1015 | for(i = 0; i < Nmeg; i++){ | |
| 2000/1013 | pg = p->l1page[i]; | |
| 2000/1011 | if(pg == nil) continue; | |
| 2000/1015 | p->l1page[i] = nil; pg->next = p->mmufree; p->mmufree = pg; } memset(p->l1table, 0, sizeof(p->l1table)); } /* * this is called with palloc locked so the pagechainhead is kosher */ void mmurelease(Proc* p) { Page *pg, *next; /* write back dirty cache entries before changing map */ cacheflush(); mmuptefree(p); for(pg = p->mmufree; pg; pg = next){ next = pg->next; | |
| 2000/1011 | if(--pg->ref) panic("mmurelease: pg->ref %d\n", pg->ref); pagechainhead(pg); | |
| 2000/1013 |
| |
| 2000/1011 | } | |
| 2000/1015 | if(p->mmufree && palloc.r.p) wakeup(&palloc.r); p->mmufree = nil; memset(l1table, 0, sizeof(p->l1table)); | |
| 2000/0902 | } void | |
| 2000/1011 | mmuswitch(Proc* p) | |
| 2000/0902 | { | |
| 2000/1014 |
| |
| 2000/1015 | if(p->newtlb){ mmuptefree(p); p->newtlb = 0; } /* write back dirty cache entries before changing map */ cacheflush(); /* move in new map */ | |
| 2000/1014 | memmove(l1table, p->l1table, sizeof(p->l1table)); | |
| 2000/1015 | /* make sure map is in memory and drain write buffer */ cacheflushaddr((ulong)l1table); | |
| 2000/1014 | wbflush(); | |
| 2000/1015 | /* lose any possible stale tlb entries */ mmuinvalidate(); } void flushmmu(void) { int s; s = splhi(); up->newtlb = 1; mmuswitch(up); splx(s); | |
| 2000/1014 | } void | |
| 2000/1015/sys/src/9/bitsy/mmu.c:222,251 – 2000/1016/sys/src/9/bitsy/mmu.c:222,256 (short | long) | ||
| 2000/0905 | void | |
| 2000/0902 | putmmu(ulong va, ulong pa, Page*) { | |
| 2000/1011 |
| |
| 2000/1016 | Page *pg; | |
| 2000/1011 | ulong *t; | |
| 2000/1015 |
| |
| 2000/1016 | print("putmmu(0x%.8lux, 0x%.8lux)\n", va, pa); | |
| 2000/1011 | /* always point L1 entry to L2 page, can't hurt */ | |
| 2000/1013 |
| |
| 2000/1011 |
| |
| 2000/1013 |
| |
| 2000/1014 |
| |
| 2000/1016 | pg = up->l1page[va>>20]; if(pg == nil){ pg = up->mmufree; if(pg != nil){ up->mmufree = pg->next; } else { pg = auxpage(); if(pg == nil) pexit("out of memory", 1); } pg->va = VA(kmap(pg)); up->l1page[va>>20] = pg; memset((uchar*)(pg->va), 0, BY2PG); | |
| 2000/1011 | } | |
| 2000/1013 |
| |
| 2000/1016 | l1table[va>>20] = L1PageTable | L1Domain0 | (pg->pa & L1PTBaseMask); | |
| 2000/1015 | cacheflushaddr((ulong)&l1table[va>>20]); | |
| 2000/1016 | print("%lux[%lux] = %lux\n", l1table, va>>20, l1table[va>>20]); | |
| 2000/1013 | up->l1table[va>>20] = l1table[va>>20]; | |
| 2000/1011 |
| |
| 2000/1016 | t = (ulong*)pg->va; | |
| 2000/1011 | /* set L2 entry */ | |
| 2000/1013 | t[(va & (OneMeg-1))>>PGSHIFT] = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)] | |
| 2000/1011 | | (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)); | |
| 2000/1015 |
| |
| 2000/1016 | print("%lux[%lux] = %lux\n", (ulong)t, (va & (OneMeg-1))>>PGSHIFT, t[(va & (OneMeg-1))>>PGSHIFT]); | |
| 2000/1015 | cacheflushaddr((ulong)&t[(va & (OneMeg-1))>>PGSHIFT]); | |
| 2000/1011 | ||
| 2000/1014 | wbflush(); | |
| 2000/1015/sys/src/9/bitsy/mmu.c:298,305 – 2000/1016/sys/src/9/bitsy/mmu.c:303,314 | ||
| 2000/0902 | } void | |
| 2000/1011 |
| |
| 2000/1016 | mmuswitch(Proc *p) | |
| 2000/0902 | { | |
| 2000/1016 | if(m->mmupid == p->pid && p->newtlb == 0) return; m->mmupid = p->pid; | |
| 2000/1015 | if(p->newtlb){ mmuptefree(p); p->newtlb = 0; | |
| 2000/1016/sys/src/9/bitsy/mmu.c:220,259 – 2000/1018/sys/src/9/bitsy/mmu.c:220,276 (short | long) | ||
| 2000/1011 | * add an entry to the current map */ | |
| 2000/0905 | void | |
| 2000/0902 |
| |
| 2000/1018 | putmmu(ulong va, ulong pa, Page *pg) | |
| 2000/0902 | { | |
| 2000/1016 |
| |
| 2000/1011 |
| |
| 2000/1018 | Page *l2pg; ulong *t, *l1p, *l2p; int s; | |
| 2000/1011 | ||
| 2000/1016 |
| |
| 2000/1011 |
| |
| 2000/1016 |
| |
| 2000/1018 | s = splhi(); /* clear out the current entry */ mmuinvalidateaddr(va); l2pg = up->l1page[va>>20]; if(l2pg == nil){ l2pg = up->mmufree; if(l2pg != nil){ up->mmufree = l2pg->next; | |
| 2000/1016 | } else { | |
| 2000/1018 | l2pg = auxpage(); if(l2pg == nil) | |
| 2000/1016 | pexit("out of memory", 1); } | |
| 2000/1018 | l2pg->va = VA(kmap(l2pg)); up->l1page[va>>20] = l2pg; memset((uchar*)(l2pg->va), 0, BY2PG); | |
| 2000/1011 | } | |
| 2000/1016 |
| |
| 2000/1015 |
| |
| 2000/1016 |
| |
| 2000/1013 |
| |
| 2000/1016 |
| |
| 2000/1011 | ||
| 2000/1018 | /* always point L1 entry to L2 page, can't hurt */ l1p = &l1table[va>>20]; *l1p = L1PageTable | L1Domain0 | (l2pg->pa & L1PTBaseMask); up->l1table[va>>20] = *l1p; t = (ulong*)l2pg->va; | |
| 2000/1011 | /* set L2 entry */ | |
| 2000/1013 |
| |
| 2000/1018 | l2p = &t[(va & (OneMeg-1))>>PGSHIFT]; *l2p = mmubits[pa & (PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)] | |
| 2000/1011 | | (pa & ~(PTEKERNEL|PTEVALID|PTEUNCACHED|PTEWRITE)); | |
| 2000/1016 |
| |
| 2000/1015 |
| |
| 2000/1011 | ||
| 2000/1014 |
| |
| 2000/1018 | /* write back dirty entries - we need this because the pio() in * fault.c is writing via a different virt addr and won't clean * its changes out of the dcache. Page coloring doesn't work * on this mmu because the virtual cache is set associative * rather than direct mapped. */ cachewb(); if(pg->cachectl[0] == PG_TXTFLUSH){ /* pio() sets PG_TXTFLUSH whenever a text page has been written */ icacheinvalidate(); pg->cachectl[0] = PG_NOFLUSH; } splx(s); | |
| 2000/0902 | } | |
| 2000/1011 | /* | |
| 2000/1016/sys/src/9/bitsy/mmu.c:300,305 – 2000/1018/sys/src/9/bitsy/mmu.c:317,323 | ||
| 2000/1015 | p->mmufree = nil; memset(l1table, 0, sizeof(p->l1table)); | |
| 2000/1018 | cachewbregion(l1table, sizeof(p->l1table)); | |
| 2000/0902 | } void | |
| 2000/1016/sys/src/9/bitsy/mmu.c:309,328 – 2000/1018/sys/src/9/bitsy/mmu.c:327,345 | ||
| 2000/1016 | return; m->mmupid = p->pid; | |
| 2000/1018 | /* write back dirty cache entries and invalidate all cache entries */ cacheflush(); | |
| 2000/1015 | if(p->newtlb){ mmuptefree(p); p->newtlb = 0; } | |
| 2000/1014 | memmove(l1table, p->l1table, sizeof(p->l1table)); | |
| 2000/1015 |
| |
| 2000/1014 |
| |
| 2000/1018 | /* make sure map is in memory */ cachewbregion(l1table, sizeof(p->l1table)); | |
| 2000/1015 | /* lose any possible stale tlb entries */ mmuinvalidate(); | |
| 2000/1018/sys/src/9/bitsy/mmu.c:127,138 – 2000/1019/sys/src/9/bitsy/mmu.c:127,138 (short | long) | ||
| 2000/0907 | { ulong *t; | |
| 2000/0928 | ulong va, i, base, end, off, entry; | |
| 2000/0924 |
| |
| 2000/1019 | int large; | |
| 2000/0924 | ulong* rv; | |
| 2000/0907 | ||
| 2000/0924 | rv = nil; | |
| 2000/1019 | large = len >= 128*1024; if(large){ | |
| 2000/0924 | base = pa & ~(OneMeg-1); end = (pa+len-1) & ~(OneMeg-1); } else { | |
| 2000/1018/sys/src/9/bitsy/mmu.c:145,151 – 2000/1019/sys/src/9/bitsy/mmu.c:145,151 | ||
| 2000/0929 | switch(l1table[va>>20] & L1TypeMask){ default: | |
| 2000/0924 | /* found unused entry on level 1 table */ | |
| 2000/1019 | if(large){ | |
| 2000/0924 | if(rv == nil) | |
| 2000/0929 | rv = (ulong*)(va+off); | |
| 2000/1011 | l1table[va>>20] = L1Section | L1KernelRW | L1Domain0 | | |
| 2000/1018/sys/src/9/bitsy/mmu.c:171,177 – 2000/1019/sys/src/9/bitsy/mmu.c:171,177 | ||
| 2000/1011 | ||
| 2000/0929 | continue; case L1PageTable: | |
| 2000/1019 | if(large) | |
| 2000/0929 | continue; break; | |
| 2000/0907 | } | |
| 2000/1018/sys/src/9/bitsy/mmu.c:178,184 – 2000/1019/sys/src/9/bitsy/mmu.c:178,184 | ||
| 2000/0924 | ||
| 2000/0929 | /* here if we're using page maps instead of sections */ | |
| 2000/0924 | t = (ulong*)(l1table[va>>20] & L1PTBaseMask); | |
| 2000/0907 |
| |
| 2000/1019 | for(i = 0; i < OneMeg && base <= end; i += BY2PG){ | |
| 2000/0924 | entry = t[i>>PGSHIFT]; | |
| 2000/0921 | ||
| 2000/0924 | /* found unused entry on level 2 table */ | |
| 2000/1018/sys/src/9/bitsy/mmu.c:196,201 – 2000/1019/sys/src/9/bitsy/mmu.c:196,202 | ||
| 2000/0924 | /* didn't fit */ if(base <= end) return nil; | |
| 2000/1019 | cacheflush(); | |
| 2000/0924 | return rv; | |
| 2000/0905 | } | |
| 2000/1018/sys/src/9/bitsy/mmu.c:359,381 – 2000/1019/sys/src/9/bitsy/mmu.c:360,382 | ||
| 2000/1014 | void peekmmu(ulong va) { | |
| 2000/1019 | ulong e, d; | |
| 2000/1014 | e = l1table[va>>20]; switch(e & L1TypeMask){ default: | |
| 2000/1019 | iprint("l1: %lux[%lux] = %lux invalid\n", l1table, va>>20, e); | |
| 2000/1014 | break; case L1PageTable: | |
| 2000/1019 | iprint("l1: %lux[%lux] = %lux pt\n", l1table, va>>20, e); | |
| 2000/1014 | va &= OneMeg-1; va >>= PGSHIFT; e &= L1PTBaseMask; | |
| 2000/1019 | d = ((ulong*)e)[va]; iprint("l2: %lux[%lux] = %lux\n", e, va, d); | |
| 2000/1014 | break; case L1Section: | |
| 2000/1019 | iprint("l1: %lux[%lux] = %lux section\n", l1table, va>>20, e); | |
| 2000/1014 | break; } | |
| 2000/0902 | } | |
| 2000/1019/sys/src/9/bitsy/mmu.c:318,324 – 2000/1106/sys/src/9/bitsy/mmu.c:318,324 (short | long) | ||
| 2000/1015 | p->mmufree = nil; memset(l1table, 0, sizeof(p->l1table)); | |
| 2000/1018 |
| |
| 2000/1106 | cachewbregion((ulong)l1table, sizeof(p->l1table)); | |
| 2000/0902 | } void | |
| 2000/1019/sys/src/9/bitsy/mmu.c:340,346 – 2000/1106/sys/src/9/bitsy/mmu.c:340,346 | ||
| 2000/1014 | memmove(l1table, p->l1table, sizeof(p->l1table)); | |
| 2000/1015 | ||
| 2000/1018 | /* make sure map is in memory */ | |
| 2000/1106 | cachewbregion((ulong)l1table, sizeof(p->l1table)); | |
| 2000/1015 | /* lose any possible stale tlb entries */ mmuinvalidate(); | |
| 2000/1106/sys/src/9/bitsy/mmu.c:51,58 – 2000/1118/sys/src/9/bitsy/mmu.c:51,58 (short | long) | ||
| 2000/0906 | }; | |
| 2000/0907 | ulong *l1table; | |
| 2000/1118 | static int mmuinited; | |
| 2000/0906 | ||
| 2000/1007 | ||
| 2000/0906 | /* * We map all of memory, flash, and the zeros area with sections. * Special use space is mapped on the fly with regmap. | |
| 2000/1106/sys/src/9/bitsy/mmu.c:67,73 – 2000/1118/sys/src/9/bitsy/mmu.c:67,73 | ||
| 2000/1007 | l1table = xspanalloc(16*1024, 16*1024, 0); memset(l1table, 0, 16*1024); | |
| 2000/0906 | ||
| 2000/1013 |
| |
| 2000/1118 | /* map low mem (I really don't know why I have to do this -- presotto) */ | |
| 2000/1013 | for(o = 0; o < 1*OneMeg; o += OneMeg) l1table[(0+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | |
| 2000/1106/sys/src/9/bitsy/mmu.c:74,94 – 2000/1118/sys/src/9/bitsy/mmu.c:74,93 | ||
| 2000/1013 | | ((0+o)&L1SectBaseMask); | |
| 2000/1011 | /* map DRAM */ | |
| 2000/1013 |
| |
| 2000/1118 | for(o = 0; o < DRAMTOP-DRAMZERO; o += OneMeg) | |
| 2000/1011 | l1table[(DRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0 | L1Cached | L1Buffered | ((PHYSDRAM0+o)&L1SectBaseMask); | |
| 2000/0907 | ||
| 2000/1011 | /* map zeros area */ | |
| 2000/1118 | for(o = 0; o < NULLTOP-NULLZERO; o += OneMeg) | |
| 2000/1011 | l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | |
| 2000/1015 | | L1Cached | L1Buffered | |
| 2000/1011 | | ((PHYSNULL0+o)&L1SectBaseMask); | |
| 2000/0907 | ||
| 2000/1011 | /* map flash */ | |
| 2000/1118 | for(o = 0; o < FLASHTOP-FLASHZERO; o += OneMeg) | |
| 2000/1011 | l1table[(FLASHZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | |
| 2000/0907 | ||
| 2000/1011 | /* map peripheral control module regs */ | |
| 2000/1106/sys/src/9/bitsy/mmu.c:117,129 – 2000/1118/sys/src/9/bitsy/mmu.c:116,130 | ||
| 2000/1015 | mmuinvalidate(); | |
| 2000/0929 | mmuenable(); | |
| 2000/1015 | cacheflush(); | |
| 2000/1118 | mmuinited = 1; | |
| 2000/0907 | } /* | |
| 2000/0923 |
| |
| 2000/1118 | * map on request | |
| 2000/0907 | */ | |
| 2000/1002 |
| |
| 2000/0924 |
| |
| 2000/1118 | static void* _map(ulong pa, int len, ulong zero, ulong top, ulong l1prop, ulong l2prop) | |
| 2000/0907 | { ulong *t; | |
| 2000/0928 | ulong va, i, base, end, off, entry; | |
| 2000/1106/sys/src/9/bitsy/mmu.c:141,147 – 2000/1118/sys/src/9/bitsy/mmu.c:142,148 | ||
| 2000/0924 | } off = pa - base; | |
| 2000/0921 | ||
| 2000/0929 |
| |
| 2000/1118 | for(va = zero; va < top && base <= end; va += OneMeg){ | |
| 2000/0929 | switch(l1table[va>>20] & L1TypeMask){ default: | |
| 2000/0924 | /* found unused entry on level 1 table */ | |
| 2000/1106/sys/src/9/bitsy/mmu.c:148,154 – 2000/1118/sys/src/9/bitsy/mmu.c:149,155 | ||
| 2000/1019 | if(large){ | |
| 2000/0924 | if(rv == nil) | |
| 2000/0929 | rv = (ulong*)(va+off); | |
| 2000/1011 |
| |
| 2000/1118 | l1table[va>>20] = L1Section | l1prop | L1Domain0 | | |
| 2000/0929 | (base & L1SectBaseMask); | |
| 2000/0924 | base += OneMeg; continue; | |
| 2000/1106/sys/src/9/bitsy/mmu.c:166,172 – 2000/1118/sys/src/9/bitsy/mmu.c:167,173 | ||
| 2000/1011 | entry = l1table[va>>20]; i = entry & L1SectBaseMask; if(pa >= i && (pa+len) <= i + OneMeg) | |
| 2000/1118 | if((entry & ~L1SectBaseMask) == (L1Section | l1prop | L1Domain0)) | |
| 2000/1011 | return (void*)(va + (pa & (OneMeg-1))); | |
| 2000/0929 | continue; | |
| 2000/1106/sys/src/9/bitsy/mmu.c:185,191 – 2000/1118/sys/src/9/bitsy/mmu.c:186,192 | ||
| 2000/0924 | if((entry & L2TypeMask) != L2SmallPage){ if(rv == nil) | |
| 2000/0929 | rv = (ulong*)(va+i+off); | |
| 2000/0924 |
| |
| 2000/1118 | t[i>>PGSHIFT] = L2SmallPage | l2prop | | |
| 2000/0924 | (base & L2PageBaseMask); base += BY2PG; continue; | |
| 2000/1106/sys/src/9/bitsy/mmu.c:199,204 – 2000/1118/sys/src/9/bitsy/mmu.c:200,308 | ||
| 2000/1019 | cacheflush(); | |
| 2000/0924 | return rv; | |
| 2000/1118 | } /* map in i/o registers */ void* mapspecial(ulong pa, int len) { return _map(pa, len, REGZERO, REGTOP, L1KernelRW, L2KernelRW); } /* map add on memory */ void* mapmem(ulong pa, int len) { return _map(pa, len, EMEMZERO, EMEMTOP, L1KernelRW|L1Cached|L1Buffered, L2KernelRW|L2Cached|L2Buffered); } /* map a virtual address to a physical one */ ulong mmu_paddr(ulong va) { ulong entry; ulong *t; entry = l1table[va>>20]; switch(entry & L1TypeMask){ case L1Section: return (entry & L1SectBaseMask) | (va & (OneMeg-1)); case L1PageTable: t = (ulong*)(entry & L1PTBaseMask); va &= OneMeg-1; entry = t[va>>PGSHIFT]; switch(entry & L1TypeMask){ case L2SmallPage: return (entry & L2PageBaseMask) | (va & (BY2PG-1)); } } return 0; } /* map a physical address to a virtual one */ static ulong findva(ulong pa, ulong zero, ulong top) { int i; ulong entry, va; ulong start, end; ulong *t; for(va = zero; va < top; va += OneMeg){ /* search the L1 entry */ entry = l1table[va>>20]; switch(entry & L1TypeMask){ default: return 0; /* no holes */ case L1Section: start = entry & L1SectBaseMask; end = start + OneMeg; if(pa >= start && pa < end) return va | (pa & (OneMeg-1)); continue; case L1PageTable: break; } /* search the L2 entry */ t = (ulong*)(l1table[va>>20] & L1PTBaseMask); for(i = 0; i < OneMeg; i += BY2PG){ entry = t[i>>PGSHIFT]; /* found unused entry on level 2 table */ if((entry & L2TypeMask) != L2SmallPage) break; start = entry & L2PageBaseMask; end = start + BY2PG; if(pa >= start && pa < end) return va | (BY2PG*i) | (pa & (BY2PG-1)); } } return 0; } ulong mmu_kaddr(ulong pa) { ulong va; /* try the easy stuff first (the first case is true most of the time) */ if(pa >= PHYSDRAM0 && pa <= PHYSDRAM0+(DRAMTOP-DRAMZERO)) return DRAMZERO+(pa-PHYSDRAM0); if(pa >= PHYSFLASH0 && pa <= PHYSFLASH0+(FLASHTOP-FLASHZERO)) return FLASHZERO+(pa-PHYSFLASH0); if(pa >= PHYSNULL0 && pa <= PHYSNULL0+(NULLTOP-NULLZERO)) return NULLZERO+(pa-PHYSNULL0); if(!mmuinited) return 0; /* this shouldn't happen */ /* walk the map for the special regs and extended memory */ va = findva(pa, EMEMZERO, EMEMTOP); if(va != 0) return va; return findva(pa, REGZERO, REGTOP); | |
| 2000/0905 | } | |
| 2000/1011 | /* | |
| 2000/1118/sys/src/9/bitsy/mmu.c:211,220 – 2000/1121/sys/src/9/bitsy/mmu.c:211,228 (short | long) | ||
| 2000/1118 | /* map add on memory */ void* | |
| 2000/1121 | mapmem(ulong pa, int len, int cached) | |
| 2000/1118 | { | |
| 2000/1121 | ulong l1, l2; if(cached){ l1 = L1KernelRW|L1Cached|L1Buffered; l2 = L2KernelRW|L2Cached|L2Buffered; } else { l1 = L1KernelRW; l2 = L2KernelRW; } return _map(pa, len, EMEMZERO, EMEMTOP, l1, l2); | |
| 2000/1118 | } /* map a virtual address to a physical one */ | |
| 2000/1121/sys/src/9/bitsy/mmu.c:79,84 – 2000/1130/sys/src/9/bitsy/mmu.c:79,89 (short | long) | ||
| 2000/1011 | | L1Cached | L1Buffered | ((PHYSDRAM0+o)&L1SectBaseMask); | |
| 2000/0907 | ||
| 2000/1130 | /* uncached DRAM */ for(o = 0; o < UCDRAMTOP-UCDRAMZERO; o += OneMeg) l1table[(UCDRAMZERO+o)>>20] = L1Section | L1KernelRW| L1Domain0 | ((PHYSDRAM0+o)&L1SectBaseMask); | |
| 2000/1011 | /* map zeros area */ | |
| 2000/1118 | for(o = 0; o < NULLTOP-NULLZERO; o += OneMeg) | |
| 2000/1011 | l1table[(NULLZERO+o)>>20] = L1Section | L1KernelRW | L1Domain0 | |
| Too many diffs (26 > 25). Stopping. | ||