summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/syscall_pagedir.c95
1 files changed, 93 insertions, 2 deletions
diff --git a/sys/syscall_pagedir.c b/sys/syscall_pagedir.c
index 6e773bf..2b81dfa 100644
--- a/sys/syscall_pagedir.c
+++ b/sys/syscall_pagedir.c
@@ -1,3 +1,4 @@
+#include "api/memory.h"
#include "api/syscall.h"
#include "hal/memory.h"
#include "jove.h"
@@ -58,6 +59,86 @@ s_syscall_pagedir_get_untyped(
}
static int
+s_syscall_pagedir_get_mapping(
+ jove_owned_obj_t *pagedir,
+ size_t bytes_left,
+ void *payload_data)
+{
+ size_t bytes_needed = sizeof(struct pagedir_mapping);
+ CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");
+
+ virtaddr_t vptr = *((virtaddr_t*)payload_data);
+ if(vptr > JOVE_USERMEMORY_LIMIT) {
+ klogf("Virtual address %p is out of bounds!\n", vptr);
+ return -EOOB;
+ }
+
+ virtaddr_t *mapping = pagedir_get_mapping(pagedir, vptr);
+ if(mapping == NULL) return -errno;
+
+ struct pagedir_mapping *payload = payload_data;
+
+ payload->pfn = pagedir_mapping_get_pfn(mapping);
+ payload->flags.present = pagedir_mapping_is_present(mapping);
+ payload->flags.writeable = pagedir_mapping_is_writeable(mapping);
+ payload->flags.executable = pagedir_mapping_is_executable(mapping);
+ return 0;
+}
+
+static int
+s_syscall_pagedir_transfer(
+ lockstack_t *lockstack,
+ jove_obj_t *rootdir,
+ jove_owned_obj_t *pagedir,
+ size_t bytes_left,
+ void *payload_data)
+{
+ //Verify the message is big enough for the payload.
+ size_t bytes_needed = sizeof(struct syscall_pagedir_transfer);
+ CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload");
+
+ //Verify the payload is big enough for the target path.
+ struct syscall_pagedir_transfer *payload = payload_data;
+ bytes_needed += sizeof(objpath_part_t) * payload->target_path_length;
+ CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for target path");
+
+ //Verify the target object is a pagedir with the correct permissions.
+ jove_perm_obj_t target = link_traverse_objdir(rootdir, payload->target_path_length, payload->target_path);
+ CHECK_OBJEXISTS(target.obj, "Target path does not point to a valid object");
+ lockstack_push(lockstack, target.obj);
+
+ CHECK_OBJTYPE(target.obj, JOVE_OBJ_PAGEDIR, "Target object is not a JOVE_OBJ_PAGEDIR");
+ CHECK_OBJPERM(target, SYSCALL_PERM_PAGEDIR_TRANSFER_TGT, "Not allowed to transfer to target");
+
+ //Verify subject has a mapping at the given address.
+ virtaddr_t *subject_mapping = pagedir_get_mapping(pagedir, payload->subject_address);
+ if(subject_mapping == NULL) {
+ klogf("Subject page directory does not have tables for %p\n", payload->subject_address);
+ return -errno;
+ }
+
+ //Verify target has a mapping at the given address.
+ virtaddr_t *target_mapping = pagedir_get_mapping(target.obj, payload->target_address);
+ if(target_mapping == NULL) {
+ klogf("Target page directory does not have tables for %p\n", payload->target_address);
+ return -errno;
+ }
+
+ //Verify target mapping is not marked present.
+ if(pagedir_mapping_is_present(target_mapping)) {
+ klogf("Target page at %p is marked as present\n", payload->target_address);
+ return -EBUSY;
+ }
+
+ //Move the mapping over and return.
+ *target_mapping = *subject_mapping;
+ *subject_mapping = 0;
+
+ pagedir_invlpg(payload->subject_address);
+ return 0;
+}
+
+static int
s_syscall_pagedir_unmap(
lockstack_t *lockstack,
jove_obj_t *objdir,
@@ -111,7 +192,7 @@ s_syscall_pagedir_map_frame(
}
struct syscall_pagedir_map *payload = payload_data;
- sysret = pagedir_map_untyped_frame(pagedir, &untyped, payload->virtual_address, payload->page_flags);
+ sysret = pagedir_map_untyped_frame(pagedir, &untyped, payload->virtual_address, payload->flags);
if(sysret == 0)
obj_settype(untyped.obj, JOVE_OBJ_NONE);
@@ -186,7 +267,7 @@ s_syscall_pagedir_map_shmem(
}
return pagedir_map_shmem_frame(pagedir, &shmem, payload->page_offset,
- payload->virtual_address, payload->page_flags);
+ payload->virtual_address, payload->flags);
}
static int
@@ -234,6 +315,16 @@ _syscall_handle_pagedir(syscall_context_t *ctx)
void *payload = ctx->payload;
switch(header->callid) {
+ case SYSCALL_PAGEDIR_GET_MAPPING:
+ if(target->permissions & SYSCALL_PERM_PAGEDIR_GET_MAPPING)
+ return s_syscall_pagedir_get_mapping(target->obj, bytes_left, payload);
+ return -EPERM;
+
+ case SYSCALL_PAGEDIR_TRANSFER:
+ if(target->permissions & SYSCALL_PERM_PAGEDIR_TRANSFER)
+ return s_syscall_pagedir_transfer(
+ lockstack, objdir, target->obj, bytes_left, payload);
+
case SYSCALL_PAGEDIR_MAP_FRAME:
if(target->permissions & SYSCALL_PERM_PAGEDIR_MAP_FRAME)
return s_syscall_pagedir_map_frame(lockstack, objdir, target->obj, bytes_left, payload);