diff options
-rw-r--r-- | src/include/kernel/basesegment.H | 5 | ||||
-rw-r--r-- | src/include/kernel/block.H | 14 | ||||
-rw-r--r-- | src/include/kernel/cpu.H | 3 | ||||
-rw-r--r-- | src/include/kernel/cpumgr.H | 14 | ||||
-rw-r--r-- | src/include/kernel/pagemgr.H | 17 | ||||
-rw-r--r-- | src/include/kernel/ptmgr.H | 10 | ||||
-rw-r--r-- | src/include/kernel/segment.H | 6 | ||||
-rw-r--r-- | src/include/kernel/segmentmgr.H | 10 | ||||
-rw-r--r-- | src/include/kernel/vmmmgr.H | 23 | ||||
-rw-r--r-- | src/kernel/basesegment.C | 9 | ||||
-rw-r--r-- | src/kernel/block.C | 99 | ||||
-rw-r--r-- | src/kernel/cpumgr.C | 32 | ||||
-rw-r--r-- | src/kernel/pagemgr.C | 9 | ||||
-rw-r--r-- | src/kernel/ptmgr.C | 22 | ||||
-rw-r--r-- | src/kernel/scheduler.C | 2 | ||||
-rw-r--r-- | src/kernel/segmentmgr.C | 18 | ||||
-rw-r--r-- | src/kernel/vmmmgr.C | 28 | ||||
-rw-r--r-- | src/usr/testcore/kernel/vmmbasetest.H | 20 |
18 files changed, 337 insertions, 4 deletions
diff --git a/src/include/kernel/basesegment.H b/src/include/kernel/basesegment.H index da262c2a0..574be1a1f 100644 --- a/src/include/kernel/basesegment.H +++ b/src/include/kernel/basesegment.H @@ -106,6 +106,11 @@ class BaseSegment : public Segment static int mmSetPermission(void* i_va, uint64_t i_size, PAGE_PERMISSIONS i_access_type); + /** + * @breif Cast out older physical memory pages + * @param[in] castout Constraint + */ + virtual void castOutPages(uint64_t i_type); private: /** diff --git a/src/include/kernel/block.H b/src/include/kernel/block.H index 2421f97f9..88c6664c2 100644 --- a/src/include/kernel/block.H +++ b/src/include/kernel/block.H @@ -156,6 +156,20 @@ class Block void updateRefCount( uint64_t i_vaddr, PageTableManager::UsageStats_t i_stats ); + /** + * @brief Cast out older phyiscal memory pages + * @param[in] i_type - Castout contraint @see VmmManager::castOutPages() + * @return number of pages cast out + */ + size_t castOutPages(uint64_t i_type); + + /** + * @brief Evict a memory page + * @param[in] i_pte shadow page table entry + * @return true of page was evicted + */ + bool evictPage(ShadowPTE* i_pte); + friend class Segment; friend class BaseSegment; friend class StackSegment; diff --git a/src/include/kernel/cpu.H b/src/include/kernel/cpu.H index ee24bdd64..ac09da288 100644 --- a/src/include/kernel/cpu.H +++ b/src/include/kernel/cpu.H @@ -77,6 +77,9 @@ struct cpu_t /** XSCOM mutex to serialize access per CPU */ mutex_t xscom_mutex; + + /** counter for executePeriodics */ + size_t periodic_count; }; /** @fn getCpuId diff --git a/src/include/kernel/cpumgr.H b/src/include/kernel/cpumgr.H index 31759564b..b60c72bc6 100644 --- a/src/include/kernel/cpumgr.H +++ b/src/include/kernel/cpumgr.H @@ -29,7 +29,12 @@ class CpuManager { public: - enum { MAXCPUS = KERNEL_MAX_SUPPORTED_CPUS }; + enum + { + MAXCPUS = KERNEL_MAX_SUPPORTED_CPUS, + CPU_PERIODIC_CHECK_MEMORY = 64, + CPU_PERIODIC_FLUSH_PAGETABLE = 1024, + }; /** @fn getCurrentCPU * Returns a pointer to the current CPU structure by using the @@ -60,6 +65,13 @@ class CpuManager */ static uint32_t getShutdownStatus() { return cv_shutdown_status; } + /** @fn executePeriodics + * Perform periodic actions + * @param[in] cpu_t the CPU + */ + static void executePeriodics(cpu_t * i_cpu); + + protected: CpuManager(); ~CpuManager() {} diff --git a/src/include/kernel/pagemgr.H b/src/include/kernel/pagemgr.H index eeed535e0..6cb6fefc4 100644 --- a/src/include/kernel/pagemgr.H +++ b/src/include/kernel/pagemgr.H @@ -27,6 +27,8 @@ #include <limits.h> #include <util/lockfree/stack.H> #include <kernel/vmmmgr.H> +#include <builtins.h> +#include <kernel/console.H> /** @class PageManager * @brief Manages the allocation of memory pages. @@ -40,6 +42,12 @@ class PageManager static void* allocatePage(size_t n = 1); static void freePage(void*, size_t n = 1); + /** + * Query state for available memory + * @returns percent of pages available + */ + static uint64_t queryAvail(); + enum { MEMLEN = VmmManager::HTABORG, @@ -55,8 +63,17 @@ class PageManager void* _allocatePage(size_t); void _freePage(void*, size_t); + /** see queryAvail() */ + ALWAYS_INLINE + uint64_t _queryAvail() const + { + return (100*iv_pagesAvail)/iv_pagesTotal; + } + /** Statistics on number of free pages (for debug) */ uint64_t iv_pagesAvail; + /** Total number of pages */ + uint64_t iv_pagesTotal; struct page_t { diff --git a/src/include/kernel/ptmgr.H b/src/include/kernel/ptmgr.H index 8eca3f213..9ae092857 100644 --- a/src/include/kernel/ptmgr.H +++ b/src/include/kernel/ptmgr.H @@ -160,6 +160,11 @@ class PageTableManager */ static void printPT( void ); + /** + * @brief Flush reference status & unload unused pages + */ + static void flush( void ); + protected: /** @@ -452,6 +457,11 @@ class PageTableManager */ void pushUsageStats( PageTableEntry* i_pte ); + /** + * @brief see flush + */ + void _flush( void ); + // Allow testcase to see inside friend class ptmgrtest; }; diff --git a/src/include/kernel/segment.H b/src/include/kernel/segment.H index d7a4a7547..798539309 100644 --- a/src/include/kernel/segment.H +++ b/src/include/kernel/segment.H @@ -89,6 +89,12 @@ class Segment return; }; + /** + * @brief Cast out older physical memory pages + * @param[in] i_type Constraint @see VmmManager::castOutPages + */ + virtual void castOutPages(uint64_t i_type) {} // default to NOOP + protected: /** The base address of the segment. */ const uint64_t iv_baseAddress; diff --git a/src/include/kernel/segmentmgr.H b/src/include/kernel/segmentmgr.H index a8f4e002d..7232c7d4f 100644 --- a/src/include/kernel/segmentmgr.H +++ b/src/include/kernel/segmentmgr.H @@ -118,6 +118,12 @@ class SegmentManager static void updateRefCount( uint64_t i_vaddr, PageTableManager::UsageStats_t i_stats ); + /** + * @brief Cast out oldest physical memory pages + * @param[in] castout type + */ + static void castOutPages(uint64_t i_type); + private: /** See handlePageFault. */ @@ -129,11 +135,13 @@ class SegmentManager /** See updateRefCount. */ void _updateRefCount( uint64_t i_vaddr, PageTableManager::UsageStats_t i_stats ); + /** See castOutPages */ + void _castOutPages(uint64_t i_type); /** See findPhysicalAddress */ uint64_t _findPhysicalAddress(uint64_t i_vaddr) const; - ALWAYS_INLINE inline + ALWAYS_INLINE size_t getSegmentIdFromAddress(uint64_t i_addr) const { return i_addr >> SLBE_s; diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H index ef8e6c362..5c7a75d5d 100644 --- a/src/include/kernel/vmmmgr.H +++ b/src/include/kernel/vmmmgr.H @@ -55,6 +55,12 @@ class VmmManager RO_EXE_ACCESS, }; + enum castout_t + { + NORMAL, + CRITICAL, + }; + static void init(); static void init_slb(); @@ -104,6 +110,17 @@ class VmmManager * @return the physical address or -EFAULT @see errno.h */ static uint64_t findPhysicalAddress(uint64_t i_vaddr); + + /** + * @brief Cast out older physical memory pages + * @param[in] castout constraint + */ + static void castOutPages(castout_t i_ct); + + /** + * @brief Flush pagetable, Update shadow page info + */ + static void flushPageTable( void); /** * @brief Remove pages by a specified operation of the given size @@ -157,6 +174,12 @@ class VmmManager /* See mmSetPermission */ int _mmSetPermission(void* i_va,uint64_t i_size, PAGE_PERMISSIONS i_access_type); + /** See castOutPages */ + void _castOutPages(castout_t i_ct); + + /** See flushPageTable */ + void _flushPageTable( void ); + public: friend class Block; diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C index e59e41753..eab00accc 100644 --- a/src/kernel/basesegment.C +++ b/src/kernel/basesegment.C @@ -29,6 +29,7 @@ #include <kernel/segmentmgr.H> #include <kernel/block.H> #include <kernel/cpuid.H> +#include <kernel/console.H> BaseSegment::~BaseSegment() @@ -147,3 +148,11 @@ int BaseSegment::mmSetPermission(void* i_va, uint64_t i_size,PAGE_PERMISSIONS i_ { return 0; } + +void BaseSegment::castOutPages(uint64_t i_type) +{ + size_t cast_out = 0; + cast_out = iv_block->castOutPages(i_type); + // Could try again with a more agressive constraint if cast_out == 0 ???? + if(cast_out) printkd("Cast out %ld pages,Type=%ld\n",cast_out,i_type); +} diff --git a/src/kernel/block.C b/src/kernel/block.C index 59a7892f2..63c1fae92 100644 --- a/src/kernel/block.C +++ b/src/kernel/block.C @@ -108,6 +108,15 @@ bool Block::handlePageFault(task_t* i_task, uint64_t i_addr) } else { + // Test code @TODO remove - SET up ro pages to test cast out pages + //if(pte->getPage() == 0) + //{ + // void* l_page = PageManager::allocatePage(); + // memset(l_page,'U',PAGESIZE); + // pte->setPageAddr(reinterpret_cast<uint64_t>(l_page)); + // pte->setPresent(true); + // pte->setWritable(false); + //} return false; //TODO - Swap kernel base block pages for user pages } } @@ -301,3 +310,93 @@ void Block::updateRefCount( uint64_t i_vaddr, spte->setDirty( i_stats.C ); } + +bool Block::evictPage(ShadowPTE* i_pte) +{ + ShadowPTE* pte = i_pte; + bool do_cast_out = false; + + if(!pte->isWritable()) // ro, executable + { + do_cast_out = true; + } + else // is writable... + { + // if pte->isWriteTracked() flush then cast out + } + + if(do_cast_out) + { + PageTableManager::delEntry(pte->getPageAddr()); + PageManager::freePage(reinterpret_cast<void*>(pte->getPageAddr())); + pte->setPresent(false); + pte->setPageAddr(NULL); + } + + return do_cast_out; +} + +size_t Block::castOutPages(uint64_t i_type) +{ + size_t cast_out = 0; + // drill down + if(iv_nextBlock) + { + cast_out += iv_nextBlock->castOutPages(i_type); + } + + // TODO We will eventually need to skip other blocks as well, such as + // when the memory space grows. + if(iv_baseAddr != 0) // Skip base area + { + bool is_cast_out = false; + size_t rw_constraint = 5; + size_t ro_constraint = 3; + + if(i_type == VmmManager::CRITICAL) + { + rw_constraint = 2; + ro_constraint = 1; + } + //printk("Block = %p:%ld\n",(void*)iv_baseAddr,iv_size / PAGESIZE); + for(uint64_t page = iv_baseAddr; + page < (iv_baseAddr + iv_size); + page += PAGESIZE) + { + ShadowPTE* pte = getPTE(page); + if (pte->isPresent() && (0 != pte->getPageAddr())) + { + //if(pte->isExecutable()) printk("x"); + //else if(pte->isWritable()) printk("w"); + //else printk("r"); + //printk("%d",(int)pte->getLRU()); + + if(pte->isWritable()) + { + if((pte->getLRU() > rw_constraint) && pte->isWriteTracked()) + { + is_cast_out = evictPage(pte); + //printk("+"); + } + } + else // ro and/or executable + { + if(pte->getLRU() > ro_constraint) + { + is_cast_out = evictPage(pte); + } + } + + if(is_cast_out) + { + //printk("-"); + ++cast_out; + is_cast_out = false; + } + } + } + //printk("\n"); + } + + return cast_out; +} diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C index d8a9960f6..01af160f1 100644 --- a/src/kernel/cpumgr.C +++ b/src/kernel/cpumgr.C @@ -33,6 +33,7 @@ #include <kernel/timemgr.H> #include <sys/sync.h> #include <kernel/cpuid.H> +#include <kernel/ptmgr.H> cpu_t* CpuManager::cv_cpus[CpuManager::MAXCPUS] = { NULL }; bool CpuManager::cv_shutdown_requested = false; @@ -141,6 +142,7 @@ void CpuManager::startCPU(ssize_t i) // Create idle task. cpu->idle_task = TaskManager::createIdleTask(); cpu->idle_task->cpu = cpu; + cpu->periodic_count = 0; printk("done\n"); } @@ -160,3 +162,33 @@ void CpuManager::startSlaveCPU(cpu_t* cpu) return; } + +void CpuManager::executePeriodics(cpu_t * i_cpu) +{ + if(i_cpu->master) + { + ++(i_cpu->periodic_count); + if(0 == (i_cpu->periodic_count % CPU_PERIODIC_CHECK_MEMORY)) + { + uint64_t pcntAvail = PageManager::queryAvail(); + if(pcntAvail < 16) // Less than 16% pages left TODO 16 ok? + { + VmmManager::flushPageTable(); + ++(i_cpu->periodic_count); // prevent another flush below + if(pcntAvail < 5) // TODO 5% ok + { + VmmManager::castOutPages(VmmManager::CRITICAL); + } + else + { + VmmManager::castOutPages(VmmManager::NORMAL); + } + } + } + if(0 == (i_cpu->periodic_count % CPU_PERIODIC_FLUSH_PAGETABLE)) + { + VmmManager::flushPageTable(); + } + } +} + diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C index f74ee89c1..826e1bc4d 100644 --- a/src/kernel/pagemgr.C +++ b/src/kernel/pagemgr.C @@ -44,7 +44,12 @@ void PageManager::freePage(void* p, size_t n) return pmgr._freePage(p, n); } -PageManager::PageManager() : iv_pagesAvail(0) +uint64_t PageManager::queryAvail() +{ + return Singleton<PageManager>::instance()._queryAvail(); +} + +PageManager::PageManager() : iv_pagesAvail(0), iv_pagesTotal(0) { // Determine first page of un-allocated memory. uint64_t addr = (uint64_t) VFS_LAST_ADDRESS; @@ -55,6 +60,7 @@ PageManager::PageManager() : iv_pagesAvail(0) page_t* page = (page_t*)((void*) addr); size_t length = (MEMLEN - addr) / PAGESIZE; + iv_pagesTotal = length; // Update statistics. __sync_add_and_fetch(&iv_pagesAvail, length); @@ -156,3 +162,4 @@ void PageManager::push_bucket(page_t* p, size_t n) if (n >= BUCKETS) return; first_page[n].push(p); } + diff --git a/src/kernel/ptmgr.C b/src/kernel/ptmgr.C index 0feffb7e6..92d211888 100644 --- a/src/kernel/ptmgr.C +++ b/src/kernel/ptmgr.C @@ -251,6 +251,10 @@ void PageTableManager::printPT( void ) Singleton<PageTableManager>::instance()._printPT(); } +void PageTableManager::flush( void ) +{ + Singleton<PageTableManager>::instance()._flush(); +} /******************** Private/Protected Methods @@ -1102,3 +1106,21 @@ void PageTableManager::pushUsageStats( PageTableEntry* i_pte ) uint64_t va = getVirtAddrFromPTE(i_pte); SegmentManager::updateRefCount( va, stats ); } + +void PageTableManager::_flush( void ) +{ + if( ivTABLE ) + { + return; + } + + PageTableEntry* pte = (PageTableEntry*)getAddress(); + uint64_t num_ptes = getSize() / sizeof(PageTableEntry); + for (uint64_t i = 0; i < num_ptes; ++i) + { + updateLRU( pte ); + pushUsageStats ( pte ); + ++pte; + } +} + diff --git a/src/kernel/scheduler.C b/src/kernel/scheduler.C index 7b57792a5..28f70debd 100644 --- a/src/kernel/scheduler.C +++ b/src/kernel/scheduler.C @@ -77,6 +77,8 @@ void Scheduler::setNextRunnable() task_t* t = NULL; cpu_t* cpu = CpuManager::getCurrentCPU(); + CpuManager::executePeriodics(cpu); + // Check for ready task in local run-queue, if it exists. if (NULL != cpu->scheduler_extra) { diff --git a/src/kernel/segmentmgr.C b/src/kernel/segmentmgr.C index 890bd1812..0b4370cfa 100644 --- a/src/kernel/segmentmgr.C +++ b/src/kernel/segmentmgr.C @@ -55,6 +55,11 @@ void SegmentManager::updateRefCount( uint64_t i_vaddr, Singleton<SegmentManager>::instance()._updateRefCount(i_vaddr,i_stats); } +void SegmentManager::castOutPages(uint64_t i_type) +{ + Singleton<SegmentManager>::instance()._castOutPages(i_type); +} + bool SegmentManager::_handlePageFault(task_t* i_task, uint64_t i_addr) { size_t segId = getSegmentIdFromAddress(i_addr); @@ -122,7 +127,7 @@ void SegmentManager::_updateRefCount( uint64_t i_vaddr, PageTableManager::UsageStats_t i_stats ) { // Get segment ID from effective address. - size_t segId = i_vaddr >> SLBE_s; + size_t segId = getSegmentIdFromAddress(i_vaddr); // Call contained segment object to update the reference count if ((segId < MAX_SEGMENTS) && (NULL != iv_segments[segId])) @@ -130,3 +135,14 @@ void SegmentManager::_updateRefCount( uint64_t i_vaddr, iv_segments[segId]->updateRefCount( i_vaddr, i_stats ); } } + +void SegmentManager::_castOutPages(uint64_t i_type) +{ + for (size_t i = 0; i < MAX_SEGMENTS; i++) + { + if (NULL != iv_segments[i]) + { + iv_segments[i]->castOutPages(i_type); + } + } +} diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C index 4009ff380..b2026944e 100644 --- a/src/kernel/vmmmgr.C +++ b/src/kernel/vmmmgr.C @@ -72,6 +72,16 @@ uint64_t VmmManager::findPhysicalAddress(uint64_t i_vaddr) return Singleton<VmmManager>::instance()._findPhysicalAddress(i_vaddr); } +void VmmManager::castOutPages(VmmManager::castout_t i_ct) +{ + Singleton<VmmManager>::instance()._castOutPages(i_ct); +} + +void VmmManager::flushPageTable( void ) +{ + Singleton<VmmManager>::instance()._flushPageTable(); +} + /** * STATIC * @brief DEPRECATED @@ -184,3 +194,21 @@ int VmmManager::_mmSetPermission(void* i_va, uint64_t i_size, PAGE_PERMISSIONS i return rc; } + +void VmmManager::_castOutPages(VmmManager::castout_t i_ct) +{ + lock.lock(); + + SegmentManager::castOutPages((uint64_t)i_ct); + + lock.unlock(); +} + +void VmmManager::_flushPageTable( void ) +{ + lock.lock(); + + PageTableManager::flush(); + + lock.unlock(); +} diff --git a/src/usr/testcore/kernel/vmmbasetest.H b/src/usr/testcore/kernel/vmmbasetest.H index 000e400ab..3e1e2fdcd 100644 --- a/src/usr/testcore/kernel/vmmbasetest.H +++ b/src/usr/testcore/kernel/vmmbasetest.H @@ -30,6 +30,7 @@ #include <sys/task.h> #include <kernel/console.H> #include <arch/ppc.H> +#include <sys/mm.h> class VmmBaseTest : public CxxTest::TestSuite { @@ -87,6 +88,25 @@ class VmmBaseTest : public CxxTest::TestSuite // @TODO. VMM not ready. } + void testCastOutPages() + { + //uint64_t vmemaddr = (1ul * 1024 * 1024 * 1024)/2; + //uint64_t vmsize = 4ul * 1024 * 500; + //printk("Test case: cast out pages\n"); + //printk("Set up virtual block at %p\n",(void*)vmemaddr); + //size_t rc = mm_alloc_block(NULL, // need a msgq? + // (void*)vmemaddr, + // vmsize); + //if(rc) printk("RC=%ld\n",rc); + // touch something on every page + //for(uint64_t i = vmemaddr; i < (vmemaddr + vmsize); i += PAGESIZE) + //{ + // if(*((char *)i) != 'U') printk("Yiks %p is %c\n",(void*)i,*((char *)i)); + //} + + // see printk buffer for cast out pages + } + private: static void readFromNULL(void* unused) |