From 41ead8de77963bae907375c1bb115dad3315f46b Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sat, 12 Nov 2022 16:41:36 +0200 Subject: initial rpc implementations --- common/proc.c | 4 +-- common/tcb.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++------ common/uapi/conf.c | 4 +++ common/uapi/ipc.c | 16 +++++++++-- common/uapi/proc.c | 10 ++++--- 5 files changed, 100 insertions(+), 17 deletions(-) (limited to 'common') diff --git a/common/proc.c b/common/proc.c index 137a2fe..1acd5b8 100644 --- a/common/proc.c +++ b/common/proc.c @@ -21,7 +21,7 @@ stat_t prepare_proc(struct tcb *t, vm_t bin, vm_t interp) if (!entry) return ERR_INVAL; - alloc_stacks(t); + alloc_stack(t); set_thread(t); set_return(t, entry); return OK; @@ -40,7 +40,7 @@ stat_t init_proc(void *fdt) use_tcb(t); /* init process has all capabilities */ - set_caps(t->caps, 0, CAP_CAPS | CAP_PROC | CAP_CALL); + set_caps(t->caps, 0, CAP_CAPS | CAP_PROC | CAP_CALL | CAP_POWER); /* allocate stacks after ELF file to make sure nothing of importance * clashes */ diff --git a/common/tcb.c b/common/tcb.c index 0a676af..aa66d3f 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -96,11 +96,11 @@ static vm_t __setup_rpc_stack(struct tcb *t, size_t bytes) vmflags_t flags = VM_V | VM_R | VM_W | VM_U; for (size_t i = 1; i <= pages; ++i) { offset = alloc_page(BASE_PAGE); - map_vpage(t->proc.vmem, offset, + map_vpage(t->rpc.vmem, offset, RPC_STACK_TOP - BASE_PAGE_SIZE * i, flags, BASE_PAGE); } - + t->rpc_stack = RPC_STACK_TOP; return RPC_STACK_TOP - BASE_PAGE_SIZE * pages; } @@ -116,7 +116,7 @@ static vm_t __setup_thread_stack(struct tcb *t, size_t bytes) return alloc_uvmem(t, bytes, VM_V | VM_R | VM_W | VM_U); } -stat_t alloc_stacks(struct tcb *t) +stat_t alloc_stack(struct tcb *t) { /* get parent process */ struct tcb *p = get_tcb(t->eid); @@ -125,11 +125,6 @@ stat_t alloc_stacks(struct tcb *t) if (!t->thread_stack) return ERR_OOMEM; - /* rpc stack always starts at the same place in vmem. - * \todo: is this a security issue? */ - if (!__setup_rpc_stack(p, __call_stack_size)) - return ERR_OOMEM; - /** \todo this only allows for a global stack size, what if a user wants * per thread stack sizes? */ t->thread_stack_top = t->thread_stack + __thread_stack_size; @@ -166,6 +161,7 @@ struct tcb *create_thread(struct tcb *p) t->eid = t->pid; t->rid = p->rid; t->rpc.vmem = create_vmem(); + __setup_rpc_stack(t, __call_stack_size); set_canary(t); return t; @@ -186,6 +182,10 @@ static stat_t __copy_proc(struct tcb *p, struct tcb *n) * need to duplicate stack info, whatever we do. */ /** @todo should there be in-kernel child tracking? */ n->exec = p->exec; + n->callback = p->callback; + n->thread_stack = p->thread_stack; + n->thread_stack_top = p->thread_stack_top; + clone_regs(n, p); copy_caps(n->caps, p->caps); return clone_mem_regions(n, p); @@ -374,3 +374,70 @@ bool running(struct tcb *t) { return cpu_tcb(t->cpu_id) == t; } + +/** + * Mark rpc stack between \p start and \p end inaccessible. + * + * @param t Thread whose rpc stack to modify. + * @param start Start address of rpc stack to mark inaccessible. + * @param end End address of rpc stack to mark inaccessible. + */ +static void mark_rpc_inaccessible(struct tcb *t, vm_t start, vm_t end) +{ + size_t page_size = BASE_PAGE_SIZE; + size_t size = end - start; + size_t pages = size / page_size; + while (pages--) { + /** @todo something like mod_vpage_flags could be faster */ + vmflags_t flags; pm_t paddr; + stat_vpage(t->rpc.vmem, start, &paddr, NULL, &flags); + mod_vpage(t->rpc.vmem, start, paddr, clear_bits(flags, VM_U)); + } +} + +/** + * Mark rpc stack between \p start and \p end accessible. + * + * @param t Thread whose rpc stack to modify. + * @param start Start address of rpc stack to mark accessible. + * @param end End address of rpc stack to mark accessible. + */ +static void mark_rpc_accessible(struct tcb *t, vm_t start, vm_t end) +{ + size_t page_size = BASE_PAGE_SIZE; + size_t size = end - start; + size_t pages = size / page_size; + while (pages--) { + /** @todo something like mod_vpage_flags could be faster */ + vmflags_t flags; pm_t paddr; + stat_vpage(t->rpc.vmem, start, &paddr, NULL, &flags); + mod_vpage(t->rpc.vmem, start, paddr, set_bits(flags, VM_U)); + } +} + +void save_context(struct tcb *t) +{ + vm_t rpc_stack = t->rpc_stack; + if (is_rpc(t)) + /** @todo what if user uses their own stack? */ + rpc_stack = align_down(get_stack(t), BASE_PAGE_SIZE); + + struct tcb *copy = (struct tcb *)(rpc_stack - sizeof(struct tcb)); + memcpy(copy, t, sizeof(struct tcb)); + clone_regs(copy, t); + + rpc_stack -= BASE_PAGE_SIZE; + mark_rpc_inaccessible(t, rpc_stack, t->rpc_stack); + t->rpc_stack = rpc_stack; +} + +void load_context(struct tcb *t) +{ + vm_t rpc_stack = t->rpc_stack; + struct tcb *copy = + (struct tcb *)(rpc_stack + BASE_PAGE_SIZE - sizeof(struct tcb)); + memcpy(t, copy, sizeof(struct tcb)); + clone_regs(t, copy); + + mark_rpc_accessible(t, rpc_stack, t->rpc_stack); +} diff --git a/common/uapi/conf.c b/common/uapi/conf.c index 7e88358..2094604 100644 --- a/common/uapi/conf.c +++ b/common/uapi/conf.c @@ -57,6 +57,10 @@ SYSCALL_DEFINE2(conf_set)(sys_arg_t param, sys_arg_t val) */ SYSCALL_DEFINE1(poweroff)(sys_arg_t type) { + struct tcb *t = cur_tcb(); + if (!(has_cap(t->caps, CAP_POWER))) + return SYS_RET1(ERR_PERM); + switch (type) { case SHUTDOWN: case COLD_REBOOT: diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c index cb53ee3..e45c7dd 100644 --- a/common/uapi/ipc.c +++ b/common/uapi/ipc.c @@ -18,7 +18,7 @@ */ SYSCALL_DEFINE1(ipc_server)(sys_arg_t callback) { - cur_tcb()->callback = callback; + cur_proc()->callback = callback; return SYS_RET1(OK); } @@ -50,8 +50,12 @@ static struct sys_ret do_ipc(sys_arg_t pid, if (!r->callback) return SYS_RET1(ERR_NOINIT); - /** \todo place data on rpc stack and clone into virtual memory */ + clone_uvmem(r->proc.vmem, t->rpc.vmem); + use_vmem(t->rpc.vmem); + save_context(t); set_return(t, r->callback); + /** @todo associate thread with new proc, should be done in tcb.c I + * think */ if (!fwd) t->eid = t->pid; @@ -105,7 +109,13 @@ SYSCALL_DEFINE4(ipc_resp)(sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) { struct tcb *t = cur_tcb(); - /* something like return_from_callback(t, r) */ + load_context(t); + + if (is_rpc(t)) + use_vmem(t->rpc.vmem); + else + use_vmem(t->proc.vmem); + return SYS_RET6(OK, t->tid, d0, d1, d2, d3); } diff --git a/common/uapi/proc.c b/common/uapi/proc.c index 969dcd6..7a078da 100644 --- a/common/uapi/proc.c +++ b/common/uapi/proc.c @@ -32,6 +32,8 @@ SYSCALL_DEFINE5(create)(sys_arg_t func, if (!t) return SYS_RET1(ERR_OOMEM); + alloc_stack(t); + set_args(t, SYS_RET5(t->tid, d0, d1, d2, d3)); set_return(t, func); @@ -55,7 +57,7 @@ SYSCALL_DEFINE5(create)(sys_arg_t func, */ SYSCALL_DEFINE0(fork)(){ struct tcb *c = cur_proc(); - if (!(get_caps(c->caps, 0) & CAP_PROC)) + if (!(has_cap(c->caps, CAP_PROC))) return SYS_RET1(ERR_PERM); struct tcb *t = create_proc(eff_proc()); @@ -118,7 +120,7 @@ SYSCALL_DEFINE2(exec)(sys_arg_t bin, sys_arg_t interp){ SYSCALL_DEFINE2(spawn)(sys_arg_t bin, sys_arg_t interp) { struct tcb *c = cur_proc(); - if (!(get_caps(c->caps, 0) & CAP_PROC)) + if (!(has_cap(c->caps, CAP_PROC))) return SYS_RET1(ERR_PERM); struct tcb *t = create_proc(NULL); @@ -139,7 +141,7 @@ SYSCALL_DEFINE2(spawn)(sys_arg_t bin, sys_arg_t interp) SYSCALL_DEFINE1(kill)(sys_arg_t tid) { struct tcb *c = cur_proc(); - if (!(get_caps(c->caps, 0) & CAP_PROC)) + if (!(has_cap(c->caps, CAP_PROC))) return SYS_RET1(ERR_PERM); return SYS_RET1(OK); @@ -157,7 +159,7 @@ SYSCALL_DEFINE1(kill)(sys_arg_t tid) */ SYSCALL_DEFINE1(swap)(sys_arg_t tid){ struct tcb *c = cur_proc(); - if (!(get_caps(c->caps, 0) & CAP_PROC)) + if (!(has_cap(c->caps, CAP_PROC))) return SYS_RET1(ERR_PERM); struct tcb *t = get_tcb(tid); -- cgit v1.3