diff options
| author | Patrick Williams <iawillia@us.ibm.com> | 2011-07-08 19:33:40 -0500 |
|---|---|---|
| committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2011-07-20 14:58:43 -0500 |
| commit | 471f09f1a9bcc46fc385fa8aca776cb682075c0b (patch) | |
| tree | e0a4969825799dcc4c28a71975cb68439f507390 /src/kernel | |
| parent | 3ecf7085ccc55eb4f815a62f47ea09f55bb6688e (diff) | |
| download | blackbird-hostboot-471f09f1a9bcc46fc385fa8aca776cb682075c0b.tar.gz blackbird-hostboot-471f09f1a9bcc46fc385fa8aca776cb682075c0b.zip | |
VMM Improvements.
- Segment Manager
- Base / Device Segments
- Block for Base image.
Change-Id: Ic0c058e5c5b210ec1c48d30f6ed9f9837d74a3c8
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/193
Tested-by: Jenkins Server
Reviewed-by: MATTHEW S. BARTH <msbarth@us.ibm.com>
Diffstat (limited to 'src/kernel')
| -rw-r--r-- | src/kernel/basesegment.C | 57 | ||||
| -rw-r--r-- | src/kernel/block.C | 109 | ||||
| -rw-r--r-- | src/kernel/devicesegment.C | 91 | ||||
| -rw-r--r-- | src/kernel/exception.C | 26 | ||||
| -rw-r--r-- | src/kernel/heapmgr.C | 3 | ||||
| -rw-r--r-- | src/kernel/makefile | 4 | ||||
| -rw-r--r-- | src/kernel/pagemgr.C | 1 | ||||
| -rw-r--r-- | src/kernel/ptmgr.C | 66 | ||||
| -rw-r--r-- | src/kernel/segmentmgr.C | 76 | ||||
| -rw-r--r-- | src/kernel/taskmgr.C | 2 | ||||
| -rw-r--r-- | src/kernel/vmmmgr.C | 193 |
11 files changed, 419 insertions, 209 deletions
diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C new file mode 100644 index 000000000..70d91ac72 --- /dev/null +++ b/src/kernel/basesegment.C @@ -0,0 +1,57 @@ +#include <limits.h> +#include <util/singleton.H> + +#include <kernel/basesegment.H> +#include <kernel/segmentmgr.H> +#include <kernel/block.H> +#include <kernel/vmmmgr.H> + +BaseSegment::~BaseSegment() +{ + delete iv_block; +} + +void BaseSegment::init() +{ + Singleton<BaseSegment>::instance()._init(); +} + +void BaseSegment::_init() +{ + // Assign segment to segment manager. + SegmentManager::addSegment(this, SegmentManager::BASE_SEGMENT_ID); + + // Create initial static 8MB block. + iv_block = new Block(0x0, 0x800000); + iv_block->setParent(this); + + // Set default page permissions on block. + for (uint64_t i = 0; i < 0x800000; i += PAGESIZE) + { + // External address filled in by linker as start of kernel's + // data pages. + extern void* data_load_address; + + // Don't map in the 0 (NULL) page. + if (i == 0) continue; + + // Set pages in kernel text section to be read-only / executable. + if (((uint64_t)&data_load_address) > i) + { + iv_block->setPhysicalPage(i, i, VmmManager::RO_EXE_ACCESS); + } + // Set all other pages to initially be read/write. VFS will set + // permissions on pages outside kernel. + // (@TODO: Future Sprint, for now keep NORMAL_ACCESS as RWX, not RW.) + else + { + iv_block->setPhysicalPage(i, i, VmmManager::NORMAL_ACCESS); + } + } +} + +bool BaseSegment::handlePageFault(task_t* i_task, uint64_t i_addr) +{ + // Tail recursion to block chain. + return iv_block->handlePageFault(i_task, i_addr); +} diff --git a/src/kernel/block.C b/src/kernel/block.C new file mode 100644 index 000000000..25157dac5 --- /dev/null +++ b/src/kernel/block.C @@ -0,0 +1,109 @@ +#include <limits.h> +#include <assert.h> + +#include <kernel/block.H> +#include <kernel/spte.H> +#include <kernel/vmmmgr.H> +#include <kernel/ptmgr.H> + +Block::~Block() +{ + // Release shadow PTE array. + delete[] iv_ptes; + + // Delete next block in the chain. + if (iv_nextBlock) + { + delete iv_nextBlock; + } +} + +void Block::init() +{ + // Create a shadow PTE for each page. + iv_ptes = new ShadowPTE[iv_size / PAGESIZE]; +} + +ShadowPTE* Block::getPTE(uint64_t i_addr) const +{ + return &iv_ptes[(i_addr - iv_baseAddr) / PAGESIZE]; +}; + +bool Block::handlePageFault(task_t* i_task, uint64_t i_addr) +{ + // Check containment, call down chain if address isn't in this block. + if (!isContained(i_addr)) + { + return (iv_nextBlock ? + false : iv_nextBlock->handlePageFault(i_task, i_addr)); + } + + ShadowPTE* pte = getPTE(i_addr); + + if (!pte->isPresent()) + { + // TODO. Needs swapping support. + return false; + } + + if (pte->getPage() == 0) + { + return false; + } + + // Add page table entry. + PageTableManager::addEntry( + (i_addr / PAGESIZE) * PAGESIZE, + pte->getPage(), + (pte->isExecutable() ? VmmManager::RO_EXE_ACCESS : + (pte->isWritable() ? VmmManager::NORMAL_ACCESS : + VmmManager::READ_O_ACCESS))); + + return true; + +} + +void Block::setPhysicalPage(uint64_t i_vAddr, uint64_t i_pAddr, + VmmManager::ACCESS_TYPES i_access) +{ + // Check containment, call down chain if address isn't in this block. + if (!isContained(i_vAddr)) + { + if (iv_nextBlock) + { + iv_nextBlock->setPhysicalPage(i_vAddr, i_pAddr, i_access); + } + else + { + // No block owns this address. Code bug. + kassert(iv_nextBlock); + } + return; + } + + // Create virtual to physical mapping. + ShadowPTE* pte = getPTE(i_vAddr); + pte->setPageAddr(i_pAddr); + pte->setPresent(true); + switch(i_access) + { + case VmmManager::READ_O_ACCESS: + pte->setExecutable(false); + pte->setWritable(false); + break; + + case VmmManager::NORMAL_ACCESS: + pte->setExecutable(false); + pte->setWritable(true); + break; + + case VmmManager::RO_EXE_ACCESS: + pte->setExecutable(true); + pte->setWritable(false); + break; + + default: + kassert(false); + break; + } +} diff --git a/src/kernel/devicesegment.C b/src/kernel/devicesegment.C new file mode 100644 index 000000000..446d17298 --- /dev/null +++ b/src/kernel/devicesegment.C @@ -0,0 +1,91 @@ +#include <util/singleton.H> +#include <limits.h> + +#include <kernel/vmmmgr.H> +#include <kernel/ptmgr.H> +#include <kernel/devicesegment.H> +#include <kernel/segmentmgr.H> + +#define SLBE_s 40 + +#include <kernel/console.H> + +void DeviceSegment::init() +{ + Singleton<DeviceSegment>::instance()._init(); +} + +void* DeviceSegment::mmioMap(void* ra, size_t pages) +{ + return Singleton<DeviceSegment>::instance()._mmioMap(ra, pages); +} + +int DeviceSegment::mmioUnmap(void* ea, size_t pages) +{ + return Singleton<DeviceSegment>::instance()._mmioUnmap(ea, pages); +} + +void DeviceSegment::_init() +{ + SegmentManager::addSegment(this, SegmentManager::MMIO_SEGMENT_ID); +} + +bool DeviceSegment::handlePageFault(task_t* i_task, uint64_t i_addr) +{ + // Check address range. + if (i_addr < this->getBaseAddress() || + i_addr >= (this->getBaseAddress() + 0x010000000000ull)) + { + return false; + } + + // Check valid device. + uint64_t segment_ea = i_addr - this->getBaseAddress(); + size_t idx = segment_ea / ((1ull << SLBE_s) / MMIO_MAP_DEVICES); + uint64_t device_offset = segment_ea - + (idx * (1ull << SLBE_s) / MMIO_MAP_DEVICES); + + if (0 == iv_mmioMap[idx]) + { + return false; + } + + PageTableManager::addEntry((i_addr / PAGESIZE) * PAGESIZE, + (iv_mmioMap[idx] + device_offset) / PAGESIZE, + VmmManager::CI_ACCESS); + return true; +} + +void* DeviceSegment::_mmioMap(void* ra, size_t pages) +{ + for (size_t i = 0; i < MMIO_MAP_DEVICES; i++) + { + if (0 == iv_mmioMap[i]) + { + iv_mmioMap[i] = reinterpret_cast<uint64_t>(ra); + return reinterpret_cast<void*>(i * + ((1ull << SLBE_s) / MMIO_MAP_DEVICES) + + this->getBaseAddress()); + } + } + + return NULL; +} + +int DeviceSegment::_mmioUnmap(void* ea, size_t pages) +{ + uint64_t segment_ea = reinterpret_cast<uint64_t>(ea) - + this->getBaseAddress(); + size_t idx = segment_ea / ((1ull << SLBE_s) / MMIO_MAP_DEVICES); + if (0 != iv_mmioMap[idx]) + { + PageTableManager::delRangePN(iv_mmioMap[idx] / PAGESIZE, + iv_mmioMap[idx] / PAGESIZE + + pages); + iv_mmioMap[idx] = 0; + return 0; + } + + return -1; +} + diff --git a/src/kernel/exception.C b/src/kernel/exception.C index cbbf3cf89..b12914fe8 100644 --- a/src/kernel/exception.C +++ b/src/kernel/exception.C @@ -47,12 +47,12 @@ void kernel_execute_data_storage() switch(exception) { case EXCEPTION_DSISR_PTEMISS: - handled = VmmManager::pteMiss(t); + handled = VmmManager::pteMiss(t, getDAR()); break; } if (!handled) { - printk("Data Storage exception on %d: %lx, %lx\n", + printk("Data Storage exception on %d: %lx, %lx\n", t->tid, getDAR(), getDSISR()); Systemcalls::TaskEnd(t); } @@ -66,12 +66,28 @@ void kernel_execute_data_segment() Systemcalls::TaskEnd(t); } +const uint64_t EXCEPTION_SRR1_INSTR_MASK = 0x0000000040000000; +const uint64_t EXCEPTION_SRR1_INSTR_PTEMISS = 0x0000000040000000; + extern "C" void kernel_execute_inst_storage() { task_t* t = TaskManager::getCurrentTask(); - printk("Inst Storage exception, killing task %d\n", t->tid); - Systemcalls::TaskEnd(t); + uint64_t exception = getSRR1() & EXCEPTION_SRR1_INSTR_MASK; + + bool handled = false; + switch (exception) + { + case EXCEPTION_SRR1_INSTR_PTEMISS: + handled = VmmManager::pteMiss(t, getSRR0()); + break; + } + if (!handled) + { + printk("Inst Storage exception on %d: %lx, %lx\n", + t->tid, getSRR0(), getSRR1()); + Systemcalls::TaskEnd(t); + } } extern "C" @@ -103,7 +119,7 @@ namespace ExceptionHandles // check for mfsprg3 if ((instruction & 0xfc1fffff) == 0x7c1342a6) { - t->context.gprs[(instruction & 0x03E00000) >> 21] = + t->context.gprs[(instruction & 0x03E00000) >> 21] = (uint64_t) t; t->context.nip = (void*) (((uint64_t)t->context.nip)+4); return true; diff --git a/src/kernel/heapmgr.C b/src/kernel/heapmgr.C index cac6999b5..8bd31bd5f 100644 --- a/src/kernel/heapmgr.C +++ b/src/kernel/heapmgr.C @@ -1,3 +1,4 @@ +#include <limits.h> #include <kernel/heapmgr.H> #include <util/singleton.H> #include <kernel/console.H> @@ -79,7 +80,7 @@ void HeapManager::newPage() { void* page = PageManager::allocatePage(); chunk_t * c = (chunk_t*)page; - for (int i = 0; i < (PageManager::PAGESIZE / (1 << (BUCKETS + 3))); i++) + for (int i = 0; i < (PAGESIZE / (1 << (BUCKETS + 3))); i++) { c->len = BUCKETS-1; push_bucket(c, BUCKETS-1); diff --git a/src/kernel/makefile b/src/kernel/makefile index fd64fd611..f3d58dee0 100644 --- a/src/kernel/makefile +++ b/src/kernel/makefile @@ -1,7 +1,9 @@ ROOTPATH = ../.. OBJS = start.o kernel.o console.o pagemgr.o heapmgr.o taskmgr.o cpumgr.o -OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o futexmgr.o ptmgr.o +OBJS += syscall.o scheduler.o spinlock.o exception.o vmmmgr.o timemgr.o +OBJS += futexmgr.o ptmgr.o segmentmgr.o devicesegment.o basesegment.o +OBJS += block.o include ${ROOTPATH}/config.mk diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C index 5d6637203..1570a97d3 100644 --- a/src/kernel/pagemgr.C +++ b/src/kernel/pagemgr.C @@ -1,3 +1,4 @@ +#include <limits.h> #include <kernel/pagemgr.H> #include <util/singleton.H> #include <kernel/console.H> diff --git a/src/kernel/ptmgr.C b/src/kernel/ptmgr.C index b4cce308a..536930322 100644 --- a/src/kernel/ptmgr.C +++ b/src/kernel/ptmgr.C @@ -6,8 +6,8 @@ #include <assert.h> //#define Dprintk(...) printk(args...) -#define Dprintk(args...) -#define Tprintk(args...) +#define Dprintk(args...) +#define Tprintk(args...) #define Eprintk(args...) printk(args) // Utilities to do some bit manipulation @@ -74,13 +74,13 @@ ALWAYS_INLINE uint64_t EXTRACT_RJ_LEN( uint64_t i_lastword, } else if( i_bitlen <= 64 ) { - uint64_t diff = 64 - i_bitlen; + uint64_t diff = 64 - i_bitlen; return EXTRACT_RJ( i_lastword, i_startbit + diff, i_lastbit + diff ); } else if( i_lastbit < (i_bitlen - 64) ) { // desired bits are inside the first word - return 0; + return 0; } // goal is to left-justify the i_startbit to be bit0 in the resulting word @@ -172,18 +172,18 @@ void PageTableManager::delEntry( uint64_t i_vAddr ) void PageTableManager::delRangeVA( uint64_t i_vAddrStart, uint64_t i_vAddrFinish ) { - return Singleton<PageTableManager>::instance()._delRangeVA(i_vAddrStart,i_vAddrFinish); -} + return Singleton<PageTableManager>::instance()._delRangeVA(i_vAddrStart,i_vAddrFinish); +} /** * STATIC * @brief Remove a range of entries from the hardware page table */ void PageTableManager::delRangePN( uint64_t i_pnStart, - uint64_t i_pnFinish ) + uint64_t i_pnFinish ) { - return Singleton<PageTableManager>::instance()._delRangePN(i_pnStart,i_pnFinish); -} + return Singleton<PageTableManager>::instance()._delRangePN(i_pnStart,i_pnFinish); +} /** @@ -193,7 +193,7 @@ void PageTableManager::delRangePN( uint64_t i_pnStart, uint64_t PageTableManager::getStatus( uint64_t i_vAddr, uint64_t& o_pn ) { - return Singleton<PageTableManager>::instance()._getStatus(i_vAddr,o_pn); + return Singleton<PageTableManager>::instance()._getStatus(i_vAddr,o_pn); } /** @@ -214,7 +214,7 @@ void PageTableManager::printPTE( const char* i_label, void PageTableManager::printPTE( uint64_t i_va, bool i_verbose ) { - PageTableEntry* pte = Singleton<PageTableManager>::instance().findPTE(i_va); + PageTableEntry* pte = Singleton<PageTableManager>::instance().findPTE(i_va); Singleton<PageTableManager>::instance().printPTE( NULL, pte, i_verbose ); } @@ -368,11 +368,11 @@ void PageTableManager::_delRangeVA( uint64_t i_vAddrStart, // Note : this could potentially be very slow for large ranges // loop around 4K pages within the range - for( uint64_t va = i_vAddrStart; va < i_vAddrFinish; va += VmmManager::PAGESIZE ) + for( uint64_t va = i_vAddrStart; va < i_vAddrFinish; va += PAGESIZE ) { _delEntry( va ); } -} +} /** * @brief Remove a range of entries from the hardware page table @@ -395,7 +395,7 @@ void PageTableManager::_delRangePN( uint64_t i_pnStart, pte++; } -} +} /** * @brief Return status information about an entry in the hardware page table @@ -407,7 +407,7 @@ uint64_t PageTableManager::_getStatus( uint64_t i_vAddr, o_pn = INVALID_PN; if( pte ) { o_pn = pte->PN; - } + } return getStatus( pte ); } @@ -453,7 +453,7 @@ uint64_t PageTableManager::getStatus( PageTableEntry* i_pte ) if( i_pte->R == 1 ) { status |= PTE_ACCESSED; } - + return status; } @@ -522,7 +522,7 @@ uint64_t PageTableManager::findPTEG( uint64_t i_vAddr ) // use the hash as the index into the array of PTEGs uint64_t pteg_addr = getAddress() + hash * PTEG_SIZE_BYTES; - Dprintk( "PageTableManager::findPTEG(i_vAddr=0x%.16lX) = 0x%.16lX\n", i_vAddr, pteg_addr ); + Dprintk( "PageTableManager::findPTEG(i_vAddr=0x%.16lX) = 0x%.16lX\n", i_vAddr, pteg_addr ); return pteg_addr; } @@ -572,7 +572,7 @@ PageTableManager::PageTableEntry* PageTableManager::findPTE( uint64_t i_vAddr, } Dprintk( "<<PageTableManager::findPTE() = %.16lX>>\n", (uint64_t)pte_found ); - return pte_found; + return pte_found; } /** @@ -682,7 +682,7 @@ void PageTableManager::printPTE( const char* i_label, { printk( "[%4ld:%4ld]> @%p : %.16lX %.16lX : AVA=%16lX, PN=%ld\n", pte_num/PTEG_SIZE, pte_num%PTEG_SIZE, i_pte, i_pte->dword0, i_pte->dword1, i_pte->AVA, i_pte->PN ); } - + } @@ -716,7 +716,7 @@ void PageTableManager::_printPT( void ) uint64_t PageTableManager::getAddress( void ) { if(ivTABLE) { - return (uint64_t)ivTABLE; + return (uint64_t)ivTABLE; } else { return VmmManager::HTABORG; } @@ -739,15 +739,23 @@ void PageTableManager::setAccessBits( PageTableEntry* o_pte, o_pte->dword1 &= ~PTE_ACCESS_BITS; if( VmmManager::NO_USER_ACCESS == i_accessType ) { o_pte->WIMG = 0b0010; // Memory Coherency Required + o_pte->N = 0b1; // No Execute } else if( VmmManager::READ_O_ACCESS == i_accessType ) { o_pte->WIMG = 0b0010; // Memory Coherency Required o_pte->pp1_2 = 0b01; // PP=001 + o_pte->N = 0b1; // No Execute } else if( VmmManager::NORMAL_ACCESS == i_accessType ) { o_pte->WIMG = 0b0010; // Memory Coherency Required o_pte->pp1_2 = 0b10; // PP=010 + o_pte->N = 0b0; // @TODO Change to 'No Execute' when VFS supports. } else if( VmmManager::CI_ACCESS == i_accessType ) { o_pte->WIMG = 0b0101; // Cache Inhibited, Guarded o_pte->pp1_2 = 0b10; // PP=010 + o_pte->N = 0b1; // No Execute + } else if( VmmManager::RO_EXE_ACCESS == i_accessType ) { + o_pte->WIMG = 0b0010; // Memory Coherency Required + o_pte->pp1_2 = 0b01; // PP=001 + o_pte->N = 0b0; // Execute } else { //@fixme - add RO_EXE_ACCESS Eprintk( "** unrecognized access=%d\n", i_accessType ); @@ -795,7 +803,7 @@ void PageTableManager::setupDefaultPTE( PageTableEntry* o_pte ) o_pte->L = 0b0; //Virtual page size (1=>4KB) o_pte->H = 0b0; //Hash function identifier (0=primary hash) } - + /** * @brief Find the real address of a PTE that that is empty or invalid */ @@ -822,7 +830,7 @@ PageTableManager::PageTableEntry* PageTableManager::findEmptyPTE( uint64_t i_pte } Dprintk( "<<PageTableManager::findEmptyPTE() = %p>>\n", pte_slot ); - return pte_slot; + return pte_slot; } /** @@ -833,15 +841,15 @@ PageTableManager::PageTableEntry* PageTableManager::findOldPTE( uint64_t i_ptegA { // Order of preference for PTE slots to steal: // 1) PTE with highest use count (LRU==SW[2:3]) - // 2) Lowest PTE with the highest use count + // 2) Lowest PTE with the highest use count PageTableEntry* pte = (PageTableEntry*)i_ptegAddr; PageTableEntry* old_pte = pte; for( uint64_t x = 0; x < 8; x++ ) { if( pte->LRU > old_pte->LRU ) { - old_pte = pte; - } + old_pte = pte; + } pte++; } @@ -860,7 +868,7 @@ void PageTableManager::updateLRU( const PageTableEntry* i_newPTE ) // find the beginning of the PTEG uint64_t pteg_addr = (((uint64_t)i_newPTE) - getAddress()) / PTEG_SIZE_BYTES; pteg_addr = pteg_addr*PTEG_SIZE_BYTES + getAddress(); - + // loop through all 8 PTEs in the PTEG PageTableEntry* pte_cur = (PageTableEntry*)pteg_addr; for( uint64_t x = 0; x < 8; x++ ) @@ -894,7 +902,7 @@ void PageTableManager::updateLRU( const PageTableEntry* i_newPTE ) new_pte.dword0 ) ); // tlbie, eieio, tlbsync, ptesync - invalidateTLB(pte_cur); + invalidateTLB(pte_cur); } pte_cur++; @@ -922,10 +930,10 @@ void PageTableManager::invalidateTLB( PageTableEntry* i_pte ) "r"(rB), "r"(rS) : "memory"); /* order tlbie before tlbsync */ - asm volatile("eieio" ::: "memory"); + asm volatile("eieio" ::: "memory"); /* order tlbie before ptesync */ - asm volatile("tlbsync" ::: "memory"); + asm volatile("tlbsync" ::: "memory"); /* order tlbie, tlbsync and 1st update before 2nd update */ asm volatile("ptesync" ::: "memory"); diff --git a/src/kernel/segmentmgr.C b/src/kernel/segmentmgr.C new file mode 100644 index 000000000..fae9d3479 --- /dev/null +++ b/src/kernel/segmentmgr.C @@ -0,0 +1,76 @@ +#include <assert.h> +#include <arch/ppc.H> +#include <util/singleton.H> + +#include <kernel/segmentmgr.H> +#include <kernel/segment.H> + +bool SegmentManager::handlePageFault(task_t* i_task, uint64_t i_addr) +{ + return Singleton<SegmentManager>::instance(). + _handlePageFault(i_task, i_addr); +} + +void SegmentManager::addSegment(Segment* i_segment, size_t i_segId) +{ + Singleton<SegmentManager>::instance()._addSegment(i_segment, i_segId); +} + +void SegmentManager::initSLB() +{ + Singleton<SegmentManager>::instance()._initSLB(); +} + +bool SegmentManager::_handlePageFault(task_t* i_task, uint64_t i_addr) +{ + // This constant should come from page manager. Segment size. + const size_t SLBE_s = 40; + + // Get segment ID from effective address. + size_t segId = i_addr >> SLBE_s; + + // Call contained segment object to handle page fault. + if ((segId < MAX_SEGMENTS) && (NULL != iv_segments[segId])) + { + return iv_segments[segId]->handlePageFault(i_task, i_addr); + } + + return false; +} + +void SegmentManager::_addSegment(Segment* i_segment, size_t i_segId) +{ + kassert(i_segId < MAX_SEGMENTS); + iv_segments[i_segId] = i_segment; +} + +void SegmentManager::_initSLB() +{ + // Flush SLB. + asm volatile("slbia" ::: "memory"); + isync(); // Ensure slbia completes prior to slbmtes. + + register uint64_t slbRS, slbRB; + + // Default segment descriptors. + // ESID = 0, V = 1, Index = 1. + slbRB = 0x0000000008000001; + // B = 01 (1TB), VSID = 0, Ks = 0, Kp = 1, NLCLP = 0 + slbRS = 0x4000000000000400; + + // Add all segments to SLB. + for (size_t i = 0; i < MAX_SEGMENTS; i++) + { + // Add segment to SLB. + if (NULL != iv_segments[i]) + { + asm volatile("slbmte %0, %1" :: "r"(slbRS), "r"(slbRB) : "memory"); + } + + // Increment ESID, VSID, Index. + slbRB += 0x0000010000000001; + slbRS += 0x0000000001000000; + } + + isync(); // Ensure slbmtes complete prior to continuing on. +} diff --git a/src/kernel/taskmgr.C b/src/kernel/taskmgr.C index 8073c0b48..7d2454b6d 100644 --- a/src/kernel/taskmgr.C +++ b/src/kernel/taskmgr.C @@ -80,7 +80,7 @@ task_t* TaskManager::_createTask(TaskManager::task_fn_t t, task->context.stack_ptr = PageManager::allocatePage(TASK_DEFAULT_STACK_SIZE); memset(task->context.stack_ptr, '\0', - TASK_DEFAULT_STACK_SIZE * PAGE_SIZE); + TASK_DEFAULT_STACK_SIZE * PAGESIZE); task->context.gprs[1] = ((uint64_t)task->context.stack_ptr) + 16320; } else diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C index ba1191d90..98e5a0410 100644 --- a/src/kernel/vmmmgr.C +++ b/src/kernel/vmmmgr.C @@ -1,8 +1,12 @@ +#include <limits.h> #include <util/singleton.H> #include <kernel/vmmmgr.H> #include <kernel/console.H> #include <arch/ppc.H> #include <kernel/ptmgr.H> +#include <kernel/segmentmgr.H> +#include <kernel/devicesegment.H> +#include <kernel/basesegment.H> extern void* data_load_address; @@ -13,10 +17,13 @@ VmmManager::VmmManager() : lock() void VmmManager::init() { printk("Starting VMM...\n"); - + VmmManager& v = Singleton<VmmManager>::instance(); - v.initSLB(); + BaseSegment::init(); + DeviceSegment::init(); + SegmentManager::initSLB(); + v.initPTEs(); v.initSDR1(); @@ -26,46 +33,24 @@ void VmmManager::init() void VmmManager::init_slb() { VmmManager& v = Singleton<VmmManager>::instance(); - v.initSLB(); + SegmentManager::initSLB(); + v.initSDR1(); } -bool VmmManager::pteMiss(task_t* t) +bool VmmManager::pteMiss(task_t* t, uint64_t effAddr) { - return Singleton<VmmManager>::instance()._pteMiss(t); + return Singleton<VmmManager>::instance()._pteMiss(t, effAddr); } void* VmmManager::mmioMap(void* ra, size_t pages) { - return Singleton<VmmManager>::instance()._mmioMap(ra,pages); + return DeviceSegment::mmioMap(ra, pages); } int VmmManager::mmioUnmap(void* ea, size_t pages) { - return Singleton<VmmManager>::instance()._mmioUnmap(ea,pages); -} - -void VmmManager::initSLB() -{ - register uint64_t slbRS, slbRB; - - // ESID = 0, V = 1, Index = 1. - slbRB = 0x0000000008000001; - - // B = 01 (1TB), VSID = 0, Ks = 0, Kp = 1, NLCLP = 0 - slbRS = 0x4000000000000400; - - asm volatile("slbia" ::: "memory"); - asm volatile("isync" ::: "memory"); - asm volatile("slbmte %0, %1" :: "r"(slbRS), "r"(slbRB) : "memory"); - - // ESID = 2TB, V = 1, Index = 3 - slbRB = 0x0000020008000003; - // B = 01 (1TB), VSID = 2TB, Ks = 0, Kp = 1, NLCLP = 0 - slbRS = 0x4000020000000400; - - asm volatile("slbmte %0, %1" :: "r"(slbRS), "r"(slbRB) : "memory"); - asm volatile("isync" ::: "memory"); + return DeviceSegment::mmioUnmap(ea, pages); } void VmmManager::initPTEs() @@ -73,21 +58,8 @@ void VmmManager::initPTEs() // Initialize and invalidate the page table PageTableManager::init(); - // Set up linear map for every 4K page - for(size_t i = 0; i < (FULL_MEM_SIZE / PAGESIZE); i++) - { - ACCESS_TYPES access = NORMAL_ACCESS; - if (0 == i) - { - access = NO_USER_ACCESS; - } - else if (((uint64_t)&data_load_address) > (i * PAGESIZE)) - { - access = READ_O_ACCESS; - } - - PageTableManager::addEntry( i*PAGESIZE, i, access ); - } + // There is no need to add PTE entries because the PTE-miss page fault + // handler will add as-needed. } void VmmManager::initSDR1() @@ -97,138 +69,15 @@ void VmmManager::initSDR1() asm volatile("mtsdr1 %0" :: "r"(sdr1) : "memory"); } -bool VmmManager::_pteMiss(task_t* t) +bool VmmManager::_pteMiss(task_t* t, uint64_t effAddr) { lock.lock(); - uint64_t effAddr = getDAR(); - uint64_t effPid = effAddr / FULL_MEM_SIZE; - - - if (effPid <= LinearSpace) - { - lock.unlock(); - return false; // Should not get this exception in Linear space - // because it is all mapped in all the time. - } - - // Check for exception in MMIO vs Dynamic Stack space. - if (effPid <= MMIOSpace) - { - // Do MMIO mapping. - uint64_t effAddrPage = (effAddr - FULL_MEM_SIZE) / PAGESIZE; - - // Check for valid entry in MMIO map. - uint64_t mmioMapEntry = mmioMapT[effAddrPage]; - if (0 == mmioMapEntry) - { - lock.unlock(); - return false; - } - - uint64_t mmioMapPage = mmioMapEntry / PAGESIZE; - - // Update PTE. - PageTableManager::addEntry( effAddr, mmioMapPage, CI_ACCESS ); - - lock.unlock(); - return true; - } - else - { - // TODO: Do dynamic stack mapping. - lock.unlock(); - return false; - } -} + bool rc = SegmentManager::handlePageFault(t, effAddr); -void* VmmManager::_mmioMap(void* ra, size_t pages) -{ - lock.lock(); - - ssize_t match = -1; - uint64_t _ra = (uint64_t) ra; - - // Search for memory already mapped in. - for (size_t i = 0; i < MMIO_T_ENTRIES; i++) - { - if ((mmioMapT[i] & ~(PAGESIZE - 1)) == _ra) - { - if (i + pages < MMIO_T_ENTRIES) - { - bool matched = true; - for (size_t j = 1; j < pages; j++) - { - if ((mmioMapT[i+j] & ~(PAGESIZE - 1)) != - (_ra + (j*PAGESIZE))) - { - matched = false; - break; - } - } - if (matched) - { - match = i; - break; - } - } - } - } - - // Found region already mapped in. - if (-1 != match) - { - // Increment ref counts. - for (size_t i = 0; i < pages; i++) - { - mmioMapT[match + i]++; - } - // Return calculated effective address. - lock.unlock(); - return (void*)(FULL_MEM_SIZE + (match * PAGESIZE)); - } - - // Search for empty region in map. - for (size_t i = 0; i < MMIO_T_ENTRIES; i++) - { - if (0 == mmioMapT[i]) - { - bool matched = true; - for (size_t j = 1; j < pages; j++) - { - if (0 != mmioMapT[i+j]) - { - matched = false; - break; - } - } - if (matched) - { - match = i; - break; - } - } - } - - // Found region to use for map. - if (-1 != match) - { - for (size_t i = 0; i < pages; i++) - { - mmioMapT[match + i] = _ra + 1; // RA + ref count of 1. - } - - lock.unlock(); - return (void*)(FULL_MEM_SIZE + (match * PAGESIZE)); - } - - // No entry found and no space for more, return NULL. lock.unlock(); - return NULL; -} -int VmmManager::_mmioUnmap(void* ea, size_t pages) -{ - return -1; + return rc; } + |

