summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDoug Gilbert <dgilbert@us.ibm.com>2011-08-22 17:14:23 -0500
committerDouglas R. Gilbert <dgilbert@us.ibm.com>2011-08-25 13:52:09 -0500
commitbf46e7954689c41cccc897b8b00bcc5db5245374 (patch)
treec7807ff84dd5f8519fb0b065e03ba4939255d485 /src
parent968add63523933786a85ab271b277d79dc5851e6 (diff)
downloadtalos-hostboot-bf46e7954689c41cccc897b8b00bcc5db5245374.tar.gz
talos-hostboot-bf46e7954689c41cccc897b8b00bcc5db5245374.zip
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 <iawillia@us.ibm.com> Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src')
-rw-r--r--src/include/kernel/basesegment.H14
-rw-r--r--src/include/kernel/block.H10
-rw-r--r--src/include/kernel/segment.H9
-rw-r--r--src/include/kernel/segmentmgr.H18
-rw-r--r--src/include/kernel/vmmmgr.H10
-rw-r--r--src/kernel/basesegment.C18
-rw-r--r--src/kernel/block.C22
-rw-r--r--src/kernel/segmentmgr.C26
-rw-r--r--src/kernel/syscall.C45
-rw-r--r--src/kernel/vmmmgr.C19
10 files changed, 167 insertions, 24 deletions
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 <kernel/task.H>
+#include <errno.h>
/** @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 <kernel/task.H>
+#include <builtins.h>
// 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 <limits.h>
+#include <errno.h>
#include <util/singleton.H>
#include <kernel/basesegment.H>
@@ -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 <limits.h>
#include <assert.h>
#include <string.h>
+#include <errno.h>
#include <sys/msg.h>
@@ -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 <assert.h>
+#include <errno.h>
#include <arch/ppc.H>
#include <util/singleton.H>
@@ -43,13 +44,14 @@ void SegmentManager::initSLB()
Singleton<SegmentManager>::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<SegmentManager>::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 <kernel/cpuid.H>
#include <kernel/misc.H>
#include <kernel/msghandler.H>
+#include <kernel/vmmmgr.H>
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<VmmManager>::instance()._pteMiss(t, effAddr);
}
+uint64_t VmmManager::findPhysicalAddress(uint64_t i_vaddr)
+{
+ return Singleton<VmmManager>::instance()._findPhysicalAddress(i_vaddr);
+}
+
/**
* STATIC
* @brief DEPRECATED
@@ -138,3 +143,17 @@ Spinlock* VmmManager::getLock()
return &Singleton<VmmManager>::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;
+}
+
+
OpenPOWER on IntegriCloud