diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/kernel/basesegment.H | 4 | ||||
-rw-r--r-- | src/include/kernel/block.H | 16 | ||||
-rw-r--r-- | src/include/kernel/spte.H | 12 | ||||
-rw-r--r-- | src/include/kernel/vmmmgr.H | 4 | ||||
-rw-r--r-- | src/kernel/basesegment.C | 46 | ||||
-rw-r--r-- | src/kernel/block.C | 110 | ||||
-rw-r--r-- | src/kernel/vmmmgr.C | 4 | ||||
-rw-r--r-- | src/usr/testcore/kernel/slbtest.H | 40 |
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: |