diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-19 11:06:32 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-10-19 11:06:32 -0400 |
| commit | 44f9642bfc9ce9f740d508670befb569e06621a2 (patch) | |
| tree | ff64ec6fd0562b4b9e6ba665fceeec52f2371840 /sys | |
| parent | b2920331b103d43793ac8be927a80a593ce0be5a (diff) | |
| download | jove-kernel-44f9642bfc9ce9f740d508670befb569e06621a2.tar.gz jove-kernel-44f9642bfc9ce9f740d508670befb569e06621a2.tar.bz2 jove-kernel-44f9642bfc9ce9f740d508670befb569e06621a2.zip | |
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/syscall_pagedir.c | 95 |
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); |
