summaryrefslogtreecommitdiffstats
path: root/arch/x86_64/syscall-invoke-mapping.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/syscall-invoke-mapping.c')
-rw-r--r--arch/x86_64/syscall-invoke-mapping.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/arch/x86_64/syscall-invoke-mapping.c b/arch/x86_64/syscall-invoke-mapping.c
new file mode 100644
index 0000000..efecbdf
--- /dev/null
+++ b/arch/x86_64/syscall-invoke-mapping.c
@@ -0,0 +1,124 @@
+#include "syscall/handles.h"
+#include "arch/x86_64/syscall.h"
+#include "arch/x86_64/page.h"
+#include <stddef.h>
+#include "error.h"
+#include "lock.h"
+
+static int
+s_handle_invoke_mapping_release(
+ objdir_t *root_dir,
+ objdir_entry_t *target_entry,
+ uint8_t *payload,
+ size_t payload_at
+ )
+{
+ target_entry->data = 0;
+ target_entry->type = KO_NONE;
+ return 0;
+}
+
+static int
+s_handle_invoke_mapping_get(
+ objdir_t *root_dir,
+ objdir_entry_t *target_entry,
+ uint8_t *payload,
+ size_t payload_at
+ )
+{
+ pmli_t pmli;
+ SYSCALL_PAYLOAD_TAKEL(payload, payload_at, pmli, pmli_t);
+
+ if(pmli > 511) return -KE_OOB;
+
+ uint8_t level = target_entry->data & 3;
+ pmle_t *target_pml = (pmle_t*)vmem_phys_tovirt(target_entry->data & ~3ULL);
+ if(level == 3 && pmli > 255) return -KE_OOB;
+ if(level == 0) return -KE_BADOBJ;
+
+ size_t dest_pathw;
+ objdir_entry_t *dest_entry;
+ SYSCALL_PAYLOAD_TAKEOBJ(payload, payload_at, dest_pathw, dest_entry);
+ if(dest_entry->type != KO_NONE) return -KE_FULL;
+
+ pmle_t pmle = target_pml[pmli];
+ if(!pmle.p) return -KE_DNE;
+
+ *dest_entry = (objdir_entry_t) {
+ .type = KO_MEMORY_MAPPING,
+ .data = (((uintptr_t)target_pml[pmli].paddr) << 12ULL) | (level - 1)
+ };
+ return 0;
+}
+
+static int
+s_handle_invoke_mapping_map(
+ objdir_t *root_dir,
+ objdir_entry_t *target_entry,
+ uint8_t *payload,
+ size_t payload_at
+ )
+{
+ uint8_t level = target_entry->data & 3;
+ pmle_t *target_pml = (pmle_t*)vmem_phys_tovirt(target_entry->data & ~3ULL);
+
+ pmli_t pmli;
+ SYSCALL_PAYLOAD_TAKEL(payload, payload_at, pmli, pmli_t);
+
+ if(pmli > 511) return -KE_OOB;
+ if(level == 3 && pmli > 255) return -KE_OOB;
+
+ size_t untyped_pathw;
+ objdir_entry_t *untyped_entry;
+ SYSCALL_PAYLOAD_TAKEOBJ(payload, payload_at, untyped_pathw, untyped_entry);
+
+ if(untyped_entry->type != KO_MEMORY_UNTYPED) return -KE_BADOBJ;
+ mtx_acquire(&untyped_entry->lock);
+
+ if((untyped_entry->data & 0xFFF) != 0) {
+ mtx_release(&untyped_entry->lock);
+ return -KE_ALIGN;
+ }
+ size_t *untyped_data = (size_t*)untyped_entry->data;
+ size_t untyped_size = *untyped_data;
+ if(untyped_size != 0x1000) {
+ mtx_release(&untyped_entry->lock);
+ return -KE_BADSIZE;
+ }
+
+ pmle_t pmle = target_pml[pmli];
+ if(pmle.p) {
+ mtx_release(&untyped_entry->lock);
+ return -KE_OCCUPIED;
+ }
+
+ target_pml[pmli].value = vmem_ident_tophys((void*)untyped_entry->data) | PAGE_RW | PAGE_US | PAGE_PRESENT;
+ untyped_entry->type = KO_MEMORY_MAPPING;
+ untyped_entry->data |= level - 1;
+
+ mtx_release(&untyped_entry->lock);
+ return 0;
+}
+
+static int (*s_invoke_handles[])(objdir_t*, objdir_entry_t*, uint8_t*, size_t) = {
+ [INVOKE_MAPPING_RELEASE] = s_handle_invoke_mapping_release,
+ [INVOKE_MAPPING_GET] = s_handle_invoke_mapping_get,
+ [INVOKE_MAPPING_MAP] = s_handle_invoke_mapping_map,
+};
+
+static size_t s_invoke_handles_count = sizeof(s_invoke_handles) / sizeof(void*);
+
+int
+syscall_handle_invoke_mapping(
+ objdir_t *root_dir,
+ objdir_entry_t *target,
+ uint8_t *payload,
+ size_t payload_at
+ )
+{
+ uint8_t funcid;
+ SYSCALL_PAYLOAD_TAKEL(payload, payload_at, funcid, uint8_t);
+
+ if(funcid >= s_invoke_handles_count) return -KE_BADFUNC;
+ return s_invoke_handles[funcid](root_dir, target, payload, payload_at);
+}