summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/kernel/basesegment.H28
-rw-r--r--src/include/kernel/syscalls.H5
-rw-r--r--src/include/kernel/vmmmgr.H16
-rw-r--r--src/include/sys/mm.h27
-rw-r--r--src/kernel/basesegment.C9
-rw-r--r--src/kernel/syscall.C18
-rw-r--r--src/kernel/vmmmgr.C21
-rw-r--r--src/lib/syscall_mm.C10
-rw-r--r--src/usr/testcore/kernel/slbtest.H16
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:
OpenPOWER on IntegriCloud