From bf46e7954689c41cccc897b8b00bcc5db5245374 Mon Sep 17 00:00:00 2001 From: Doug Gilbert Date: Mon, 22 Aug 2011 17:14:23 -0500 Subject: map virtual address to physical address in kernel Change-Id: Id18e604facd517598a18968af3dff927026ad894 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/272 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III Reviewed-by: Daniel M. Crowell --- src/include/kernel/basesegment.H | 14 ++++++++++++- src/include/kernel/block.H | 10 +++++++++ src/include/kernel/segment.H | 9 ++++++++ src/include/kernel/segmentmgr.H | 18 ++++++++++++++++ src/include/kernel/vmmmgr.H | 10 +++++++++ src/kernel/basesegment.C | 18 ++++++++++++---- src/kernel/block.C | 22 ++++++++++++++++++++ src/kernel/segmentmgr.C | 26 ++++++++++++++++++----- src/kernel/syscall.C | 45 +++++++++++++++++++++++++++------------- src/kernel/vmmmgr.C | 19 +++++++++++++++++ 10 files changed, 167 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/include/kernel/basesegment.H b/src/include/kernel/basesegment.H index c8cc7a137..a661ae5ce 100644 --- a/src/include/kernel/basesegment.H +++ b/src/include/kernel/basesegment.H @@ -44,7 +44,7 @@ class BaseSegment : public Segment * @brief Constructor. * Initialize attributes and set base addresss of segment to 0 TB. */ - BaseSegment() : Segment(0x0), iv_block(NULL) {}; + BaseSegment() : Segment(0x0), iv_block(NULL), iv_physMemSize(0) {}; /** * @brief Destructor * Delete any blocks owned by this segment. @@ -75,6 +75,14 @@ class BaseSegment : public Segment static int mmAllocBlock(MessageQueue* i_mq,void* i_va, uint64_t i_size); + /** + * @brief Locate the physical address of the given virtual address + * @param[in] i_vaddr virtual address + * @return the physical address bound to the virtual address, or + * -EFAULT if i_vaddr not found. @see errno.h + */ + virtual uint64_t findPhysicalAddress(uint64_t i_vaddr) const; + private: /** * @brief Internal implementation of init function. @@ -84,6 +92,9 @@ class BaseSegment : public Segment /** Block-chain associated with this Segment. */ Block* iv_block; + /** Physical memory byte size */ + uint64_t iv_physMemSize; + /** * @brief Allocates a block of virtual memory of the given size * @param i_mq[in] - Message queue to be associated with the block @@ -92,6 +103,7 @@ class BaseSegment : public Segment * @return int - 0 for successful block allocation, non-zero otherwise */ int _mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size); + }; #endif diff --git a/src/include/kernel/block.H b/src/include/kernel/block.H index 50286a3db..3745b065e 100644 --- a/src/include/kernel/block.H +++ b/src/include/kernel/block.H @@ -130,6 +130,16 @@ class Block */ void addPTE(void* i_vaddr); + /** + * @brief Locate the physical address of the given virtual address + * + * @param[in] i_vaddr virtual address + * + * @return the physical address bound to the virtual address, + * -EFAULT if not found @see errno.h + */ + uint64_t findPhysicalAddress(uint64_t i_vaddr) const; + friend class Segment; friend class BaseSegment; friend class StackSegment; diff --git a/src/include/kernel/segment.H b/src/include/kernel/segment.H index a3df88602..05c5c0fdc 100644 --- a/src/include/kernel/segment.H +++ b/src/include/kernel/segment.H @@ -27,6 +27,7 @@ #define __KERNEL_SEGMENT_H #include +#include /** @class Segment * @brief Virtual segment class to handle virtual memory management within @@ -66,6 +67,14 @@ class Segment */ uint64_t getBaseAddress() const { return iv_baseAddress; }; + /** + * @brief Locate the physical address of the given virtual address + * @param[in] i_vaddr virtual address + * @return the physical address bound to the virtual address, + * or -EFAULT if i_vaddr not found. @see errno.h + */ + virtual uint64_t findPhysicalAddress(uint64_t i_vaddr) const { return -EFAULT; }; + 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 cf1a02b1a..0d8caec33 100644 --- a/src/include/kernel/segmentmgr.H +++ b/src/include/kernel/segmentmgr.H @@ -28,6 +28,7 @@ #define __KERNEL_SEGMENTMGR_H #include +#include // Forward declaration. class Segment; @@ -99,6 +100,14 @@ class SegmentManager */ static void initSLB(); + /** + * @brief Find the phyiscal address bound to the given address + * @param[in] i_vaddr The address + * @return the physical address or -EFAULT @see errno.h + */ + static uint64_t findPhysicalAddress(uint64_t i_vaddr); + + private: /** See handlePageFault. */ bool _handlePageFault(task_t* i_task, uint64_t i_addr); @@ -107,6 +116,15 @@ class SegmentManager /** See initSLB. */ void _initSLB(); + /** See findPhysicalAddress */ + uint64_t _findPhysicalAddress(uint64_t i_vaddr) const; + + ALWAYS_INLINE inline + size_t getSegmentIdFromAddress(uint64_t i_addr) const + { + return i_addr >> 40; // SLBE_s = 40 Should come from page manager? + } + /** Array of segment objects to associated segment IDs. */ Segment* iv_segments[MAX_SEGMENTS]; }; diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H index a32408e24..06533e34e 100644 --- a/src/include/kernel/vmmmgr.H +++ b/src/include/kernel/vmmmgr.H @@ -101,6 +101,13 @@ class VmmManager */ static int mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size); + /** + * @brief Find the phyiscal address bound to the given address + * @param[in] i_vaddr The address + * @return the physical address or -EFAULT @see errno.h + */ + static uint64_t findPhysicalAddress(uint64_t i_vaddr); + protected: VmmManager(); @@ -121,6 +128,9 @@ class VmmManager bool _pteMiss(task_t*, uint64_t); + /** See findPhysicalAddress */ + uint64_t _findPhysicalAddress(uint64_t i_vaddr); + public: friend class Block; diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C index 85b3d384a..2dc99d458 100644 --- a/src/kernel/basesegment.C +++ b/src/kernel/basesegment.C @@ -21,6 +21,7 @@ // // IBM_PROLOG_END #include +#include #include #include @@ -48,23 +49,25 @@ void BaseSegment::_init() SegmentManager::addSegment(this, SegmentManager::BASE_SEGMENT_ID); // Create initial static 3 or 8MB block. - uint64_t iv_baseBlockSize = 0; switch (CpuID::getCpuType()) { case CORE_POWER7: case CORE_POWER7_PLUS: case CORE_POWER8_VENICE: - iv_baseBlockSize = VmmManager::EIGHT_MEG; + iv_physMemSize = VmmManager::EIGHT_MEG; break; case CORE_POWER8_SALERNO: default: - iv_baseBlockSize = VmmManager::FOUR_MEG; + iv_physMemSize = VmmManager::FOUR_MEG; break; } - iv_block = new Block(0x0, iv_baseBlockSize); + // Base block is L3 cache physical memory size + iv_block = new Block(0x0, iv_physMemSize); iv_block->setParent(this); + // TODO iv_physMemSize needs to be recalculated when DIMM memory is avail. + // Set default page permissions on block. for (uint64_t i = 0; i < 0x800000; i += PAGESIZE) { @@ -126,3 +129,10 @@ int BaseSegment::_mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size) iv_block->appendBlock(l_block); return 0; } + +uint64_t BaseSegment::findPhysicalAddress(uint64_t i_vaddr) const +{ + if(i_vaddr < iv_physMemSize) return i_vaddr; + return (iv_block ? iv_block->findPhysicalAddress(i_vaddr) : -EFAULT); +} + diff --git a/src/kernel/block.C b/src/kernel/block.C index 19d2962f8..9a38ba3b0 100644 --- a/src/kernel/block.C +++ b/src/kernel/block.C @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -184,3 +185,24 @@ void Block::addPTE(void* i_vaddr) (l_pte->isWritable() ? VmmManager::NORMAL_ACCESS : VmmManager::READ_O_ACCESS))); } + +uint64_t Block::findPhysicalAddress(uint64_t i_vaddr) const +{ + uint64_t paddr = -EFAULT; + + if(!isContained(i_vaddr)) + { + return (iv_nextBlock ? + iv_nextBlock->findPhysicalAddress(i_vaddr) : paddr); + } + + ShadowPTE* pte = getPTE(i_vaddr); + + if (pte->isPresent() && pte->getPage() != 0) + { + paddr = pte->getPageAddr(); + paddr += i_vaddr % PAGESIZE; + } + + return paddr; +} diff --git a/src/kernel/segmentmgr.C b/src/kernel/segmentmgr.C index 10a97f911..3f43db965 100644 --- a/src/kernel/segmentmgr.C +++ b/src/kernel/segmentmgr.C @@ -21,6 +21,7 @@ // // IBM_PROLOG_END #include +#include #include #include @@ -43,13 +44,14 @@ void SegmentManager::initSLB() Singleton::instance()._initSLB(); } -bool SegmentManager::_handlePageFault(task_t* i_task, uint64_t i_addr) +uint64_t SegmentManager::findPhysicalAddress(uint64_t i_vaddr) { - // This constant should come from page manager. Segment size. - const size_t SLBE_s = 40; + return Singleton::instance()._findPhysicalAddress(i_vaddr); +} - // Get segment ID from effective address. - size_t segId = i_addr >> SLBE_s; +bool SegmentManager::_handlePageFault(task_t* i_task, uint64_t i_addr) +{ + size_t segId = getSegmentIdFromAddress(i_addr); // Call contained segment object to handle page fault. if ((segId < MAX_SEGMENTS) && (NULL != iv_segments[segId])) @@ -96,3 +98,17 @@ void SegmentManager::_initSLB() isync(); // Ensure slbmtes complete prior to continuing on. } + +uint64_t SegmentManager::_findPhysicalAddress(uint64_t i_vaddr) const +{ + uint64_t paddr = -EFAULT; + size_t segId = getSegmentIdFromAddress(i_vaddr); + + if ((segId < MAX_SEGMENTS) && (NULL != iv_segments[segId])) + { + paddr = iv_segments[segId]->findPhysicalAddress(i_vaddr); + } + + return paddr; +} + diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index c33f2b40a..098474d8e 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -36,6 +36,7 @@ #include #include #include +#include extern "C" void kernel_execute_decrementer() @@ -386,20 +387,28 @@ namespace Systemcalls */ void FutexWait(task_t * t) { - uint64_t * uaddr = (uint64_t *) TASK_GETARG0(t); + uint64_t uaddr = (uint64_t) TASK_GETARG0(t); uint64_t val = (uint64_t) TASK_GETARG1(t); // Set RC to success initially. TASK_SETRTN(t,0); - //TODO translate uaddr from user space to kernel space - // Right now they are the same. - - uint64_t rc = FutexManager::wait(t,uaddr,val); - if (rc != 0) // Can only set rc if we still have control of the task, - // which is only (for certain) on error rc's. + //translate uaddr from user space to kernel space + uaddr = VmmManager::findPhysicalAddress(uaddr); + if(uaddr != (uint64_t)(-EFAULT)) + { + uint64_t rc = FutexManager::wait(t,(uint64_t *)uaddr,val); + if (rc != 0) // Can only set rc if we still have control of the task, + // which is only (for certain) on error rc's. + { + TASK_SETRTN(t,rc); + } + } + else { - TASK_SETRTN(t,rc); + printk("Task %d terminated. No physical address found for address 0x%p", + t->tid, (void *) uaddr); + TaskEnd(t); } } @@ -409,15 +418,23 @@ namespace Systemcalls */ void FutexWake(task_t * t) { - uint64_t * uaddr = (uint64_t *) TASK_GETARG0(t); + uint64_t uaddr = (uint64_t) TASK_GETARG0(t); uint64_t count = (uint64_t) TASK_GETARG1(t); - // TODO translate uaddr from user space to kernel space - // Right now they are the same - - uint64_t started = FutexManager::wake(uaddr,count); + // translate uaddr from user space to kernel space + uaddr = VmmManager::findPhysicalAddress(uaddr); + if(uaddr != (uint64_t)(-EFAULT)) + { + uint64_t started = FutexManager::wake((uint64_t *)uaddr,count); - TASK_SETRTN(t,started); + TASK_SETRTN(t,started); + } + else + { + printk("Task %d terminated. No physical address found for address 0x%p", + t->tid, (void *) uaddr); + TaskEnd(t); + } } /** diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C index 7fc41f489..ba5b795f3 100644 --- a/src/kernel/vmmmgr.C +++ b/src/kernel/vmmmgr.C @@ -65,6 +65,11 @@ bool VmmManager::pteMiss(task_t* t, uint64_t effAddr) return Singleton::instance()._pteMiss(t, effAddr); } +uint64_t VmmManager::findPhysicalAddress(uint64_t i_vaddr) +{ + return Singleton::instance()._findPhysicalAddress(i_vaddr); +} + /** * STATIC * @brief DEPRECATED @@ -138,3 +143,17 @@ Spinlock* VmmManager::getLock() return &Singleton::instance().lock; } +uint64_t VmmManager::_findPhysicalAddress(uint64_t i_vaddr) +{ + uint64_t paddr = 0; + + lock.lock(); + + paddr = SegmentManager::findPhysicalAddress(i_vaddr); + + lock.unlock(); + + return paddr; +} + + -- cgit v1.2.1