diff options
author | Patrick Williams <iawillia@us.ibm.com> | 2012-07-06 15:40:43 -0500 |
---|---|---|
committer | A. Patrick Williams III <iawillia@us.ibm.com> | 2012-07-11 08:18:41 -0500 |
commit | 14a2721d2c87dc13f1ef66818c41cd0848dd52db (patch) | |
tree | 66ae0220b0443f9a87d87075279ba9a5c08ba412 /src | |
parent | a23283c6facfee055c9c6d43e23a04ca02edc467 (diff) | |
download | talos-hostboot-14a2721d2c87dc13f1ef66818c41cd0848dd52db.tar.gz talos-hostboot-14a2721d2c87dc13f1ef66818c41cd0848dd52db.zip |
Live-lock issues in memory allocator.
* Debug tool for PageManager.
* Support PageMgr allocations of non-2^k size.
* Switch page-allocation to always be in kernel-mode.
While investigating issue 44511, I noticed two problesm with the
memory page allocator (PageManager). First, the allocator did
not support allocations of pages which were not a power of 2,
which would result in pages appearing to "leak". Second, in
situations where a large allocation was requested and there was
not a large chunk available, the allocation would enter a
live-lock condition where coalescing would never occur.
Switched the PageManager so that all allocations happen in
kernel space. This allows us to force memory-release operations
on the syscall path when we are out of memory and also put in
place a task_yield call which will allow coalescing to eventually
occur. Issue 44523 is suppose to fully resolve any of these
live-lock paths.
RTC: 44511
Change-Id: Ifefd5d0996ee6914e291c862fac0c7b76980717f
Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/1330
Tested-by: Jenkins Server
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/build/debug/Hostboot/PageMgr.pm | 100 | ||||
-rw-r--r-- | src/include/kernel/devicesegment.H | 47 | ||||
-rw-r--r-- | src/include/kernel/misc.H | 63 | ||||
-rw-r--r-- | src/include/kernel/pagemgr.H | 22 | ||||
-rw-r--r-- | src/include/kernel/syscalls.H | 4 | ||||
-rw-r--r-- | src/include/sys/mm.h | 6 | ||||
-rw-r--r-- | src/include/usr/vmmconst.h | 15 | ||||
-rw-r--r-- | src/kernel/cpumgr.C | 4 | ||||
-rw-r--r-- | src/kernel/pagemgr.C | 179 | ||||
-rw-r--r-- | src/kernel/syscall.C | 36 | ||||
-rw-r--r-- | src/lib/syscall_mm.C | 8 | ||||
-rw-r--r-- | src/usr/testcore/kernel/segmenttest.H | 47 |
12 files changed, 332 insertions, 199 deletions
diff --git a/src/build/debug/Hostboot/PageMgr.pm b/src/build/debug/Hostboot/PageMgr.pm new file mode 100644 index 000000000..5f8f24533 --- /dev/null +++ b/src/build/debug/Hostboot/PageMgr.pm @@ -0,0 +1,100 @@ +#!/usr/bin/perl +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/build/debug/Hostboot/PageMgr.pm $ +# +# IBM CONFIDENTIAL +# +# COPYRIGHT International Business Machines Corp. 2012 +# +# p1 +# +# Object Code Only (OCO) source materials +# Licensed Internal Code Source Materials +# IBM HostBoot Licensed Internal Code +# +# The source code for this program is not published or other- +# wise divested of its trade secrets, irrespective of what has +# been deposited with the U.S. Copyright Office. +# +# Origin: 30 +# +# IBM_PROLOG_END_TAG + +use strict; + +package Hostboot::PageMgr; +use Exporter; +our @EXPORT_OK = ('main'); + +use constant PAGEMGR_INSTANCE_NAME => + "Singleton<PageManager>::instance()::instance"; +use constant PAGEMGR_CORE_OFFSET => 3 * 8; +use constant PAGEMGR_PAGES_AVAIL_OFFSET => 0; +use constant PAGEMGR_BUCKETS_OFFSET => 8; +use constant PAGEMGR_NUMBER_OF_BUCKETS => 16; + + +sub main +{ + my ($packName, $args) = @_; + + # Parse 'debug' option. + my $debug = 0; + if (defined $args->{"debug"}) + { + $debug = 1; + } + + # Find the PageManager + my ($symAddr, $symSize) = ::findSymbolAddress(PAGEMGR_INSTANCE_NAME); + if (not defined $symAddr) + { + ::userDisplay "Couldn't find ".PAGEMGR_INSTANCE_NAME; + die; + } + # Increment to the PageManagerCore for the general heap. + $symAddr = $symAddr + PAGEMGR_CORE_OFFSET; + + # Read pages available. + my $pagesAvail = ::read64($symAddr + PAGEMGR_PAGES_AVAIL_OFFSET); + ::userDisplay "Pages available: ".$pagesAvail."\n"; + + # Parse through buckets and count pages in buckets. + my $pagesInBuckets = 0; + + for (my $bucket = 0; $bucket < PAGEMGR_NUMBER_OF_BUCKETS; $bucket++) + { + my $stackAddr = ::read32($symAddr + PAGEMGR_BUCKETS_OFFSET + + (8 * $bucket) + 4); + + my $stackCount = countItemsInStack($stackAddr); + my $size = (1 << $bucket) * $stackCount; + + $pagesInBuckets = $pagesInBuckets + $size; + + ::userDisplay "Bucket $bucket has $stackCount blocks for ". + "$size pages.\n" if $debug; + } + + ::userDisplay "Pages in buckets: ".$pagesInBuckets."\n"; + + # Compare if they match. Hopefully they do. + if ($pagesAvail != $pagesInBuckets) + { + my $difference = abs ($pagesAvail - $pagesInBuckets); + ::userDisplay "WARNING: Values differ by $difference!!\n"; + } +} + +sub countItemsInStack +{ + my $stack = shift; + + return 0 if (0 == $stack); + + return 1 + countItemsInStack(::read64($stack)); +} + + diff --git a/src/include/kernel/devicesegment.H b/src/include/kernel/devicesegment.H index c300eedde..2b87c9161 100644 --- a/src/include/kernel/devicesegment.H +++ b/src/include/kernel/devicesegment.H @@ -1,25 +1,26 @@ -// IBM_PROLOG_BEGIN_TAG -// This is an automatically generated prolog. -// -// $Source: src/include/kernel/devicesegment.H $ -// -// IBM CONFIDENTIAL -// -// COPYRIGHT International Business Machines Corp. 2011 -// -// p1 -// -// Object Code Only (OCO) source materials -// Licensed Internal Code Source Materials -// IBM HostBoot Licensed Internal Code -// -// The source code for this program is not published or other- -// wise divested of its trade secrets, irrespective of what has -// been deposited with the U.S. Copyright Office. -// -// Origin: 30 -// -// IBM_PROLOG_END +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/include/kernel/devicesegment.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2011-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ #ifndef __KERNEL_DEVICESEGMENT_H #define __KERNEL_DEVICESEGMENT_H @@ -41,7 +42,7 @@ class DeviceSegment : public Segment * * Associates itself with the SegmentManager. */ - explicit DeviceSegment(size_t segId) : Segment(segId * TERABYTE) + explicit DeviceSegment(size_t segId) : Segment(segId * VMM_SEGMENT_SIZE) { init(segId); }; /** diff --git a/src/include/kernel/misc.H b/src/include/kernel/misc.H index f04439748..ebec9cc48 100644 --- a/src/include/kernel/misc.H +++ b/src/include/kernel/misc.H @@ -1,25 +1,26 @@ -// IBM_PROLOG_BEGIN_TAG -// This is an automatically generated prolog. -// -// $Source: src/include/kernel/misc.H $ -// -// IBM CONFIDENTIAL -// -// COPYRIGHT International Business Machines Corp. 2011 -// -// p1 -// -// Object Code Only (OCO) source materials -// Licensed Internal Code Source Materials -// IBM HostBoot Licensed Internal Code -// -// The source code for this program is not published or other- -// wise divested of its trade secrets, irrespective of what has -// been deposited with the U.S. Copyright Office. -// -// Origin: 30 -// -// IBM_PROLOG_END +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/include/kernel/misc.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2011-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ /** @file misc.H * @brief Misc. Kernel functions and utilities. */ @@ -28,6 +29,7 @@ #define __KERNEL_MISC_H #include <stdint.h> +#include <usr/vmmconst.h> namespace KernelMisc { @@ -40,5 +42,22 @@ namespace KernelMisc extern uint64_t g_payload_base; /** @brief Address from base of payload entry-point. */ extern uint64_t g_payload_entry; + + /** @fn in_kernel_mode + * @brief Determine if the code is currently in kernel mode or not. + * + * @return [true | false] + */ + inline bool in_kernel_mode() + { + uint64_t stack = 0; + asm volatile("mr %0, 1" : "=r"(stack)); + if((stack >= VMM_VADDR_STACK_SEGMENT) && + (stack < (VMM_VADDR_STACK_SEGMENT + VMM_SEGMENT_SIZE))) + { + return false; + } + return true; + } }; #endif diff --git a/src/include/kernel/pagemgr.H b/src/include/kernel/pagemgr.H index 6676a469c..93cd82bb5 100644 --- a/src/include/kernel/pagemgr.H +++ b/src/include/kernel/pagemgr.H @@ -54,7 +54,7 @@ class PageManagerCore /** * Default Constructor */ - PageManagerCore() + PageManagerCore() : iv_available(0) {} /** @@ -76,7 +76,7 @@ class PageManagerCore * @return a pointer to the requested allocation | NULL * if the request could not be satisfied. */ - page_t * allocatePage( size_t i_pageCount ); + page_t * allocatePage( size_t i_pageCount ); /** * Return page allocations to the page manager @@ -136,9 +136,10 @@ class PageManager /** * Allocate pages * @param[in] n, Requested allocation in pages + * @param[in] userspace - Request to allocate came from userspace * @return pointer to requested memory */ - static void* allocatePage(size_t n = 1); + static void* allocatePage(size_t n = 1, bool userspace = false); /** * Return pages to the pagemanager @@ -170,6 +171,9 @@ class PageManager { MEMLEN = VmmManager::MBOX_DMA_ADDR, RESERVED_PAGES = 4, + + LOWMEM_NORM_LIMIT = 16, + LOWMEM_CRIT_LIMIT = 5, }; static size_t cv_coalesce_count; //!< running coalesced counter @@ -182,15 +186,9 @@ class PageManager private: - void* _allocatePage(size_t); //!< see allocatePage() - void _freePage(void*, size_t); //!< see freePage() - void _coalesce( void ); //!< see coalesce() - - /** - * Query if in kernel mode - * @return [true | false] - */ - bool queryKernelMode() const; + void* _allocatePage(size_t,bool); //!< see allocatePage() + void _freePage(void*, size_t); //!< see freePage() + void _coalesce( void ); //!< see coalesce() /** see queryAvail() */ ALWAYS_INLINE uint64_t _queryAvail() const diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H index 20cfd4e65..a46fde703 100644 --- a/src/include/kernel/syscalls.H +++ b/src/include/kernel/syscalls.H @@ -97,8 +97,8 @@ namespace Systemcalls /** mm_set_permission() */ MM_SET_PERMISSION, - /** mm_flush_pages() */ - MM_FLUSH_PAGES, + /** mm_alloc_pages() */ + MM_ALLOC_PAGES, SYSCALL_MAX }; diff --git a/src/include/sys/mm.h b/src/include/sys/mm.h index 105b145be..d9b5536a1 100644 --- a/src/include/sys/mm.h +++ b/src/include/sys/mm.h @@ -97,12 +97,6 @@ int mm_remove_pages(PAGE_REMOVAL_OPS i_op, void* i_vaddr, uint64_t i_size); */ int mm_set_permission(void* va, uint64_t size, uint64_t access_type); -/** @fn mm_flush_pages() - * @brief System call to flush pages - * @param[in] i_sev - [VmmManager::NORMAL | VmmManager::CRITIAL] - */ -void mm_flush_pages(uint64_t i_sev); - #ifdef __cplusplus } #endif diff --git a/src/include/usr/vmmconst.h b/src/include/usr/vmmconst.h index a43a70a7a..1997b9276 100644 --- a/src/include/usr/vmmconst.h +++ b/src/include/usr/vmmconst.h @@ -35,14 +35,21 @@ * Segments */ +/** Stacks are all 1TB in size. */ +#define VMM_SEGMENT_SIZE (1 * TERABYTE) + +/** Base Segment is at 0 TB */ +#define VMM_VADDR_BASE_SEGMENT (0 * TERABYTE) + /** Stack Segment is at 1 TB */ -#define VMM_VADDR_STACK_SEGMENT (1 * TERABYTE) +#define VMM_VADDR_STACK_SEGMENT (VMM_VADDR_BASE_SEGMENT + VMM_SEGMENT_SIZE) /** Device Segments are at 2 TB - 10 TB */ -#define VMM_VADDR_DEVICE_SEGMENT_FIRST (2 * TERABYTE) -#define VMM_VADDR_DEVICE_SEGMENT_LAST (VMM_VADDR_DEVICE_SEGMENT_FIRST + \ - (8 * TERABYTE)) +#define VMM_VADDR_DEVICE_SEGMENT_FIRST \ + (VMM_VADDR_STACK_SEGMENT + VMM_SEGMENT_SIZE) +#define VMM_VADDR_DEVICE_SEGMENT_LAST \ + (VMM_VADDR_DEVICE_SEGMENT_FIRST + (8 * VMM_SEGMENT_SIZE)) /** * Resource Providers diff --git a/src/kernel/cpumgr.C b/src/kernel/cpumgr.C index 3bb52b63c..2a5c2edcc 100644 --- a/src/kernel/cpumgr.C +++ b/src/kernel/cpumgr.C @@ -192,11 +192,11 @@ void CpuManager::executePeriodics(cpu_t * i_cpu) if(0 == (i_cpu->periodic_count % CPU_PERIODIC_CHECK_MEMORY)) { uint64_t pcntAvail = PageManager::queryAvail(); - if(pcntAvail < 16) + if(pcntAvail < PageManager::LOWMEM_NORM_LIMIT) { VmmManager::flushPageTable(); ++(i_cpu->periodic_count); // prevent another flush below - if(pcntAvail < 5) + if(pcntAvail < PageManager::LOWMEM_CRIT_LIMIT) { VmmManager::castOutPages(VmmManager::CRITICAL); } diff --git a/src/kernel/pagemgr.C b/src/kernel/pagemgr.C index 3991ff920..60db55e12 100644 --- a/src/kernel/pagemgr.C +++ b/src/kernel/pagemgr.C @@ -29,10 +29,11 @@ #include <util/locked/pqueue.H> #include <kernel/task.H> #include <kernel/taskmgr.H> -#include <usr/vmmconst.h> #include <kernel/vmmmgr.H> #include <sys/task.h> -#include <sys/mm.h> +#include <kernel/misc.H> +#include <sys/syscall.h> +#include <assert.h> size_t PageManager::cv_coalesce_count = 0; size_t PageManager::cv_low_page_count = -1; @@ -47,14 +48,14 @@ void PageManagerCore::addMemory( size_t i_addr, size_t i_pageCount ) size_t page_length = BUCKETS-1; while(length > 0) { - while (length < (size_t)(1 << page_length)) + while (length < (size_t)(1 << page_length)) { - page_length--; + page_length--; } - iv_heap[page_length].push(page); - page = (page_t*)((uint64_t)page + (1 << page_length)*PAGESIZE); - length -= (1 << page_length); + iv_heap[page_length].push(page); + page = (page_t*)((uint64_t)page + (1 << page_length)*PAGESIZE); + length -= (1 << page_length); } __sync_add_and_fetch(&iv_available, i_pageCount); } @@ -63,8 +64,15 @@ void PageManagerCore::addMemory( size_t i_addr, size_t i_pageCount ) PageManagerCore::page_t * PageManagerCore::allocatePage( size_t i_pageCount ) { - size_t which_bucket = 0; - while (i_pageCount > (size_t)(1 << which_bucket)) which_bucket++; + size_t which_bucket = ((sizeof(size_t)*8 - 1) - + __builtin_clzl(i_pageCount)); + size_t bucket_size = ((size_t)1) << which_bucket; + + if (bucket_size != i_pageCount) + { + ++which_bucket; + bucket_size <<= 1; + } page_t* page = (page_t*)NULL; int retries = 0; @@ -77,7 +85,18 @@ PageManagerCore::page_t * PageManagerCore::allocatePage( size_t i_pageCount ) // Update statistics. if(page) { - __sync_sub_and_fetch(&iv_available, i_pageCount); + __sync_sub_and_fetch(&iv_available, bucket_size); + + // Buckets are 2^k in size so if i_pageCount is not 2^k we have some + // extra pages allocated. ie. the non-2^k portion of i_pageCount. + // Return that portion by freeing. + if (bucket_size != i_pageCount) + { + freePage(reinterpret_cast<void*>( + reinterpret_cast<uintptr_t>(page) + + (i_pageCount*PAGESIZE)), + bucket_size - i_pageCount); + } } return page; @@ -89,13 +108,24 @@ void PageManagerCore::freePage( void * i_page, size_t i_pageCount ) { if ((NULL == i_page) || (0 == i_pageCount)) return; - size_t which_bucket = 0; - while (i_pageCount > (size_t)(1 << which_bucket)) which_bucket++; + size_t which_bucket = ((sizeof(size_t)*8 - 1) - + __builtin_clzl(i_pageCount)); + size_t bucket_size = ((size_t)1) << which_bucket; push_bucket((page_t*)i_page, which_bucket); // Update statistics. - __sync_add_and_fetch(&iv_available, i_pageCount); + __sync_add_and_fetch(&iv_available, bucket_size); + + // Buckets are 2^k in size so if i_pageCount is not 2^k we have some + // spare pages to free. ie. the non-2^k portion of i_pageCount. + if (bucket_size != i_pageCount) + { + freePage(reinterpret_cast<void*>( + reinterpret_cast<uintptr_t>(i_page) + + (bucket_size*PAGESIZE)), + i_pageCount - bucket_size); + } return; } @@ -107,10 +137,34 @@ void PageManager::init() Singleton<PageManager>::instance(); } -void* PageManager::allocatePage(size_t n) +void* PageManager::allocatePage(size_t n, bool userspace) { - PageManager& pmgr = Singleton<PageManager>::instance(); - return pmgr._allocatePage(n); + void* page = NULL; + + // In non-kernel mode, make a system-call to allocate in kernel-mode. + if (!KernelMisc::in_kernel_mode()) + { + while (NULL == page) + { + page = _syscall1(Systemcalls::MM_ALLOC_PAGES, + reinterpret_cast<void*>(n)); + + // Didn't successfully allocate, so yield in hopes that memory + // will eventually free up (ex. VMM flushes). + if (NULL == page) + { + task_yield(); + } + } + } + else + { + // In kernel mode. Do a normal call to the PageManager. + PageManager& pmgr = Singleton<PageManager>::instance(); + page = pmgr._allocatePage(n, userspace); + } + + return page; } void PageManager::freePage(void* p, size_t n) @@ -140,8 +194,8 @@ PageManager::PageManager() // Display. printk("Initializing PageManager with %zd pages starting at %lx...", - length, - addr); + length, + addr); // Populate L3 cache lines. uint64_t* cache_line = reinterpret_cast<uint64_t*>(addr); @@ -172,62 +226,27 @@ PageManager::PageManager() printk("done\n"); } -void* PageManager::_allocatePage(size_t n) +void* PageManager::_allocatePage(size_t n, bool userspace) { - PageManagerCore::page_t* page = NULL; + PageManagerCore::page_t* page = iv_heap.allocatePage(n); - // Initiate a page cast out if low - if(_queryAvail() < 16 && queryKernelMode() == false) + // If the allocation came from kernel-space and normal allocation + // was unsuccessful, pull a page off the reserve heap. + if ((NULL == page) && (!userspace)) { - // Kernel mode might have Vmm mutex lock which would cause deadlock - // were VmmManager functions called to flush and cast out. - - // Only want one thread testing and flushing - if(__sync_bool_compare_and_swap(&(iv_lock),0,1)) - { - if(_queryAvail() < 5) - { - mm_flush_pages(VmmManager::CRITICAL); - } - else - { - mm_flush_pages(VmmManager::NORMAL); - } - iv_lock = 0; - } + printkd("PAGEMANAGER: kernel heap used\n"); + page = iv_heapKernel.allocatePage(n); } - while(page == NULL) - { - page = iv_heap.allocatePage(n); - - if(NULL == page) - { - if(queryKernelMode() == true) - { - printkd("PAGEMANAGER: kernel heap used\n"); - page = iv_heapKernel.allocatePage(n); - break; - } - else - { - //task yield and hope there is more memory available - //when execution continues - printkd("PAGEMANAGER: Task held off\n"); - task_yield(); - - //Possible Loop forever? or is there a break condition?? - } - } - } - - if (NULL == page) + // If still not successful, we're out of memory. Assert. + if ((NULL == page) && (!userspace)) { register task_t* t; asm volatile("mr %0, 13" : "=r"(t)); - printk("Insufficient memory for alloc of size %zd page on tid=%d!\n", n, t->tid); + printk("Insufficient memory for alloc %zd pages on tid=%d!\n", + n, t->tid); printk("Pages available=%ld\n",iv_pagesAvail); - while(1); + kassert(false); } // Update statistics. @@ -257,7 +276,6 @@ void PageManager::_freePage(void* p, size_t n) if(page) { iv_heapKernel.addMemory(reinterpret_cast<size_t>(page), ks); - __sync_sub_and_fetch(&iv_pagesAvail, ks); } } @@ -273,14 +291,14 @@ PageManagerCore::page_t* PageManagerCore::pop_bucket(size_t i_n) if (NULL == p) { - // Couldn't allocate from the correct size bucket, so split up an - // item from the next sized bucket. - p = pop_bucket(i_n+1); - if (NULL != p) - { - push_bucket((page_t*) (((uint64_t)p) + (PAGESIZE * (1 << i_n))), - i_n); - } + // Couldn't allocate from the correct size bucket, so split up an + // item from the next sized bucket. + p = pop_bucket(i_n+1); + if (NULL != p) + { + push_bucket((page_t*) (((uint64_t)p) + (PAGESIZE * (1 << i_n))), + i_n); + } } return p; } @@ -304,9 +322,6 @@ void PageManager::_coalesce( void ) // Coalsesce adjacent free memory blocks void PageManagerCore::coalesce( void ) { - // TODO: Issue 44511 - Function appears to leak memory. - return; - // Look at all the "free buckets" and find blocks to merge // Since this is binary, all merges will be from the same free bucket // Each bucket is a stack of non-allocated memory blocks of the same size @@ -371,13 +386,3 @@ void PageManagerCore::coalesce( void ) printkd("PAGEMGR low page count %ld\n", PageManager::cv_low_page_count); } -bool PageManager::queryKernelMode() const -{ - uint64_t stack = 0; - asm volatile("mr %0, 1" : "=r"(stack)); - if(stack >= VMM_VADDR_STACK_SEGMENT && stack < VMM_VADDR_DEVICE_SEGMENT_FIRST) - { - return false; - } - return true; -} diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 1ed68624e..b6fa46f8a 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -89,8 +89,6 @@ namespace Systemcalls void MsgSendRecv(task_t*); void MsgRespond(task_t*); void MsgWait(task_t*); - void MmioMap(task_t*); - void MmioUnmap(task_t*); void DevMap(task_t*); void DevUnmap(task_t*); void TimeNanosleep(task_t*); @@ -101,7 +99,7 @@ namespace Systemcalls void MmAllocBlock(task_t *t); void MmRemovePages(task_t *t); void MmSetPermission(task_t *t); - void MmFlushPages(task_t *t); + void MmAllocPages(task_t *t); syscall syscalls[] = @@ -135,7 +133,7 @@ namespace Systemcalls &MmAllocBlock, // MM_ALLOC_BLOCK &MmRemovePages, // MM_REMOVE_PAGES &MmSetPermission, // MM_SET_PERMISSION - &MmFlushPages, // MM_FLUSH_PAGES + &MmAllocPages, // MM_ALLOC_PAGES }; }; @@ -165,6 +163,9 @@ namespace Systemcalls Scheduler* s = t->cpu->scheduler; s->returnRunnable(); s->setNextRunnable(); + + // TODO: Issue 44523 - Temporary workaround for live-lock situation. + CpuManager::executePeriodics(CpuManager::getCurrentCPU()); } void TaskStart(task_t* t) @@ -671,15 +672,30 @@ namespace Systemcalls } /** - * Flush and Cast out 'old' pages + * Call PageManager to allocate a number of pages. * @param[in] t: The task used. */ - void MmFlushPages(task_t* t) + void MmAllocPages(task_t* t) { - VmmManager::castout_t sev = (VmmManager::castout_t)TASK_GETARG0(t); - VmmManager::flushPageTable(); - VmmManager::castOutPages(sev); - TASK_SETRTN(t,0); + // Attempt to allocate the page(s). + void* page = PageManager::allocatePage(TASK_GETARG0(t), true); + TASK_SETRTN(t, reinterpret_cast<uint64_t>(page)); + + // If we are low on memory, call into the VMM to free some up. + uint64_t pcntAvail = PageManager::queryAvail(); + if (pcntAvail < PageManager::LOWMEM_NORM_LIMIT) + { + static uint64_t one_at_a_time = 0; + if (!__sync_lock_test_and_set(&one_at_a_time, 1)) + { + VmmManager::flushPageTable(); + VmmManager::castout_t sev = + (pcntAvail < PageManager::LOWMEM_CRIT_LIMIT) ? + VmmManager::CRITICAL : VmmManager::NORMAL; + VmmManager::castOutPages(sev); + __sync_lock_release(&one_at_a_time); + } + } } }; diff --git a/src/lib/syscall_mm.C b/src/lib/syscall_mm.C index 006586f81..b539cf05a 100644 --- a/src/lib/syscall_mm.C +++ b/src/lib/syscall_mm.C @@ -81,11 +81,3 @@ int mm_set_permission(void* va, uint64_t size, uint64_t access_type) { return (int64_t)_syscall3(MM_SET_PERMISSION, va, (void*)size, (void*)access_type); } - -/** - * System call to flush pages - */ -void mm_flush_pages(uint64_t i_sev) -{ - _syscall1(MM_FLUSH_PAGES, (void*)i_sev); -} diff --git a/src/usr/testcore/kernel/segmenttest.H b/src/usr/testcore/kernel/segmenttest.H index e5b9ff64a..72ae8f23a 100644 --- a/src/usr/testcore/kernel/segmenttest.H +++ b/src/usr/testcore/kernel/segmenttest.H @@ -1,25 +1,26 @@ -// IBM_PROLOG_BEGIN_TAG -// This is an automatically generated prolog. -// -// $Source: src/usr/testcore/kernel/segmenttest.H $ -// -// IBM CONFIDENTIAL -// -// COPYRIGHT International Business Machines Corp. 2011 -// -// p1 -// -// Object Code Only (OCO) source materials -// Licensed Internal Code Source Materials -// IBM HostBoot Licensed Internal Code -// -// The source code for this program is not published or other- -// wise divested of its trade secrets, irrespective of what has -// been deposited with the U.S. Copyright Office. -// -// Origin: 30 -// -// IBM_PROLOG_END +/* IBM_PROLOG_BEGIN_TAG + * This is an automatically generated prolog. + * + * $Source: src/usr/testcore/kernel/segmenttest.H $ + * + * IBM CONFIDENTIAL + * + * COPYRIGHT International Business Machines Corp. 2011-2012 + * + * p1 + * + * Object Code Only (OCO) source materials + * Licensed Internal Code Source Materials + * IBM HostBoot Licensed Internal Code + * + * The source code for this program is not published or other- + * wise divested of its trade secrets, irrespective of what has + * been deposited with the U.S. Copyright Office. + * + * Origin: 30 + * + * IBM_PROLOG_END_TAG + */ #ifndef __SEGMENTTEST_H #define __SEGMENTTEST_H /** @@ -91,7 +92,7 @@ class segmenttest: public CxxTest::TestSuite void* block = NULL; while (reinterpret_cast<uint64_t>(block) - < (VMM_VADDR_DEVICE_SEGMENT_FIRST + TERABYTE)) + < (VMM_VADDR_DEVICE_SEGMENT_FIRST + VMM_SEGMENT_SIZE)) { block = mmio_dev_map(reinterpret_cast<void*>(10 * TERABYTE), THIRTYTWO_GB); |