#include "sys/syscall.h" #include "arch/x86_64/hal/obj.h" #include "hal/smp.h" #include "proc/process.h" #include "jove.h" #include "lib/printf.h" #include "sys/link.h" #include "sys/message.h" int __syscall_generic_objpath(jove_owned_obj_t *objdir, size_t payload_bytes, void *payload_data, jove_owned_obj_t **retobj) { size_t bytes_needed = sizeof(struct syscall_generic_objpath); CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for payload."); struct syscall_generic_objpath *payload = payload_data; bytes_needed += payload->pathlen << 1; CHECK_TOOSMALL(bytes_needed, payload_bytes, "Message too small for object path."); errno = 0; *retobj = objdir_getobj(objdir, payload->path, payload->pathlen); return errno; } int _syscall_handle_generic(syscall_context_t *ctx) { pcb_t *pcb = obj_deref(ctx->pcb); klogf("Process %i encountered stub syscall on object %P\n", pcb_pid(pcb), ctx->header->path, ctx->header->pathlen); return -EBADOBJ; } static const syscall_handle_t s_syscall_handles[128] = { [JOVE_OBJ_UNTYPED] = _syscall_handle_untyped, [JOVE_OBJ_OBJDIR] = _syscall_handle_objdir, [JOVE_OBJ_PAGEDIR] = _syscall_handle_pagedir, [JOVE_OBJ_PROCESSOR] = _syscall_handle_generic, [JOVE_OBJ_SHMEMORY] = _syscall_handle_generic, [JOVE_OBJ_PCB] = _syscall_handle_generic, [JOVE_OBJ_INT_HANDLE] = _syscall_handle_generic, [JOVE_OBJ_INITRD_FILE] = _syscall_handle_generic, [JOVE_OBJ_FRAMEBUFFER] = _syscall_handle_generic, [JOVE_OBJ_VIRTTERM] = _syscall_handle_vtt, [JOVE_OBJ_MESSAGE] = _syscall_handle_generic, [JOVE_OBJ_LINK] = _syscall_handle_generic, }; int _syscall_handle_switch(syscall_context_t *ctx) { uint8_t target_type = obj_gettype(ctx->target.obj); if(target_type == JOVE_OBJ_NONE) { klogf("Tried to call syscall on NULL object %P\n", ctx->header->path, ctx->header->pathlen); return -EBADOBJ; } if(target_type > 0x7F) { return _syscall_handle_arch(ctx); } else { syscall_handle_t call_handle = s_syscall_handles[target_type]; if(call_handle == NULL) { klogf("Tried to call syscall on object %P which doesn't support syscalls!\n", ctx->header->path, ctx->header->pathlen); return -EBADOBJ; } else { return call_handle(ctx); } } } int syscall_handler(uintmax_t message_path_raw, uint16_t message_pathlen) { uint16_t *message_path = (uint16_t*)&message_path_raw; if(message_pathlen > sizeof(uintmax_t) >> 1) { return -EBADPATH; } syscall_context_t ctx; ctx.lockstack.depth = 0; int sysret = 0; ctx.pcb = process_current(); pcb_t *pcb = obj_deref(ctx.pcb); ctx.objdir = lockstack_push(&ctx.lockstack, obj_take(pcb_rootdir(pcb))); ctx.message = link_try_traverse_objdir( ctx.objdir, &ctx.lockstack, message_pathlen, message_path); if(ctx.message.obj == NULL) { klogf("Process %i failed to get message %P : %s\n", pcb_pid(pcb), message_path, message_pathlen, errstr(errno)); sysret = -errno; goto release_return; } if(obj_gettype(ctx.message.obj) != JOVE_OBJ_MESSAGE) { klogf("Process %i tried to call syscall with invalid object %P\n", pcb_pid(pcb), message_path, message_pathlen); sysret = -EBADOBJ; goto release_return; } if((ctx.message.permissions & JOVE_PERM_READ) == 0) { klogf("Process %i tried to call syscall with message object %P without read permissions\n", pcb_pid(pcb), message_path, message_pathlen); sysret = -EPERM; goto release_return; } size_t messagelen = message_len(ctx.message.obj); void *messagedata = message_data(ctx.message.obj); struct syscall_header *header = messagedata; size_t bytes_needed = sizeof(struct syscall_header) + header->pathlen * 2; if(bytes_needed > messagelen) { //Target path exceeds message length. klogf("Process %i tried to call syscall with target path too big for message.\n", pcb_pid(pcb)); sysret = -ETOOSMALL; goto release_return; } ctx.header = header; ctx.bytes_left = messagelen - bytes_needed; ctx.payload = (void*)((uintptr_t)header + bytes_needed); ctx.target = link_try_traverse_objdir( ctx.objdir, &ctx.lockstack, ctx.header->pathlen, ctx.header->path); if(ctx.target.obj == 0) { //Could not find payload target in pcb rootdir. klogf("Process %i tried to call syscall with bad target path %P : %s\n", pcb_pid(pcb), header->path, header->pathlen, errstr(errno)); sysret = -errno; goto release_return; } sysret = _syscall_handle_switch(&ctx); release_return: lockstack_popall(&ctx.lockstack); return sysret; }