From 1a0188fac0c0f265c4495b83592389b8b3645462 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Sun, 13 Nov 2022 17:16:28 +0200 Subject: outline rpc stack handling --- common/tcb.c | 23 +++++++++++++++++++- common/uapi/conf.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++---- common/uapi/ipc.c | 3 +++ include/apos/caps.h | 5 ++++- include/apos/conf.h | 14 ++++++++++++ include/apos/tcb.h | 8 +++++++ 6 files changed, 109 insertions(+), 6 deletions(-) diff --git a/common/tcb.c b/common/tcb.c index 5121940..afc8442 100644 --- a/common/tcb.c +++ b/common/tcb.c @@ -432,7 +432,8 @@ void save_context(struct tcb *t) /** @todo what if user uses their own stack? Or is a dick and * sets the stack pointer to RPC_STACK_TOP or something? It'll * likely only cause a fuckup in the process who did the dumb - * thing, so maybe just consider it user error? */ + * thing, so maybe just consider it user error? Except by + * causing the stack of the next rpc to run out of memory... */ rpc_stack = align_down(get_stack(t), BASE_PAGE_SIZE); @@ -443,8 +444,20 @@ void save_context(struct tcb *t) ctx->regs = t->regs; ctx->rpc_stack = rpc_stack; + /** @todo if we run out of rpc_stack space we should just stop, likely + * return a status? */ rpc_stack -= BASE_PAGE_SIZE; + /** @todo what if each stack is only some number of pages, and if a proc + * goes over the limit is is seen as programming error? Possibly user + * configurable number as well, might actually use the config subsystem + * :D + * In such a case it would probably be smarter to mark all pages + * inaccessible at first, and then mark the first page accessible. If + * the process needs more stack space it'll cause a paging exception, + * we'll handle it separately and if the process isn't going over the + * limit just give it more. + * */ mark_rpc_inaccessible(t, rpc_stack, t->rpc_stack); t->rpc_stack = rpc_stack; t->regs = (vm_t)ctx; @@ -461,3 +474,11 @@ void load_context(struct tcb *t) t->eid = ctx->eid; t->regs = ctx->regs; } + +bool enough_rpc_stack(struct tcb *t) +{ + vm_t top = RPC_STACK_BASE + __call_stack_size; + vm_t rpc_stack = t->rpc_stack + BASE_PAGE_SIZE; + + return top - rpc_stack >= __call_stack_size / 4; +} diff --git a/common/uapi/conf.c b/common/uapi/conf.c index 2094604..596cb5c 100644 --- a/common/uapi/conf.c +++ b/common/uapi/conf.c @@ -16,6 +16,15 @@ * conf*-syscalls even necessary? */ size_t __thread_stack_size = SZ_2M; size_t __call_stack_size = SZ_2M; +size_t __rpc_stack_size = SZ_512K; + +/** IDs for configuration parameters. */ +/** @todo should probably be moved somewhere so it can be shared with userspace */ +enum conf_param { + CONF_THREAD_STACK = 0, + CONF_CALL_STACK, + CONF_RPC_STACK, +}; /** * Configuration parameter read syscall handler. @@ -27,7 +36,29 @@ size_t __call_stack_size = SZ_2M; */ SYSCALL_DEFINE1(conf_get)(sys_arg_t param) { - return SYS_RET1(OK); + struct tcb *t = cur_tcb(); + if (!has_cap(t->caps, CAP_CONF)) + return SYS_RET1(ERR_PERM); + + long val = 0; + switch (param) { + case CONF_THREAD_STACK: + val = __thread_stack_size; + break; + + case CONF_CALL_STACK: + val = __call_stack_size; + break; + + case CONF_RPC_STACK: + val = __rpc_stack_size; + break; + + default: + return SYS_RET1(ERR_NF); + } + + return SYS_RET2(OK, val); } /** @@ -41,9 +72,32 @@ SYSCALL_DEFINE1(conf_get)(sys_arg_t param) */ SYSCALL_DEFINE2(conf_set)(sys_arg_t param, sys_arg_t val) { - UNUSED(param); - UNUSED(val); - /* no parameters supported atm */ + struct tcb *t = cur_tcb(); + if (!has_cap(t->caps, CAP_CONF)) + return SYS_RET1(ERR_PERM); + + size_t size = 0; + switch (param) { + case CONF_THREAD_STACK: + __thread_stack_size = align_up(val, BASE_PAGE_SIZE); + break; + + case CONF_CALL_STACK: + size = align_up(val, 4 * BASE_PAGE_SIZE); + if (size < __rpc_stack_size * 4) + return SYS_RET1(ERR_MISC); + + __call_stack_size = size; + break; + + case CONF_RPC_STACK: + size = align_up(val, BASE_PAGE_SIZE); + if (size > __call_stack_size / 4) + return SYS_RET1(ERR_MISC); + + __rpc_stack_size = size; + break; + } return SYS_RET1(OK); } diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c index 052e0ad..5d91588 100644 --- a/common/uapi/ipc.c +++ b/common/uapi/ipc.c @@ -41,6 +41,9 @@ static struct sys_ret do_ipc(sys_arg_t pid, bool fwd) { struct tcb *t = cur_tcb(); + if (!enough_rpc_stack(t)) + return SYS_RET1(ERR_OOMEM); + struct tcb *r = get_tcb(pid); if (!r) return SYS_RET1(ERR_INVAL); diff --git a/include/apos/caps.h b/include/apos/caps.h index be64663..e762d0f 100644 --- a/include/apos/caps.h +++ b/include/apos/caps.h @@ -20,7 +20,7 @@ enum { /** Thread is allowed to set capabilities of other threads. */ CAP_CAPS = (1 << 0), - /** Thread is allowed to modify process statuses, exec/fork/etc. */ + /** Thread is allowed to modify process statuses, create/exec/fork/etc. */ CAP_PROC = (1 << 1), /** Thread is allowed to force interrupt to callback in other thread. */ @@ -28,6 +28,9 @@ enum { /** Thread is allowed to shut down system. */ CAP_POWER = (1 << 3), + + /** Thread is allowed to access configuration parameters. */ + CAP_CONF = (1 << 4), }; /** diff --git a/include/apos/conf.h b/include/apos/conf.h index 467b1e3..33fa8e5 100644 --- a/include/apos/conf.h +++ b/include/apos/conf.h @@ -23,10 +23,24 @@ extern size_t __thread_stack_size; /** * Provides access to the runtime global parameter. + * Must be at most RPC_STACK_TOP - RPC_STACK_BASE. + * * \see __thread_stack_size. * \global * \todo This should probably also be a function instead. */ extern size_t __call_stack_size; +/** + * Provides access to the runtime global parameter. This sets the maximum size + * a single rpc stack instance can be. + * + * Must be at most a fourth of \ref __call_stack_size? + * (that way we can maybe pretty quickly check that we're running out of memory + * for stack stuff and can return an error about it) + * + * \global + */ +extern size_t __rpc_stack_size; + #endif /* APOS_CONF_H */ diff --git a/include/apos/tcb.h b/include/apos/tcb.h index 6097153..981f352 100644 --- a/include/apos/tcb.h +++ b/include/apos/tcb.h @@ -389,4 +389,12 @@ void save_context(struct tcb *t); */ void load_context(struct tcb *t); +/** + * Check that we have enough rpc stack. + * + * @param t Thread whose rpc stack to check. + * @return \ref true if we have enough, \ref false otherwise. + */ +bool enough_rpc_stack(struct tcb *t); + #endif /* APOS_TCB_H */ -- cgit v1.3