#include "syscall.h" #include "sys/errno.h" #include "sys/permission.h" #include "usr/tasking.h" #include "mem/memory.h" #include "io/log.h" #define ENSURE_ADDR(ptr) \ if(!mem_check_ptr(ptr)) { klogf("User passed bad address %#016X\n", ptr); return -EFAULT; } #define ENSURE_PERM(p) \ if(!(task_current->perm & p)) return -ENOPERM #define PD_FOR_LINEAR_ADDRESS(addr) current_page_directory; \ if(addr.tid == -1) addr.tid = task_current->id; \ if(addr.tid != task_current->id) { \ ENSURE_PERM(PERM_MEM_VIRT_PD); \ struct Task *task = task_get(addr.tid); \ if(task == NULL) return -EFAULT; \ pd = task->pd; \ } int _syscall_handler_log(struct syscall_log *req) { ENSURE_ADDR(req->message); klogf("%s", req->message); return 0; } intmax_t _syscall_handler_tid(syscall_t *req) { return task_current->id; } int _syscall_handler_mem_phys_resv(struct syscall_mem_phys_range_op *req) { ENSURE_PERM(PERM_MEM_PHYS_RESV); mem_phys_reserve(req->base, req->limit); return 0; } int _syscall_handler_mem_phys_free(struct syscall_mem_phys_range_op *req) { ENSURE_PERM(PERM_MEM_PHYS_FREE); mem_phys_release(req->base, req->limit); return 0; } int _syscall_handler_mem_phys_alloc(struct syscall_mem_phys_alloc *req) { ENSURE_ADDR(req->result); ENSURE_PERM(PERM_MEM_PHYS_ALLOC); *req->result = mem_phys_alloc(req->npages); return 0; } int _syscall_handler_mem_virt_mapping(struct syscall_mem_virt_mapping *req) { ENSURE_ADDR(req->result); ENSURE_PERM(PERM_MEM_VIRT_MAP); page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->addr); *req->result = mem_get_mapping_as(pd, req->addr.addr); return 0; } int _syscall_handler_mem_virt_map(struct syscall_mem_virt_map *req) { ENSURE_PERM(PERM_MEM_VIRT_MAP); page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->addr); mem_set_mapping_as(pd, req->map, req->addr.addr); return 0; } int _syscall_handler_mem_virt_alloc(struct syscall_mem_virt_alloc *req) { ENSURE_PERM(PERM_MEM_VIRT_MAP); ENSURE_PERM(PERM_MEM_PHYS_ALLOC); page_directory_t *pd = PD_FOR_LINEAR_ADDRESS(req->from); mem_ensure_range_as(pd, req->from.addr, req->to, req->flg); return 0; } void *_syscall_handlers[SYSCALL_COUNT] = { _syscall_handler_log, _syscall_handler_tid, _syscall_handler_mem_phys_resv, _syscall_handler_mem_phys_free, _syscall_handler_mem_phys_alloc, _syscall_handler_mem_virt_mapping, _syscall_handler_mem_virt_map, _syscall_handler_mem_virt_alloc, }; int syscall_handler(syscall_t *req) { ENSURE_ADDR(req); if(req->id >= SYSCALL_COUNT) return -ENOSYS; ENSURE_ADDR(_syscall_handlers[req->id]); return ((syscall_handler_t)(_syscall_handlers[req->id]))(req); }