diff options
-rw-r--r-- | src/include/kernel/basesegment.H | 28 | ||||
-rw-r--r-- | src/include/kernel/syscalls.H | 5 | ||||
-rw-r--r-- | src/include/kernel/vmmmgr.H | 16 | ||||
-rw-r--r-- | src/include/sys/mm.h | 27 | ||||
-rw-r--r-- | src/kernel/basesegment.C | 9 | ||||
-rw-r--r-- | src/kernel/syscall.C | 18 | ||||
-rw-r--r-- | src/kernel/vmmmgr.C | 21 | ||||
-rw-r--r-- | src/lib/syscall_mm.C | 10 | ||||
-rw-r--r-- | src/usr/testcore/kernel/slbtest.H | 16 |
9 files changed, 146 insertions, 4 deletions
diff --git a/src/include/kernel/basesegment.H b/src/include/kernel/basesegment.H index 72869d535..da262c2a0 100644 --- a/src/include/kernel/basesegment.H +++ b/src/include/kernel/basesegment.H @@ -27,6 +27,7 @@ #define __KERNEL_BASESEGMENT_H #include <kernel/segment.H> +//#include <kernel/vmmmgr.H> // Forward declaration. class MessageQueue; @@ -93,6 +94,19 @@ class BaseSegment : public Segment */ virtual uint64_t findPhysicalAddress(uint64_t i_vaddr) const; + /** + * @brief Sets the page permissions for a given virtual address and size. + * @param i_va[in] - virtual address of the page(s) to set permissions + * @param i_size[in] - range of memory that needs permissions updated... + * if i_size equals 0 then we only need to update an + * individual page. + * @param i_access_type[in] - type of permission to set + * @return int - 0 for successful block allocation, non-zero otherwise + */ + static int mmSetPermission(void* i_va, + uint64_t i_size, + PAGE_PERMISSIONS i_access_type); + private: /** * @brief Internal implementation of init function. @@ -114,6 +128,20 @@ class BaseSegment : public Segment */ int _mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size); + /** + * @brief Sets the page permissions for a given virtual address and size. + * @param i_va[in] - virtual address of the page(s) to set permissions + * @param i_size[in] - range of memory that needs permissions updated... + * if i_size equals 0 then we only need to update an individual + * page. + * @param i_access_type[in] - type of permission to set + * @return int - 0 for successful block allocation, non-zero otherwise + */ + int _mmSetPermission(void* i_va, + uint64_t i_size, + PAGE_PERMISSIONS i_access_type); + + }; #endif diff --git a/src/include/kernel/syscalls.H b/src/include/kernel/syscalls.H index bdffea120..70dd436be 100644 --- a/src/include/kernel/syscalls.H +++ b/src/include/kernel/syscalls.H @@ -97,7 +97,10 @@ namespace Systemcalls /** mm_remove_pages() */ MM_REMOVE_PAGES, - SYSCALL_MAX + /** mm_set_permission() */ + MM_SET_PERMISSION, + + SYSCALL_MAX }; /** @enum SysCalls_FastPath diff --git a/src/include/kernel/vmmmgr.H b/src/include/kernel/vmmmgr.H index 2d0d0297d..ef8e6c362 100644 --- a/src/include/kernel/vmmmgr.H +++ b/src/include/kernel/vmmmgr.H @@ -118,6 +118,19 @@ class VmmManager */ static int mmRemovePages(PAGE_REMOVAL_OPS i_op, void* i_vaddr, uint64_t i_size); + /** + * @brief Sets the permissions for a given page or range of pages + * @param i_va[in] - Virtual address of the page to update permission + * @param i_size[in] - range of memory that needs permissions updated... + * if i_size equals 0 then we only need to update an + * individual page. + * @return int - 0 for successful permission update, non-zero otherwise + * + * The given virtual address will be 'rounded' down to the nearest page + * 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); protected: VmmManager(); @@ -141,6 +154,9 @@ class VmmManager /** See findPhysicalAddress */ uint64_t _findPhysicalAddress(uint64_t i_vaddr); + /* See mmSetPermission */ + int _mmSetPermission(void* i_va,uint64_t i_size, PAGE_PERMISSIONS i_access_type); + public: friend class Block; diff --git a/src/include/sys/mm.h b/src/include/sys/mm.h index a14e4f83d..d01dbc851 100644 --- a/src/include/sys/mm.h +++ b/src/include/sys/mm.h @@ -41,6 +41,21 @@ enum PAGE_REMOVAL_OPS FLUSH, }; +/** + * Page permission types mapped to the same bits in the Shadow PTE + */ +enum PAGE_PERMISSIONS +{ + READ_ONLY = 0x00000001, + WRITABLE = 0x000000002, + EXECUTABLE = 0x00000004, + WRITE_TRACKED = 0x00000008, + ALLOCATE_FROM_ZERO = 0x00000010, + NO_ALLOCATE_FROM_ZERO = 0x00000020, + NO_ACCESS = 0x00000040, +}; + + /** @fn mm_alloc_block() * @brief System call to allocate virtual memory block in the base segment * @@ -63,6 +78,18 @@ int mm_alloc_block(msg_q_t mq,void* va,uint64_t size); */ int mm_remove_pages(PAGE_REMOVAL_OPS i_op, void* i_vaddr, uint64_t i_size); +/** @fn mm_set_permission() + * @brief System call to set the page permissions + * + * @param[in] va - virtual address of the pages(s) to update permission + * @param[in] size - requested size of memory in bytes + * if size = 0 then only a single page will be updated. + * @param[in] access_type - Type of permission to be given to the page(s) + * + * @return int - 0 for successful update of permission, non-zero otherwise + */ +int mm_set_permission(void* va, uint64_t size, PAGE_PERMISSIONS access_type); + #ifdef __cplusplus } #endif diff --git a/src/kernel/basesegment.C b/src/kernel/basesegment.C index fc053f856..e59e41753 100644 --- a/src/kernel/basesegment.C +++ b/src/kernel/basesegment.C @@ -28,7 +28,6 @@ #include <kernel/basesegment.H> #include <kernel/segmentmgr.H> #include <kernel/block.H> -#include <kernel/vmmmgr.H> #include <kernel/cpuid.H> @@ -140,3 +139,11 @@ void BaseSegment::updateRefCount( uint64_t i_vaddr, // Just call over to block chain iv_block->updateRefCount(i_vaddr, i_stats); } + +/** + * 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) +{ + return 0; +} diff --git a/src/kernel/syscall.C b/src/kernel/syscall.C index 0e3395d9e..ecfdd9b1b 100644 --- a/src/kernel/syscall.C +++ b/src/kernel/syscall.C @@ -82,6 +82,8 @@ namespace Systemcalls void CpuDDLevel(task_t *t); void MmAllocBlock(task_t *t); void MmRemovePages(task_t *t); + void MmSetPermission(task_t *t); + syscall syscalls[] = { @@ -116,7 +118,8 @@ namespace Systemcalls &MmAllocBlock, // MM_ALLOC_BLOCK &MmRemovePages, // MM_REMOVE_PAGES - }; + &MmSetPermission, // MM_SET_PERMISSION + }; }; extern "C" @@ -520,4 +523,17 @@ namespace Systemcalls TASK_SETRTN(t, VmmManager::mmRemovePages(oper,vaddr,size)); } + /** + * Set the Permissions on a block containing the virtual address passed in. + * @param[in] t: The task used to set Page Permissions for a given block + */ + void MmSetPermission(task_t* t) + { + void* va = (void*)TASK_GETARG0(t); + uint64_t size = (uint64_t)TASK_GETARG1(t); + PAGE_PERMISSIONS access_type = (PAGE_PERMISSIONS)TASK_GETARG2(t); + + TASK_SETRTN(t, VmmManager::mmSetPermission(va,size, access_type)); + } + }; diff --git a/src/kernel/vmmmgr.C b/src/kernel/vmmmgr.C index 684570daa..4009ff380 100644 --- a/src/kernel/vmmmgr.C +++ b/src/kernel/vmmmgr.C @@ -140,6 +140,7 @@ int VmmManager::mmAllocBlock(MessageQueue* i_mq,void* i_va,uint64_t i_size) return BaseSegment::mmAllocBlock(i_mq,i_va,i_size); } + Spinlock* VmmManager::getLock() { return &Singleton<VmmManager>::instance().lock; @@ -163,3 +164,23 @@ int VmmManager::mmRemovePages(PAGE_REMOVAL_OPS i_op, void* i_vaddr, { return 0; } + + +int VmmManager::mmSetPermission(void* i_va, uint64_t i_size, PAGE_PERMISSIONS 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 rc = 1; + + lock.lock(); + + rc = BaseSegment::mmSetPermission(i_va, i_size, i_access_type); + + lock.unlock(); + + return rc; +} diff --git a/src/lib/syscall_mm.C b/src/lib/syscall_mm.C index 52e0a5340..b72e897ba 100644 --- a/src/lib/syscall_mm.C +++ b/src/lib/syscall_mm.C @@ -23,6 +23,7 @@ #include <sys/syscall.h> #include <sys/mm.h> #include <arch/ppc.H> +#include <kernel/vmmmgr.H> using namespace Systemcalls; @@ -71,3 +72,12 @@ void mm_icache_invalidate(void * i_addr, size_t i_cpu_word_count) isync(); } + + +/** + * System call update permissions on a page for a given virtual address + */ +int mm_set_permission(void* va, uint64_t size, PAGE_PERMISSIONS access_type) +{ + return (int64_t)_syscall3(MM_SET_PERMISSION, va, (void*)size, (void*)access_type); +} diff --git a/src/usr/testcore/kernel/slbtest.H b/src/usr/testcore/kernel/slbtest.H index a4b2a46a4..d3613720c 100644 --- a/src/usr/testcore/kernel/slbtest.H +++ b/src/usr/testcore/kernel/slbtest.H @@ -105,8 +105,22 @@ class slbtest: public CxxTest::TestSuite if (rc != 0) { TS_FAIL("Failed to remove pages\n"); + } + } + + void testSetPerm() + { + 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"); + rc = mm_set_permission(reinterpret_cast<void*>(va), size, access); + if (rc != 0) + { + TS_FAIL("Failed to Update permissions.\n"); } - } + } private: |