summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/kernel/basesegment.H4
-rw-r--r--src/include/kernel/block.H16
-rw-r--r--src/include/kernel/spte.H12
-rw-r--r--src/include/kernel/vmmmgr.H4
-rw-r--r--src/kernel/basesegment.C46
-rw-r--r--src/kernel/block.C110
-rw-r--r--src/kernel/vmmmgr.C4
-rw-r--r--src/usr/testcore/kernel/slbtest.H40
8 files changed, 219 insertions, 17 deletions
diff --git a/src/include/kernel/basesegment.H b/src/include/kernel/basesegment.H
index 574be1a1f..1064e1f82 100644
--- a/src/include/kernel/basesegment.H
+++ b/src/include/kernel/basesegment.H
@@ -105,7 +105,7 @@ class BaseSegment : public Segment
*/
static int mmSetPermission(void* i_va,
uint64_t i_size,
- PAGE_PERMISSIONS i_access_type);
+ uint64_t i_access_type);
/**
* @breif Cast out older physical memory pages
* @param[in] castout Constraint
@@ -144,7 +144,7 @@ class BaseSegment : public Segment
*/
int _mmSetPermission(void* i_va,
uint64_t i_size,
- PAGE_PERMISSIONS i_access_type);
+ uint64_t i_access_type);
};
diff --git a/src/include/kernel/block.H b/src/include/kernel/block.H
index 88c6664c2..405791e94 100644
--- a/src/include/kernel/block.H
+++ b/src/include/kernel/block.H
@@ -32,6 +32,7 @@
#include <kernel/blockmsghdlr.H>
#include <kernel/msghandler.H>
#include <kernel/ptmgr.H>
+#include <sys/mm.h>
class ShadowPTE;
class Segment;
@@ -232,6 +233,21 @@ class Block
*/
void releaseAllPages();
+ /**
+ * @brief Sets the page permissions for a given virtual addr
+ * and a size of memory needing updated permissions
+ * @param i_va[in] - virtual address of the beginning of the
+ * pages that need updating.
+ * @param i_size[in] - range of memory that needs updating
+ * if i_size equals 0 then we only need to update an
+ * individual page.
+ * @param i_access_type[in] - type of permission to set using
+ * PAGE_PERMISSION enum values OR'd together
+ * @return int - 0 for successful block allocation,
+ * non-zero otherwise
+ */
+ int mmSetPermission(uint64_t i_va, uint64_t i_size, uint64_t i_access_type);
+
private:
/** Base address of the block */
const uint64_t iv_baseAddr;
diff --git a/src/include/kernel/spte.H b/src/include/kernel/spte.H
index abd81dff3..49c15f83c 100644
--- a/src/include/kernel/spte.H
+++ b/src/include/kernel/spte.H
@@ -53,7 +53,8 @@ class ShadowPTE
uint32_t page:20;
/** Page is present (is PN valid?). */
uint32_t present:1;
-
+ /** May the page be read */
+ uint32_t readable:1;
/** May the page be written to. */
uint32_t writable:1;
/** May code be executed off page. */
@@ -65,12 +66,10 @@ class ShadowPTE
uint32_t dirty:1;
/** Allocate from a zero'd page. */
uint32_t allocate_from_zero:1;
-
/** LRU value - lower means it was accessed more recently. */
uint32_t last_access:3;
-
/** Reserved for future use. */
- uint32_t reserved:3;
+ uint32_t reserved:2;
} PACKED;
};
@@ -91,7 +90,10 @@ class ShadowPTE
bool isPresent() const { return present; };
/** Set present bit. */
void setPresent(bool i_present) { present = i_present; };
-
+ /** Get readable bit. */
+ bool isReadable() const { return readable; };
+ /** Set readable bit. */
+ void setReadable(bool i_read) { readable = i_read; };
/** Get writable bit. */
bool isWritable() const { return writable; };
/** Set writable bit. */
diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H
index 5c7a75d5d..ce7aedafb 100644
--- a/src/include/kernel/vmmmgr.H
+++ b/src/include/kernel/vmmmgr.H
@@ -147,7 +147,7 @@ class VmmManager
* boundary, along with the given size will be 'rounded' up to the
* nearest divisible page size.
*/
- static int mmSetPermission(void* i_va,uint64_t i_size, PAGE_PERMISSIONS i_access_type);
+ static int mmSetPermission(void* i_va,uint64_t i_size, uint64_t i_access_type);
protected:
VmmManager();
@@ -172,7 +172,7 @@ class VmmManager
uint64_t _findPhysicalAddress(uint64_t i_vaddr);
/* See mmSetPermission */
- int _mmSetPermission(void* i_va,uint64_t i_size, PAGE_PERMISSIONS i_access_type);
+ int _mmSetPermission(void* i_va,uint64_t i_size, uint64_t i_access_type);
/** See castOutPages */
void _castOutPages(castout_t i_ct);
diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C
index eab00accc..8eb7e5484 100644
--- a/src/kernel/basesegment.C
+++ b/src/kernel/basesegment.C
@@ -142,11 +142,53 @@ void BaseSegment::updateRefCount( uint64_t i_vaddr,
}
/**
+ * STATIC
* Sets the Page Permissions for a given page via virtual address
*/
-int BaseSegment::mmSetPermission(void* i_va, uint64_t i_size,PAGE_PERMISSIONS i_access_type)
+int BaseSegment::mmSetPermission(void* i_va, uint64_t i_size, uint64_t i_access_type)
{
- return 0;
+ return Singleton<BaseSegment>::instance()._mmSetPermission(i_va,i_size,i_access_type);
+}
+
+
+/**
+ * Sets the Page Permissions for a given page via virtual address
+ */
+int BaseSegment::_mmSetPermission(void* i_va, uint64_t i_size, uint64_t i_access_type)
+{
+ int l_rc = 0;
+ Block *l_block = iv_block;
+ uint64_t l_va = reinterpret_cast<uint64_t>(i_va);
+
+
+ do
+ {
+ // If the va is not part of this block
+ if (!(l_block->isContained(l_va)))
+ {
+ // Check to see if there is a next block
+ if (l_block->iv_nextBlock)
+ {
+ // set local block to the next block
+ l_block = l_block->iv_nextBlock;
+ }
+ else
+ {
+ // address passed in does not fall into a block
+ return -EINVAL;
+ }
+ }
+ // The virtual address falls within this block
+ else
+ {
+ // Set the permission on the the current block.
+ return(l_block->mmSetPermission(l_va, i_size, i_access_type));
+
+ }
+ } while (l_block->iv_nextBlock);
+
+ return l_rc;
+
}
void BaseSegment::castOutPages(uint64_t i_type)
diff --git a/src/kernel/block.C b/src/kernel/block.C
index 63c1fae92..f72a8f6f7 100644
--- a/src/kernel/block.C
+++ b/src/kernel/block.C
@@ -33,6 +33,7 @@
#include <kernel/ptmgr.H>
#include <kernel/pagemgr.H>
#include <kernel/console.H>
+#include <util/align.H>
Block::~Block()
{
@@ -171,16 +172,19 @@ void Block::setPhysicalPage(uint64_t i_vAddr, uint64_t i_pAddr,
switch(i_access)
{
case VmmManager::READ_O_ACCESS:
+ pte->setReadable(true);
pte->setExecutable(false);
pte->setWritable(false);
break;
case VmmManager::NORMAL_ACCESS:
+ pte->setReadable(true);
pte->setExecutable(false);
pte->setWritable(true);
break;
case VmmManager::RO_EXE_ACCESS:
+ pte->setReadable(true);
pte->setExecutable(true);
pte->setWritable(false);
break;
@@ -311,6 +315,7 @@ void Block::updateRefCount( uint64_t i_vaddr,
}
+
bool Block::evictPage(ShadowPTE* i_pte)
{
ShadowPTE* pte = i_pte;
@@ -400,3 +405,108 @@ size_t Block::castOutPages(uint64_t i_type)
return cast_out;
}
+
+
+int Block::mmSetPermission(uint64_t i_va, uint64_t i_size,uint64_t i_access_type)
+{
+ int l_rc = 0;
+
+ // Need to align the page address and the size on a page boundary. before I get the page.
+ uint64_t l_aligned_va = ALIGN_PAGE_DOWN(i_va);
+ uint64_t l_aligned_size = ALIGN_PAGE(i_size);
+//printk("aligned VA = 0x%.lX aligned size = %ld\n", l_aligned_va, l_aligned_size);
+
+ // if size is zero..we are only updating 1 page.. so need to increment the size to 1 page
+ if (i_size == 0)
+ {
+ l_aligned_size+=PAGESIZE;
+ }
+
+ // loop through all the pages asked for based on passed aligned
+ // Virtual address and passed in aligned size.
+ for(uint64_t cur_page_addr = l_aligned_va;
+ cur_page_addr < (l_aligned_va + l_aligned_size);
+ cur_page_addr += PAGESIZE)
+ {
+//printk("aligned VA = 0x%.lX aligned size = %ld\n", l_aligned_va, l_aligned_size);
+ ShadowPTE* spte = getPTE(cur_page_addr);
+
+ // if the page present need to delete the hardware
+ // page table entry before we set permissions.
+ if (spte->isPresent())
+ {
+ // delete the hardware page table entry
+ PageTableManager::delEntry(cur_page_addr);
+ }
+
+ // If read_only
+ if ( i_access_type & READ_ONLY)
+ {
+ spte->setReadable(true);
+ spte->setExecutable(false);
+ spte->setWritable(false);
+
+ // If the writable or executable access bits
+ // are set.. invalid combination.. return error
+ if ((i_access_type & WRITABLE) || (i_access_type & EXECUTABLE))
+ {
+ return -EINVAL;
+ }
+ }
+ // if writable
+ else if ( i_access_type & WRITABLE)
+ {
+ spte->setReadable(true);
+ spte->setWritable(true);
+ spte->setExecutable(false);
+
+ if (i_access_type & EXECUTABLE)
+ {
+ // error condition.. not valid to be
+ // writable and executable
+ return -EINVAL;
+ }
+ }
+ // if executable
+ else if ( i_access_type & EXECUTABLE)
+ {
+ spte->setReadable(true);
+ spte->setExecutable(true);
+ spte->setWritable(false);
+ }
+
+ // if write_tracked
+ if ( i_access_type & WRITE_TRACKED)
+ {
+ spte->setWriteTracked(true);
+ }
+ else
+ {
+ spte->setWriteTracked(false);
+ }
+
+ // if Allocate from zero
+ if ( i_access_type & ALLOCATE_FROM_ZERO)
+ {
+ spte->setAllocateFromZero(true);
+ }
+ // not allocated from zero
+ else
+ {
+ spte->setAllocateFromZero(false);
+ }
+
+ // if no access
+ if ( i_access_type & NO_ACCESS)
+ {
+ spte->setReadable(false);
+ spte->setExecutable(false);
+ spte->setWritable(false);
+ spte->setAllocateFromZero(false);
+ spte->setWriteTracked(false);
+ }
+
+ }
+ return l_rc;
+
+}
diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C
index b2026944e..c923d80e0 100644
--- a/src/kernel/vmmmgr.C
+++ b/src/kernel/vmmmgr.C
@@ -176,13 +176,13 @@ int VmmManager::mmRemovePages(PAGE_REMOVAL_OPS i_op, void* i_vaddr,
}
-int VmmManager::mmSetPermission(void* i_va, uint64_t i_size, PAGE_PERMISSIONS i_access_type)
+int VmmManager::mmSetPermission(void* i_va, uint64_t i_size, uint64_t i_access_type)
{
return Singleton<VmmManager>::instance()._mmSetPermission(i_va, i_size, i_access_type);
}
-int VmmManager::_mmSetPermission(void* i_va, uint64_t i_size, PAGE_PERMISSIONS i_access_type)
+int VmmManager::_mmSetPermission(void* i_va, uint64_t i_size, uint64_t i_access_type)
{
int rc = 1;
diff --git a/src/usr/testcore/kernel/slbtest.H b/src/usr/testcore/kernel/slbtest.H
index d3613720c..fef88b5d5 100644
--- a/src/usr/testcore/kernel/slbtest.H
+++ b/src/usr/testcore/kernel/slbtest.H
@@ -110,16 +110,48 @@ class slbtest: public CxxTest::TestSuite
void testSetPerm()
{
- int rc = -1;
+ int rc = 1;
uint64_t va = 0xC800000000; //800GB
uint64_t size = 0x0;
- PAGE_PERMISSIONS access = WRITABLE; //Access value
- printk("Update Page Permissions. but not real page or address\n");
+ uint64_t access = (uint64_t)(WRITABLE | ALLOCATE_FROM_ZERO); //Access value
+ printkd("Update Page Permissions. Writable/Allocate from zero to addr 800Gb and size = 0 \n");
+ rc = mm_set_permission(reinterpret_cast<void*>(va), size, access);
+ if (rc != 0)
+ {
+ TS_FAIL(" 1 Failed to Update permissions.\n");
+ }
+
+ rc = 1;
+ size = PAGESIZE * 3;
+ access = (uint64_t)(WRITE_TRACKED); //Access value
+ printkd("Update Page Permissions. write_tracked to addr 800Gb and size = 3 pages\n");
+ rc = mm_set_permission(reinterpret_cast<void*>(va), size, access);
+ if (rc != 0)
+ {
+ TS_FAIL("2 Failed to Update permissions.\n");
+ }
+ rc = 1;
+ va = 0xC800000000 + (PAGESIZE * 10);
+ size = PAGESIZE * 2;
+ access = (uint64_t)(EXECUTABLE); //Access value
+ printkd("Update Page Permissions. executable to addr C800A000 and size = 2 pages\n");
rc = mm_set_permission(reinterpret_cast<void*>(va), size, access);
if (rc != 0)
{
- TS_FAIL("Failed to Update permissions.\n");
+ TS_FAIL("3 Failed to Update permissions.\n");
}
+ rc = 0;
+ va = 0xC800000000; //800GB
+ size = 0x0;
+ access = (uint64_t)(WRITABLE | EXECUTABLE); //Access value
+ printkd("Update Page Permissions. Writable/executable to addr 800Gb and size = 0 \n");
+ rc = mm_set_permission(reinterpret_cast<void*>(va), size, access);
+ if (rc == 0)
+ {
+ printk("Error .. invalid combination that did not get detected\n");
+ TS_FAIL(" 4 Failed to detect a bad parm condition.\n");
+ }
+
}
private:
OpenPOWER on IntegriCloud