#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 "syscall.h" int s_syscall_pcb_yield(jove_owned_obj_t *pcb_obj, size_t bytes_left, void *payload_data) { //Validate that 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_owned_obj_t *objdir_obj, size_t bytes_left, void *payload_data) { //Validate that 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; //Validate that 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"); //Validate that 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; } //Validate that the subject objdir path is valid. jove_perm_obj_t subject_objdir = link_try_traverse_objdir( objdir_obj, lockstack, payload->send_path_length - 1, payload->send_path); if(errno) { klogf("Unable to get subject %P objdir : %s\n", payload->send_path, payload->send_path_length, errstr(errno)); return -errno; } //Validate that 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"); //Validate that the subject exists in the subject objdir. jove_owned_obj_t *subject = objdir_trygetlocal(subject_objdir.obj, payload->send_path[payload->send_path_length-1]); 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_owned_obj_t *objdir_obj, size_t bytes_left, void *payload_data) { //Validate that 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; //Validate that 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"); //Validate that the destination object exists. jove_perm_obj_t destination = link_try_traverse_objdir( objdir_obj, lockstack, payload->recv_path_length, payload->recv_path); if(errno) { klogf("Unable to get destination %P : %s\n", payload->recv_path, payload->recv_path_length, errstr(errno)); return -errno; } //Validate that 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_owned_obj_t *objdir_obj, size_t bytes_left, void *payload_data) { //Validate that 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; //Validate that 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"); //Validate that the subject is not the rootdir. if(payload->swap_path_length == 0) { kprintf("%s: Unable to swap the root directory\n", __func__); return -EBADPATH; } //Validate that the subject objdir exists. jove_perm_obj_t subject_objdir = link_try_traverse_objdir( objdir_obj, lockstack, payload->swap_path_length - 1, payload->swap_path); if(errno) { klogf("Unable to get subject %P objdir : %s\n", payload->swap_path, payload->swap_path_length, errstr(errno)); return -errno; } //Validate that the subject objdir has send permissions. CHECK_OBJPERM(subject_objdir, SYSCALL_PERM_PCB_SEND_OBJDIR, "Subject objdir does not permit send"); //Validate that the subject object exists. jove_owned_obj_t *subject = objdir_trygetlocal(subject_objdir.obj, payload->swap_path[payload->swap_path_length-1]); if(subject == 0) { klogf("Unable to get subject %P object : %s\n", payload->swap_path, payload->swap_path_length, errstr(errno)); return -errno; } //Validate that 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; } //Validate that 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; } //Validate that 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_owned_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_try_traverse_objdir(rootdir, lockstack, payload->stack_path_length, payload->stack_path); //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 _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; default: return -EBADCALL; } }