diff options
Diffstat (limited to 'common/uapi')
| -rw-r--r-- | common/uapi/cap.c | 94 | ||||
| -rw-r--r-- | common/uapi/conf.c | 115 | ||||
| -rw-r--r-- | common/uapi/dispatch.c | 89 | ||||
| -rw-r--r-- | common/uapi/ipc.c | 348 | ||||
| -rw-r--r-- | common/uapi/irq.c | 29 | ||||
| -rw-r--r-- | common/uapi/mem.c | 158 | ||||
| -rw-r--r-- | common/uapi/proc.c | 188 | ||||
| -rw-r--r-- | common/uapi/timers.c | 120 |
8 files changed, 0 insertions, 1141 deletions
diff --git a/common/uapi/cap.c b/common/uapi/cap.c deleted file mode 100644 index 157ef47..0000000 --- a/common/uapi/cap.c +++ /dev/null @@ -1,94 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -#include <kmi/uapi.h> -#include <kmi/caps.h> -#include <kmi/tcb.h> - -/** - * @file cap.c - * Sycalls handlers for thread capabilities. - */ - -/** - * Check that values are legal for thread ID and offset. - * - * @param tid Thread ID of thread whose caps should be fetched. - * @param off Offset of capabilities. - * @return Pointer to capabilities of \p tid, \c 0 otherwise. - */ -static capflags_t *__get_tcb_caps(id_t tid, size_t off) -{ - if (!cap_off_ok(off)) - return NULL; - - struct tcb *t = get_tcb(tid); - if (!t) - return NULL; - - return &t->caps; -} - -/** - * Set capabilities. - * - * @param t Current tcb. - * @param tid Thread ID whose capabilities to set. - * @param off Offset of capability, multiple of \c bits(cap). - * @param caps Mask of capabilities to set. - * @return \ref OK on success, \ref ERR_INVAL on invalid input. - */ -SYSCALL_DEFINE3(set_cap)(struct tcb *t, sys_arg_t tid, sys_arg_t off, - sys_arg_t caps) -{ - if (!is_set(t->caps, CAP_CAPS)) - return_args1(t, ERR_PERM); - - capflags_t *c; - if (!(c = __get_tcb_caps(tid, off))) - return_args1(t, ERR_INVAL); - - set_caps(*c, off, caps); - return_args1(t, OK); -} - -/** - * Get capabilities. - * - * @param t Current tcb. - * @param tid Thread ID whose capabilities to get. - * @param off Offset of capability, multiple of \c bits(cap). - * @return \ref OK, capabilities. - */ -SYSCALL_DEFINE2(get_cap)(struct tcb *t, sys_arg_t tid, sys_arg_t off) -{ - capflags_t *c; - if (!(c = __get_tcb_caps(tid, off))) - return_args1(t, ERR_INVAL); - - return_args2(t, OK, get_caps(*c, off)); -} - -/** - * Clear capabilities. - * - * @param t Current tcb. - * @param tid Thread ID whose capabilities to clear. - * @param off Offset of capability, multiple of \c bits(cap). - * @param caps Mask of capabilities to clear. - * @return ERR_LERM if invalid permissions, ERR_INVAL if \p tid doesn't exist, - * otherwise OK. - */ -SYSCALL_DEFINE3(clear_cap)(struct tcb *t, sys_arg_t tid, sys_arg_t off, - sys_arg_t caps) -{ - if (!is_set(t->caps, CAP_CAPS)) - return_args1(t, ERR_PERM); - - capflags_t *c; - if (!(c = __get_tcb_caps(tid, off))) - return_args1(t, ERR_INVAL); - - clear_caps(*c, off, caps); - return_args1(t, OK); -} diff --git a/common/uapi/conf.c b/common/uapi/conf.c deleted file mode 100644 index 894b98a..0000000 --- a/common/uapi/conf.c +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file conf.c - * Runtime configuration sycall implementations. - * - * At the moment there are not runtime configuration parameters. - */ - -#include <kmi/power.h> -#include <kmi/sizes.h> -#include <kmi/uapi.h> -#include <kmi/conf.h> - -#include <arch/proc.h> - -/** \todo stack size should really be set on a per-thread basis, and are the - * conf*-syscalls even necessary? */ -size_t __thread_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_RPC_STACK, -}; - -/** - * Configuration parameter read syscall handler. - * - * \todo Implement parameters. - * - * @param t Current tcb. - * @param param Parameter to read. - * @return \ref OK and parameter value. - */ -SYSCALL_DEFINE1(conf_get)(struct tcb *t, sys_arg_t param) -{ - if (!has_cap(t->caps, CAP_CONF)) - return_args1(t, ERR_PERM); - - long val = 0; - switch (param) { - case CONF_THREAD_STACK: - val = __thread_stack_size; - break; - - case CONF_RPC_STACK: - val = __rpc_stack_size; - break; - - default: - return_args1(t, ERR_NF); - } - - return_args2(t, OK, val); -} - -/** - * Configuration parameter write syscall handler. - * - * \todo Implement parameters. - * - * @param t Current tcb. - * @param param Parameter to write. - * @param val Value to set \c param to. - * @return \ref OK and \c 0. - */ -SYSCALL_DEFINE2(conf_set)(struct tcb *t, sys_arg_t param, sys_arg_t val) -{ - if (!has_cap(t->caps, CAP_CONF)) - return_args1(t, ERR_PERM); - - size_t size = 0; - switch (param) { - case CONF_THREAD_STACK: - __thread_stack_size = align_up(val, BASE_PAGE_SIZE); - break; - - case CONF_RPC_STACK: - size = align_up(val, BASE_PAGE_SIZE); - if (size > max_rpc_size()) - return_args1(t, ERR_MISC); - - __rpc_stack_size = size; - break; - } - - return_args1(t, OK); -} - -/** - * Poweroff syscall handler. - * - * @param t Current tcb. - * @param type Type of poweroff. - * @return \ref ERR_INVAL and \c 0 if incorrect poweroff \c type give, otherwise - * does not return. - */ -SYSCALL_DEFINE1(poweroff)(struct tcb *t, sys_arg_t type) -{ - if (!(has_cap(t->caps, CAP_POWER))) - return_args1(t, ERR_PERM); - - switch (type) { - case SHUTDOWN: - case COLD_REBOOT: - case WARM_REBOOT: - return_args2(t, OK, poweroff(type)); - }; - - return_args1(t, ERR_INVAL); -} diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c deleted file mode 100644 index 5b523cc..0000000 --- a/common/uapi/dispatch.c +++ /dev/null @@ -1,89 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file dispatch.c - * Syscall dispatch. - */ - -#include <kmi/canary.h> -#include <kmi/debug.h> -#include <kmi/uapi.h> - -/* not sure why doxygen requires these two definitions to state their return - * values, when they don't actually return anything but eh */ - -/** - * Noop syscall handler. - * - * @param t Current tcb. - * - * @return \ref OK and \c 0. - */ -SYSCALL_DEFINE0(noop)(struct tcb *t) -{ - info("sys_noop\n"); - set_args1(t, OK); -} - -/** - * Putch syscall handler. - * - * @param t Current tcb. - * @param a Character to put. - * - * @return \ref OK and 0. - */ -SYSCALL_DEFINE1(putch)(struct tcb *t, sys_arg_t a) -{ - dbg("%c", (char)a); - set_args1(t, OK); -} - -void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, - sys_arg_t c, sys_arg_t d, sys_arg_t e, struct tcb *t) -{ - adjust_syscall(t); - - switch (syscall) { - case SYS_NOOP: sys_noop(t, a, b, c, d, e); break; - case SYS_PUTCH: sys_putch(t, a, b, c, d, e); break; - case SYS_REQ_MEM: sys_req_mem(t, a, b, c, d, e); break; - case SYS_REQ_PAGE: sys_req_page(t, a, b, c, d, e); break; - case SYS_REQ_PMEM: sys_req_pmem(t, a, b, c, d, e); break; - case SYS_REQ_FIXMEM: sys_req_fixmem(t, a, b, c, d, e); break; - case SYS_REQ_SHAREDMEM: sys_req_sharedmem(t, a, b, c, d, e); break; - case SYS_FREE_MEM: sys_free_mem(t, a, b, c, d, e); break; - case SYS_TIMEBASE: sys_timebase(t, a, b, c, d, e); break; - case SYS_TICKS: sys_ticks(t, a, b, c, d, e); break; - case SYS_REQ_REL_TIMER: sys_req_rel_timer(t, a, b, c, d, e); break; - case SYS_REQ_ABS_TIMER: sys_req_abs_timer(t, a, b, c, d, e); break; - case SYS_IPC_SERVER: sys_ipc_server(t, a, b, c, d, e); break; - case SYS_IPC_REQ: sys_ipc_req(t, a, b, c, d, e); break; - case SYS_IPC_FWD: sys_ipc_fwd(t, a, b, c, d, e); break; - case SYS_IPC_KICK: sys_ipc_kick(t, a, b, c, d, e); break; - case SYS_IPC_RESP: sys_ipc_resp(t, a, b, c, d, e); break; - case SYS_IPC_NOTIFY: sys_ipc_notify(t, a, b, c, d, e); break; - case SYS_CREATE: sys_create(t, a, b, c, d, e); break; - case SYS_FORK: sys_fork(t, a, b, c, d, e); break; - case SYS_EXEC: sys_exec(t, a, b, c, d, e); break; - case SYS_SPAWN: sys_spawn(t, a, b, c, d, e); break; - case SYS_KILL: sys_kill(t, a, b, c, d, e); break; - case SYS_SWAP: sys_swap(t, a, b, c, d, e); break; - case SYS_CONF_SET: sys_conf_set(t, a, b, c, d, e); break; - case SYS_CONF_GET: sys_conf_get(t, a, b, c, d, e); break; - case SYS_SET_CAP: sys_set_cap(t, a, b, c, d, e); break; - case SYS_GET_CAP: sys_get_cap(t, a, b, c, d, e); break; - case SYS_CLEAR_CAP: sys_clear_cap(t, a, b, c, d, e); break; - case SYS_POWEROFF: sys_poweroff(t, a, b, c, d, e); break; - case SYS_IRQ_REQ: sys_irq_req(t, a, b, c, d, e); break; - default: - error("Syscall %zu outside allowed range [0 - %i]\n", syscall, - SYS_NUM - 1); - set_args1(t, ERR_INVAL); - }; - - if (check_canary(t)) { - bug("Syscall %zu overwrote stack canary\n", syscall); - } -} diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c deleted file mode 100644 index cb2ce28..0000000 --- a/common/uapi/ipc.c +++ /dev/null @@ -1,348 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file ipc.c - * Interprocess communication syscall implementations. - */ - -#include <kmi/uapi.h> -#include <kmi/tcb.h> -#include <kmi/ipi.h> -#include <kmi/conf.h> - -/** Structure for maintaining the required context data for an rpc call. */ -struct call_ctx { - /** Execution continuation point. */ - vm_t exec; - - /** Register save area. */ - vm_t regs; - - /** Position in rpc stack. */ - vm_t rpc_stack; - - /** Effective process ID. */ - id_t eid; - - /** Current process ID. */ - id_t pid; - - /** Whether this context should be skipped when responding. */ - bool kick; -}; - -/** - * Represents difference between where rpc stack was before rpc call and during. - * Used to figure out which areas should be marked inaccessible. - */ -struct stack_diff { - /** Current stack start. Keep in mind that stacks grow down. */ - vm_t start; - /** Difference end, i.e. previous stack start. */ - vm_t end; -}; - -/** Enumerator for IPC kind. Used by do_ipc(). */ -enum ipc_kind { - IPC_REQ, IPC_FWD, IPC_KICK -}; - -/** - * Now that we know we're doing an rpc, clone virtual memories and do - * the slow stuff. - * - * @param t Thread to migrate. - * @param r Process to migrate to. - * @param s RPC stack regions to mark inaccessible. - */ -static void finalize_rpc(struct tcb *t, struct tcb *r, vm_t s) -{ - clone_uvmem(r->proc.vmem, t->rpc.vmem); - set_return(t, r->callback); - reference_proc(r); - t->pid = r->rid; - - /* make sure updates are visible when swapping to the new virtual memory */ - mark_rpc_invalid(t, s); - use_vmem(t->rpc.vmem); -} - -/** - * Optimistically assume we're going to take the rpc and do some preparations - * for it. Most notably, write the arguments as early as possible to - * free up registers for the compiler to play with. - * - * @param t Thread to migrate. - * @param a RPC arguments. - * @param kind Kind of IPC we're doing. Essentially toggles kick boolean. - * @return RPC stack difference that should be passed to finalize_rpc(). - */ -static vm_t enter_rpc(struct tcb *t, struct sys_ret a, - enum ipc_kind kind) -{ - vm_t rpc_stack = rpc_position(t); - - struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; - ctx->regs = t->regs; - t->regs = (vm_t)ctx; - - /* try to get rid of args as fast as possible to free up registers for - * later use */ - set_args(t, 6, a); - - ctx->exec = t->exec; - ctx->pid = t->pid; - ctx->eid = t->eid; - ctx->rpc_stack = rpc_stack; - - /* only rpcs can be kicked forward */ - ctx->kick = kind == IPC_KICK && is_rpc(t); - - /** @todo if we run out of rpc_stack space we should just stop, likely - * return a status? except it shouldn't happen after we've run - * enough_rpc_stack(). */ - vm_t new_stack = 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. - * */ - t->rpc_stack = new_stack; - set_stack(t, new_stack); - return new_stack; -} - -/** - * Jump back to process where rpc came from, assuming such a thing exists. - * - * @param t Thread to do return migration on. - * @param a Arguments to pass along. - */ -static void leave_rpc(struct tcb *t, struct sys_ret a) -{ - vm_t rpc_stack = t->rpc_stack + BASE_PAGE_SIZE; - struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1; - vm_t top = ctx->rpc_stack; - - /* find first instance of not kicked context */ - while (ctx->kick) { - rpc_stack = ctx->rpc_stack + BASE_PAGE_SIZE; - ctx = (struct call_ctx *)(rpc_stack) - 1; - unreference_proc(get_tcb(ctx->pid)); - } - - t->regs = ctx->regs; - /* again, get rid of args as fast as possible */ - set_args(t, 6, a); - - set_return(t, ctx->exec); - /* if we're returning from a failed rpc, this should essentially be a - * no-op */ - mark_rpc_valid(t, top); - t->rpc_stack = ctx->rpc_stack; - t->pid = ctx->pid; - t->eid = ctx->eid; - - if (is_rpc(t)) - use_vmem(t->rpc.vmem); - else - use_vmem(t->proc.vmem); -} - -/** - * Check that there's enough stack left for an rpc invocation. - * - * @param t Thread whose migration to check. - * @return \c true if there's enough stack left to safely do migration, - * \c false otherwise. - */ -static bool enough_rpc_stack(struct tcb *t) -{ - /* get top of call stack */ - vm_t top = rpc_position(t); - - /* if we can still fit an rpc stack into the call stack, we can safely - * do the migration. */ - return top - BASE_PAGE_SIZE - __rpc_stack_size >= RPC_STACK_BASE; -} - -/** - * IPC server notification syscall handler. - * - * @param t Current tcb. - * @param callback Address of server callback. - * @return \ref OK and \c 0. - */ -SYSCALL_DEFINE1(ipc_server)(struct tcb *t, sys_arg_t callback) -{ - get_cproc(t)->callback = callback; - return_args1(t, OK); -} - -/** - * Actual IPC syscall handler. - * - * @param t Current tcb. - * @param pid Process to request RPC to. - * @param d0 IPC argument 0. - * @param d1 IPC argument 1. - * @param d2 IPC argument 2. - * @param d3 IPC argument 3. - * @param kind Which kind of IPC to perform. - * - * Returns \ref ERR_OOMEM if there isn't enough IPC stack left, \ref ERR_INVAL - * if the the target process doesn't exist, \ref ERR_NOINIT if the target - * process hasn't defined a callback. Otherwise \ref OK and whatever the target - * process sends back. - * - * @todo should all static functions have double underscores? I seem to be - * inconsistent. - */ -static void do_ipc(struct tcb *t, - sys_arg_t pid, - sys_arg_t d0, - sys_arg_t d1, - sys_arg_t d2, - sys_arg_t d3, - enum ipc_kind kind) -{ - if (unlikely(!enough_rpc_stack(t))) - return_args1(t, ERR_OOMEM); - - vm_t s = enter_rpc(t, SYS_RET6(t->eid, t->tid, d0, d1, d2, d3), kind); - - struct tcb *r = get_tcb(pid); - if (unlikely(!r)) { - leave_rpc(t, SYS_RET1(ERR_INVAL)); - return; - } - - r = get_rproc(r); - if (unlikely(r->dead)) { - leave_rpc(t, SYS_RET1(ERR_INVAL)); - return; - } - - if (unlikely(!r->callback)) { - leave_rpc(t, SYS_RET1(ERR_NOINIT)); - return; - } - - if (kind != IPC_REQ) - t->eid = t->pid; - - finalize_rpc(t, r, s); - /* I tested out passing the return values as arguments to - * ret_userspace_fast, but apparently that causes enough stack shuffling - * to be slower overall. */ - ret_userspace_fast(); -} -/** - * IPC request syscall handler. - * - * @param t Current tcb. - * @param pid Process to request RPC to. - * @param d0 IPC argument 0. - * @param d1 IPC argument 1. - * @param d2 IPC argument 2. - * @param d3 IPC argument 3. - * @return When succesful: OK, thread id of the caller and the arguments as-is. - */ -SYSCALL_DEFINE5(ipc_req)(struct tcb *t, sys_arg_t pid, - sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) -{ - do_ipc(t, pid, d0, d1, d2, d3, IPC_REQ); -} - -/** - * IPC forwarding syscall handler. - * - * @param t Current tcb. - * @param pid Process to request RPC to. - * @param d0 IPC argument 0. - * @param d1 IPC argument 1. - * @param d2 IPC argument 2. - * @param d3 IPC argument 3. - * @return When succesful: OK, thread id of the caller and the arguments as-is. - */ -SYSCALL_DEFINE5(ipc_fwd)(struct tcb *t, sys_arg_t pid, - sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) -{ - do_ipc(t, pid, d0, d1, d2, d3, IPC_FWD); -} - -/** - * IPC kicking syscall handler. - * - * @param t Current tcb. - * @param pid Process to request RPC to. - * @param d0 IPC argument 0. - * @param d1 IPC argument 1. - * @param d2 IPC argument 2. - * @param d3 IPC argument 3. - * @return When succesful: OK, thread id of the caller and the arguments as-is. - */ -SYSCALL_DEFINE5(ipc_kick)(struct tcb *t, sys_arg_t pid, - sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, - sys_arg_t d3) -{ - do_ipc(t, pid, d0, d1, d2, d3, IPC_KICK); -} - -/** - * IPC response syscall handler. - * - * @param t Current tcb. - * @param d0 IPC return value 0. - * @param d1 IPC return value 1. - * @param d2 IPC return value 2. - * @param d3 IPC return value 3. - * @return \c d0 and \c d1. - */ -SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1, - sys_arg_t d2, - sys_arg_t d3) -{ - /* if we're not in an rpc, the user messed something up. */ - /** @todo choose or come up with more fitting error value. */ - if (unlikely(!is_rpc(t))) - return_args1(t, ERR_MISC); - - leave_rpc(t, SYS_RET6(OK, t->tid, d0, d1, d2, d3)); -} - -/** - * Notify syscall handler. - * - * \todo Implement. - * - * @param t Current tcb. - * @param tid Thread ID to notify. - * @return \ref OK and 0. - */ -SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){ - if (!has_cap(t->caps, CAP_CALL)) - return_args1(t, ERR_PERM); - - struct tcb *r = get_tcb(tid); - if (r->notify_state == NOTIFY_QUEUED) - return_args1(t, OK); - - if (r->notify_state == NOTIFY_RUNNING) { - t->notify_state = NOTIFY_QUEUED; - return_args1(t, OK); - } - - r->notify_state = NOTIFY_QUEUED; - if (running(r)) - send_ipi(r); - - return_args1(t, OK); -} diff --git a/common/uapi/irq.c b/common/uapi/irq.c deleted file mode 100644 index 6687826..0000000 --- a/common/uapi/irq.c +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2023, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file irq.c - * IRQ request syscall handling implementation. - */ - -#include <kmi/uapi.h> -#include <kmi/irq.h> - -/** - * Actual IRQ handling request syscall handler. - * - * @param t Current tcb. - * @param id IRQ id to request to handle. - * - * @return OK on success, non-zero otherwise. - */ -SYSCALL_DEFINE1(irq_req)(struct tcb *t, sys_arg_t id) -{ - if (!has_cap(t->caps, CAP_IRQ)) - return_args1(t, ERR_PERM); - - if (!t->callback) - return_args1(t, ERR_NF); - - return_args1(t, register_irq(t, id)); -} diff --git a/common/uapi/mem.c b/common/uapi/mem.c deleted file mode 100644 index d54390a..0000000 --- a/common/uapi/mem.c +++ /dev/null @@ -1,158 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file mem.c - * Memory handling syscall implementations. - * \todo Should we return more error information? - */ - -#include <kmi/uapi.h> -#include <kmi/utils.h> -#include <kmi/vmem.h> -#include <kmi/dmem.h> - -/** - * Memory request syscall handler. - * - * @param t Current tcb. - * @param size Minimum size of allocation. - * @param flags Flags of allocation. - * @return \ref OK and start of allocation when succesful, - * \ref ERR_OOMEM and \c NULL otherwise. - */ -SYSCALL_DEFINE2(req_mem)(struct tcb *t, sys_arg_t size, sys_arg_t flags) -{ - struct tcb *r = get_cproc(t); - vm_t start = 0; - /** @todo expose flags to users */ - if (!(start = alloc_uvmem(r, size, flags))) - return_args1(t, ERR_OOMEM); - - return_args2(t, OK, start); -} - -/** - * Allocate single page to program. - * - * @param t Current tcb. - * @param size Size of the allocation. - * @param flags Flags of allocation. - * @return \ref ERR_OOMEM if unsucessful, otherwise \ref OK, virtual address, - * actual size, physical address, in that order. - */ -SYSCALL_DEFINE2(req_page)(struct tcb *t, sys_arg_t size, sys_arg_t flags) -{ - struct tcb *r = get_cproc(t); - vm_t start = 0; pm_t paddr = 0; size_t asize = size; - if (!(start = alloc_uvpage(r, asize, flags, &asize, &paddr))) - return_args1(t, ERR_OOMEM); - - return_args4(t, OK, start, asize, paddr); -} - -/** - * Fixed memory request syscall handler. - * - * @param t Current tcb. - * @param fixed Address which should be included in allocation. - * @param size Minimum size of allocation after \c start. - * @param flags Flags of allocation. - * @return \ref OK and start of allocation when succesful, - * \ref ERR_OOMEM and \c NULL otherwise. - */ -SYSCALL_DEFINE3(req_fixmem)(struct tcb *t, sys_arg_t fixed, sys_arg_t size, - sys_arg_t flags) -{ - struct tcb *r = get_cproc(t); - vm_t start = 0; - if (!(start = alloc_fixed_uvmem(r, fixed, size, flags))) - return_args1(t, ERR_OOMEM); - - return_args2(t, OK, start); -} - -/** - * Free memory syscall handler. - * - * @param t Current tcb. - * @param start Start of allocation to free. - * @return \ref OK and \c 0 when succesful, \ref ERR_NF and \c 0 otherwise. - */ -SYSCALL_DEFINE1(free_mem)(struct tcb *t, sys_arg_t start) -{ - struct tcb *r = get_cproc(t); - vm_t vm_start = (vm_t)start; - - stat_t status = OK; - /* try freeing normal user memory first, if that fails, try device - * memory, otherwise just assume the address is borked. */ - if (!(status = free_uvmem(r, vm_start))) - return_args1(t, OK); - - if (!(status = free_devmem(r, vm_start))) - return_args1(t, OK); - - return_args1(t, status); -} - -/** - * Request physical memory syscall handler. - * - * @param t Current tcb. - * @param paddr Physical address to map. - * @param size Minimum size of allocation. - * @param flags Flags of allocation. - * @return \ref OK and start of allocation when succesful, - * \ref ERR_OOMEM and \c NULL otherwise. - */ -SYSCALL_DEFINE3(req_pmem)(struct tcb *t, sys_arg_t paddr, sys_arg_t size, - sys_arg_t flags) -{ - /* this will require some pondering, but essentially this syscall should - * only be used for device access, so any addresses requested should be - * outside the RAM area, and I'll probably have to implement some method - * that keeps track of used regions outside of RAM. We'll see. - */ - struct tcb *r = get_cproc(t); - vm_t start = 0; - if (!(start = alloc_devmem(r, paddr, size, flags))) - return_args1(t, ERR_OOMEM); - - return_args2(t, OK, start); -} - -/** - * Request shared memory syscall handler. - * - * @param t Current tcb. - * @param tid Thread to share memory with. - * @param size Minimum size of allocation. - * @param sflags Flags of allocation for \p t. - * @param cflags Flags of allocation for \p tid. - * @return \ref OK and start of \p t allocation and start of \p tid allocation, - * in that order, \ref ERR_OOMEM otherwise. - * - * @todo should we also take the thread who should get the other end of the - * memory? - */ -SYSCALL_DEFINE4(req_sharedmem)(struct tcb *t, sys_arg_t tid, - sys_arg_t size, sys_arg_t sflags, - sys_arg_t cflags) -{ - /** @todo check capability for shared memory */ - struct tcb *u = get_tcb(tid); - if (!u) - return_args1(t, ERR_INVAL); - - struct tcb *s = get_cproc(t); - struct tcb *c = get_rproc(u); - - vm_t sstart, cstart; - if (alloc_shared_uvmem(s, c, size, sflags, cflags, &sstart, &cstart)) - return_args1(t, ERR_OOMEM); - - return_args3(t, OK, sstart, cstart); -} - -/** \todo add some way to specify who gets to access the shared memory? */ diff --git a/common/uapi/proc.c b/common/uapi/proc.c deleted file mode 100644 index e7fa49d..0000000 --- a/common/uapi/proc.c +++ /dev/null @@ -1,188 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file proc.c - * Process/thread handling syscall implementations. - */ - -#include <kmi/elf.h> -#include <kmi/uapi.h> -#include <kmi/proc.h> -#include <kmi/bits.h> -#include <kmi/mem_regions.h> - -/** - * Create syscall handler. - * - * @param t Current tcb. - * @param func Function to jump to at thread creation. - * @param d0 Argument 0. - * @param d1 Argument 1. - * @param d2 Argument 2. - * @param d3 Argument 3. - * - * @return ERR_OOMEM if thread creation was unsuccessful, otherwise OK and the - * thread id. - */ -SYSCALL_DEFINE5(create)(struct tcb *t, sys_arg_t func, - sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) -{ - struct tcb *c = create_thread(t); - if (!c) - return_args1(t, ERR_OOMEM); - - alloc_stack(c); - - set_args5(c, c->tid, d0, d1, d2, d3); - set_return(c, func); - - return_args2(t, OK, c->tid); -} - -/** - * Fork syscall handler. - * - * \todo Not entirely sure how I should handle forks/execs etc, mostly whether I - * should allow forks/execs to be called directly or only though the process - * manager. Probably though the process manager, although that will add in a - * slight bit of delay. - * - * I suppose I could add in a runtime parameter - * that would allow them to be called directly, and then the process manager - * would have to periodically ask the kernel about all threads it is aware of - * via sys_sync. Dunno. - * - * @param t Current tcb. - * @return \ref OK and 0. - */ -SYSCALL_DEFINE0(fork)(struct tcb *t) -{ - struct tcb *c = get_cproc(t); - if (!(has_cap(c->caps, CAP_PROC))) - return_args1(t, ERR_PERM); - - struct tcb *n = create_proc(get_eproc(t)); - if (!n) - return_args1(t, ERR_OOMEM); - - /* prepare args for when we eventually swap to the new proc, giving - * parent ID as third return value */ - set_args3(n, OK, 0, get_eproc(t)->pid); - - return_args2(t, OK, n->pid); -} - -/** - * Exec syscall handler. - * - * @param t Current tcb. - * @param bin Binary to execute. - * @param interp Optional interpreter binary. - * - * @return \see prepare_proc(). - */ -SYSCALL_DEFINE2(exec)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) -{ - /** @todo probably make sure thread is root thread of process? */ - /* mark binary to be kept */ - struct mem_region *b = find_used_region(&t->sp_r, bin); - if (!b) - return_args1(t, ERR_INVAL); - - set_bit(b->flags, MR_KEEP); - - struct mem_region *i = 0; - if (interp) { - /* mark interpreter to be kept */ - i = find_used_region(&t->sp_r, interp); - if (!i) - return_args1(t, ERR_INVAL); - - set_bit(i->flags, MR_KEEP); - } - - /* free everything except regions to be kept */ - clear_uvmem(t); - - /* restore to normal */ - clear_bit(b->flags, MR_KEEP); - if (interp) - clear_bit(b->flags, MR_KEEP); - - return_args1(t, prepare_proc(t, bin, interp)); -} - -/** - * Spawn syscall handler. - * - * @param t Current tcb. - * @param bin Binary to execute. - * @param interp Optional interpreter binary. - * - * @return \see prepare_proc() and process id of the new process. - */ -SYSCALL_DEFINE2(spawn)(struct tcb *t, sys_arg_t bin, sys_arg_t interp) -{ - struct tcb *c = get_proc(t); - if (!(has_cap(c->caps, CAP_PROC))) - return_args1(t, ERR_PERM); - - struct tcb *n = create_proc(NULL); - if (!n) - return_args1(t, ERR_OOMEM); - - return_args2(t, prepare_proc(n, bin, interp), n->pid); -} - -/** - * Kill syscall handler. - * - * @param t Current tcb. - * @param tid Thread to kill. - * \todo Implement. - * - * @return ERR_PERM if not capable to kill, otherwise OK. - */ -SYSCALL_DEFINE1(kill)(struct tcb *t, sys_arg_t tid) -{ - struct tcb *c = get_cproc(t); - if (!(has_cap(c->caps, CAP_PROC))) - return_args1(t, ERR_PERM); - - /** @todo implement */ - /** @todo remember to unregister IRQ handlers */ - - return_args1(t, OK); -} - -/** - * Swap syscall handler. - * - * \todo Implement. - * \todo Should swap return the registers of the new thread that would be used - * for message passing? - * - * @param t Current tcb. - * @param tid Thread ID to swap to. - * - * @return \ref OK. - */ -SYSCALL_DEFINE1(swap)(struct tcb *t, sys_arg_t tid){ - struct tcb *c = get_cproc(t); - if (!(has_cap(c->caps, CAP_PROC))) - return_args1(t, ERR_PERM); - - struct tcb *s = get_tcb(tid); - if (!s) - return_args1(t, ERR_INVAL); - - /* switch over to new thread */ - use_tcb(s); - - /* set return value for current thread */ - set_args1(t, OK); - - /* get register state for new thread */ - return_args(s, get_args(s)); -} diff --git a/common/uapi/timers.c b/common/uapi/timers.c deleted file mode 100644 index b119fcc..0000000 --- a/common/uapi/timers.c +++ /dev/null @@ -1,120 +0,0 @@ -/* SPDX-License-Identifier: copyleft-next-0.3.1 */ -/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ - -/** - * @file timers.c - * Timer syscall implementations. - */ - -#include <kmi/timer.h> -#include <kmi/uapi.h> - -#include <arch/timer.h> - -/** - * Convert arch-specific register values \p ticks and \p mult to \ref ticks_t. - * - * If we're on a 32bit system, one register can't contain a tick value, - * so we use two registers and combine them into one value and let the compiler - * handle the rest. - * - * @param ticks Register width tick value. - * @param mult Register width repeat value. - * @return Corresponding \ref ticks_t value. - */ -static ticks_t scaled_ticks(sys_arg_t ticks, sys_arg_t mult) -{ -#if defined(_LP64) - UNUSED(mult); - return ticks; -#else - return (ticks_t)ticks * (ticks_t)mult; -#endif -} - -/** - * Timebase syscall handler. - * - * @param t Current tcb. - * @return \ref OK and timebase in second argument if 64bit, otherwise high 32 - * bits of timebase in second argument and low 32 bits in third argument. - */ -SYSCALL_DEFINE0(timebase)(struct tcb *t) -{ - ticks_t tm = secs_to_ticks(1); -#if defined(_LP64) - return_args2(t, OK, tm); -#else - return_args3(t, OK, tm >> 32, tm); -#endif -} - -/** - * Current ticks syscall handler. - * - * Note that most platforms allow user level read access to hardware timers, and - * should be preferred over this syscall on such platforms. Still, for - * completeness sake. - * - * @param t Current tcb. - * @return \ref OK and the current ticks when on 64bit systems, otherwise high - * 32 bits of ticks in second argument and low 32 bits in third. - */ -SYSCALL_DEFINE0(ticks)(struct tcb *t) -{ - ticks_t tm = current_ticks(); -#if defined(_LP64) - return_args2(t, OK, tm); -#else - return_args3(t, OK, tm >> 32, tm); -#endif -} - -/** - * Relative timer request syscall handler. - * - * \note On 64bit systems, \p mult is ignored as \p ticks register is large - * enough to contain essentially any timepoint we want. A couple thousand years - * when the clock runs at 5GHz, if I'm not completely mistaken. - * - * @param t Current tcb. - * @param ticks Number of ticks from now. - * @param mult Multiply \c ticks by this value. - * @return \ref OK and \c cid of created timer. - */ -SYSCALL_DEFINE2(req_rel_timer)(struct tcb *t, sys_arg_t ticks, sys_arg_t mult) -{ - return_args2(t, OK, new_rel_timer(t->tid, scaled_ticks(ticks, mult))); -} - -/** - * Absolute timer request syscall handler. - * - * @param t Current tcb. - * @param ticks Absolute timepoint relative to some start point defined at boot. - * @param mult Multiply \c ticks by this value. - * @return \ref OK and \c cid of created timer. - * \see req_rel_timer(). - */ -SYSCALL_DEFINE2(req_abs_timer)(struct tcb *t, sys_arg_t ticks, sys_arg_t mult) -{ - return_args2(t, OK, new_abs_timer(t->tid, scaled_ticks(ticks, mult))); -} - -/** - * Free timer request syscall handler. - * - * @param t Current tcb. - * @param cid \c cid of timer to free. - * @return \ref ERR_NF and \c 0if no timer could be found with \c cid, \ref OK - * and 0 otherwise. - */ -SYSCALL_DEFINE1(free_timer)(struct tcb *t, sys_arg_t cid) -{ - struct timer *timer = find_timer(cid); - if (!timer) - return_args1(t, ERR_NF); - - remove_timer(timer); - return_args1(t, OK); -} |
