#include "arch/x86_64/syscall/wrappers.h" #include "arch/x86_64/syscall.h" #include "arch/x86_64/page.h" #include #include "error.h" #include "lock.h" #include "string.h" #include "memory.h" #include "print.h" static int s_handle_invoke_mapping_exists( objdir_t *root_dir, objdir_entry_t *target_entry, uint8_t *payload, size_t payload_at ) { pmle_t *pml4 = (pmle_t*)vmem_phys_tovirt(target_entry->data); pmle_t *target_pml; uint8_t target_depth; SYSCALL_PAYLOAD_TAKEPML(payload, payload_at, pml4, target_depth, target_pml); if(target_pml == NULL || !target_pml->p) return KE_DNE; #ifdef DBG_SYSCALL klogf("pml d%i %p from %p exists\n", target_depth, target_pml, pml4); #endif 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 ) { pmle_t *pml4 = (pmle_t*)vmem_phys_tovirt(target_entry->data); pmle_t *target_pml; uint8_t target_depth; SYSCALL_PAYLOAD_TAKEPML(payload, payload_at, pml4, target_depth, target_pml); if(target_pml == NULL) return KE_DNE; 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; } uintptr_t untyped_phys = untyped_entry->data; size_t *untyped = ko_entry_data(untyped_entry); size_t untyped_size = *untyped; if(untyped_size != 0x1000) { mtx_release(&untyped_entry->lock); return KE_BADSIZE; } target_pml->value = untyped_phys | PAGE_RW | PAGE_US | PAGE_PRESENT; __asm__ volatile("invlpg (%0)":: "r"(untyped): "memory"); if(target_depth != 3) { memset(untyped, 0, 0x1000); } untyped_entry->type = KO_NONE; #ifdef DBG_SYSCALL klogf("map %p[%i] to %p[%i]\n", untyped_phys, target_depth, target_pml, ((uintptr_t)target_pml & 0xFFF) / 8); #endif mtx_release(&untyped_entry->lock); return 0; } static int s_handle_invoke_mapping_unmap( objdir_t *root_dir, objdir_entry_t *target_entry, uint8_t *payload, size_t payload_at ) { pmle_t *pml4 = (pmle_t*)vmem_phys_tovirt(target_entry->data); pmle_t *target_pml; uint8_t target_depth; SYSCALL_PAYLOAD_TAKEPML(payload, payload_at, pml4, target_depth, target_pml); if(target_pml == NULL || !target_pml->p) return KE_DNE; if(target_depth != 3) { for(pmli_t i = 0; i < 512; i++) { if(target_pml[i].p) return KE_FULL; } } target_pml->p = false; objdir_entry_t *dest_entry; size_t dest_pathw; SYSCALL_PAYLOAD_TAKEOBJ(payload, payload_at, dest_pathw, dest_entry); if(dest_entry->type != KO_NONE) return KE_FULL; uintptr_t pmle_addr = target_pml->paddr << 12; size_t *untyped = vmem_phys_tovirt(pmle_addr); __asm__ volatile("invlpg (%0)":: "r"(untyped): "memory"); *untyped = 0x1000; dest_entry->type = KO_MEMORY_UNTYPED; dest_entry->data = pmle_addr; #ifdef DBG_SYSCALL klogf("unmap %p[%i] to untyped %p\n", target_pml, 3 - target_depth, pmle_addr); #endif return 0; } static int (*s_invoke_handles[])(objdir_t*, objdir_entry_t*, uint8_t*, size_t) = { [INVOKE_MAPPING_EXISTS] = s_handle_invoke_mapping_exists, [INVOKE_MAPPING_MAP] = s_handle_invoke_mapping_map, [INVOKE_MAPPING_UNMAP] = s_handle_invoke_mapping_unmap }; 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; int r = s_invoke_handles[funcid](root_dir, target, payload, payload_at); #ifdef DBG_SYSCALL klogf("Call returns %i\n", r); #endif return r; }