#include "api/error.h" #include "api/obj.h" #include "api/syscall.h" #include "jove.h" #include "lib/printf.h" #include "proc/process.h" #include "proc/scheduler.h" #include "sys/objdir.h" #include "syscall.h" int s_syscall_pcb_yield(jove_owned_obj_t *pcb_obj, size_t bytes_left, void *payload_data) { //Verify message is big enough for payload size_t bytes_needed = sizeof(pid_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); //Get subject PID from payload. pid_t subject_pid = *((pid_t*)payload_data); //Yield to target. return scheduler_yield(subject_pid); } int s_syscall_pcb_send(jove_owned_obj_t *pcb_obj, lockstack_t *lockstack, jove_obj_t *objdir_obj, size_t bytes_left, void *payload_data) { //Verify message is big enough for payload. size_t bytes_needed = sizeof(struct syscall_pcb_send); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); struct syscall_pcb_send *payload = payload_data; //Verify message is big enough for payload object path. bytes_needed += payload->send_path_length; CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for subject path"); //Verify subject object path is not the root directory. if(payload->send_path_length == 0) { kprintf("%s: Unable to send root directory\n", __func__); return -EBADPATH; } //Verify the subject objdir path is valid. jove_perm_obj_t subject_objdir = link_traverse_objdir(objdir_obj, payload->send_path_length - 1, payload->send_path); if(subject_objdir.obj == NULL) { klogf("Unable to get subject %P objdir : %s\n", payload->send_path, payload->send_path_length, errstr(errno)); obj_release(subject_objdir.obj); return -errno; } //Verify the currently running PCB has mutate permissions for this objdir. CHECK_OBJPERM(subject_objdir, SYSCALL_PERM_PCB_SEND_OBJDIR, "Subject objdir does not permit send"); //Verify the subject exists in the subject objdir. jove_owned_obj_t *subject = objdir_getlocal( obj_release(subject_objdir.obj), payload->send_path[payload->send_path_length-1]); lockstack_push(lockstack, subject); if(subject == 0) { klogf("Unable to get subject %P object : %s\n", payload->send_path, payload->send_path_length, errstr(errno)); return -errno; } //Send subject to target. return pcb_send(obj_deref(pcb_obj), payload->send_target, subject, payload->send_timeout); } int s_syscall_pcb_recv(jove_owned_obj_t *pcb_obj, lockstack_t *lockstack, jove_obj_t *objdir_obj, size_t bytes_left, void *payload_data) { //Verify the message is big enough for the payload. size_t bytes_needed = sizeof(struct syscall_pcb_recv); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); struct syscall_pcb_recv *payload = payload_data; //Verify the message is big enough for the payload object. bytes_needed += payload->recv_path_length * sizeof(objpath_part_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for destination path"); //Verify the destination object exists. jove_perm_obj_t destination = link_traverse_objdir(objdir_obj, payload->recv_path_length, payload->recv_path); lockstack_push(lockstack, destination.obj); if(errno) { klogf("Unable to get destination %P : %s\n", payload->recv_path, payload->recv_path_length, errstr(errno)); return -errno; } //Verify the destination path is JOVE_OBJ_NONE and that the object has recieve permissions. CHECK_OBJTYPE(destination.obj, JOVE_OBJ_NONE, "Destination object is occupied"); CHECK_OBJPERM(destination, SYSCALL_PERM_PCB_RECV_DST, "Destination object does not permit recv."); //Recieve from some PID into destination. return pcb_recv(obj_deref(pcb_obj), payload->recv_target, destination.obj, payload->recv_timeout); } int s_syscall_pcb_swap(jove_owned_obj_t *pcb_obj, lockstack_t *lockstack, jove_obj_t *objdir_obj, size_t bytes_left, void *payload_data) { //Verify the message is big enough for payload. size_t bytes_needed = sizeof(struct syscall_pcb_recv); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); struct syscall_pcb_swap *payload = payload_data; //Verify the message is big enough for the subject path. bytes_needed += payload->swap_path_length * sizeof(objpath_part_t); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for swap path"); //Verify the subject is not the rootdir. if(payload->swap_path_length == 0) { kprintf("%s: Unable to swap the root directory\n", __func__); return -EBADPATH; } //Verify the subject objdir exists. jove_perm_obj_t subject_objdir = link_traverse_objdir(objdir_obj, payload->swap_path_length - 1, payload->swap_path); if(subject_objdir.obj == NULL) { klogf("Unable to get subject %P objdir : %s\n", payload->swap_path, payload->swap_path_length, errstr(errno)); obj_release(subject_objdir.obj); return -errno; } //Verify the subject objdir has send permissions. CHECK_OBJPERM(subject_objdir, SYSCALL_PERM_PCB_SEND_OBJDIR, "Subject objdir does not permit send"); //Verify the subject object exists. jove_owned_obj_t *subject = objdir_getlocal( obj_release(subject_objdir.obj), payload->swap_path[payload->swap_path_length-1]); lockstack_push(lockstack, subject); if(subject == 0) { klogf("Unable to get subject %P object : %s\n", payload->swap_path, payload->swap_path_length, errstr(errno)); return -errno; } //Verify the target PCB exists. if(pcb_frompid(payload->swap_target) == 0) { klogf("Swap PCB target %i does not exist\n", payload->swap_target); return -EBADPROC; } //Verify the message was sent before timeout. int send_result = pcb_send( obj_deref(pcb_obj), payload->swap_target, subject, payload->send_timeout); if(send_result < 0) { klogf("Send to %i failed with code %s\n", payload->swap_target, errstr(-send_result)); return send_result; } //Verify a message was recieved before timeout. int recv_result = pcb_recv( obj_deref(pcb_obj), payload->swap_target, subject, payload->recv_timeout); return recv_result; } int s_syscall_pcb_stack(jove_owned_obj_t *pcb_obj, lockstack_t *lockstack, jove_obj_t *rootdir, size_t bytes_left, void *payload_data) { //Verify the message is big enough for the payload struct. size_t bytes_needed = sizeof(struct syscall_pcb_stack); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); //Verify the message is big enough for the untyped object path. struct syscall_pcb_stack *payload = payload_data; bytes_needed += sizeof(objpath_part_t) * payload->stack_path_length; CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for untyped path"); jove_perm_obj_t untyped = link_traverse_objdir(rootdir, payload->stack_path_length, payload->stack_path); lockstack_push(lockstack, untyped.obj); //Verify the untyped object exists. if(untyped.obj == NULL) { klogf("Unable to get untyped %P : %s\n", payload->stack_path, payload->stack_path_length, errstr(errno)); return -errno; } //Verify the correct type and permissions. CHECK_OBJTYPE(untyped.obj, JOVE_OBJ_UNTYPED, "Subject untyped is not an untyped."); CHECK_OBJPERM(untyped, SYSCALL_PERM_PCB_STACK_OBJ, "Untyped is missing permissions"); jove_untyped_t *untyped_data = obj_deref(untyped.obj); if((uintptr_t)untyped_data & 0xFFF) { klogf("Untyped object %P is not aligned to page boundary.\n", payload->stack_path, payload->stack_path_length); return -EALIGN; } if(untyped_data->limit != 0x1000) { klogf("Untyped object %P is not page sized.\n", payload->stack_path, payload->stack_path_length); return -EBADSIZE; } //Set the stack. Error if bad type or stack already exists. pcb_t *pcb = obj_deref(pcb_obj); switch(payload->type) { case PCB_STACK_SYSTEM: if(pcb_get_syscall_stack(pcb) != 0) { klogf("PCB %p Already has a system stack!\n", pcb); return -EFULL; } pcb_set_syscall_stack(pcb, obj_getvalue(untyped.obj)); break; case PCB_STACK_INTERRUPT: if(pcb_get_interrupt_stack(pcb) != 0) { klogf("PCB %p Already has a interrupt stack!\n", pcb); return -EFULL; } pcb_set_interrupt_stack(pcb, obj_getvalue(untyped.obj)); break; default: klogf("Unknown stack type %i\n", payload->type); return -EBADARG; } //Destroy untyped object. obj_settype(untyped.obj, JOVE_OBJ_NONE); obj_setvalue(untyped.obj, 0); return 0; } int s_syscall_pcb_ready( jove_owned_obj_t *target_obj, lockstack_t *lockstack, jove_obj_t *objdir) { jove_objdir_t *target_objdir = obj_getobjdir(obj_asunowned(target_obj)); if(!obj_compare(&target_objdir->entries[PCB_ROOTDIR_SELF_I], obj_asunowned(target_obj))) { klogf("Target PCB is not in entry %i of it's objdir!\n", PCB_ROOTDIR_SELF_I); return -EBADPATH; } jove_owned_obj_t *pagedir_obj = obj_take(&target_objdir->entries[PCB_ROOTDIR_PAGEDIR_I]); if(obj_gettype(pagedir_obj) != JOVE_OBJ_PAGEDIR) { klogf("Target PCB rootdir does not have pagedir in entry %i\n", PCB_ROOTDIR_PAGEDIR_I); obj_release(pagedir_obj); return -EBADPATH; } obj_release(pagedir_obj); return 0; } int s_syscall_pcb_stop(jove_owned_obj_t *pcb_obj, size_t bytes_left, void *payload_data) { size_t bytes_needed = sizeof(int); CHECK_TOOSMALL(bytes_needed, bytes_left, "Message too small for payload"); int stop_code = *((int*)payload_data); return scheduler_stop(pcb_obj, stop_code); } int _syscall_handle_pcb(syscall_context_t *ctx) { switch(ctx->header->callid) { case SYSCALL_PCB_YIELD: if(ctx->target.permissions & SYSCALL_PERM_PCB_YIELD) return s_syscall_pcb_yield(ctx->target.obj, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_PCB_SEND: if(ctx->target.permissions & SYSCALL_PERM_PCB_SEND) return s_syscall_pcb_send( ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_PCB_RECV: if(ctx->target.permissions & SYSCALL_PERM_PCB_RECV) return s_syscall_pcb_recv( ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_PCB_SWAP: if(ctx->target.permissions & SYSCALL_PERM_PCB_SWAP) return s_syscall_pcb_swap( ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_PCB_STACK: if(ctx->target.permissions & SYSCALL_PERM_PCB_STACK) return s_syscall_pcb_stack( ctx->target.obj, &ctx->lockstack, ctx->objdir, ctx->bytes_left, ctx->payload); return -EPERM; case SYSCALL_PCB_READY: if(ctx->target.permissions & SYSCALL_PERM_PCB_READY) return s_syscall_pcb_ready( ctx->target.obj, &ctx->lockstack, ctx->objdir); return -EPERM; case SYSCALL_PCB_STOP: if(ctx->target.permissions & SYSCALL_PERM_PCB_STOP) return s_syscall_pcb_stop( ctx->target.obj, ctx->bytes_left, ctx->payload); default: return -EBADCALL; } }