diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-05-24 13:24:27 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-05-24 18:13:43 +0300 |
| commit | bc600ecc3bdf0f189861dfb840f70c2339a7a853 (patch) | |
| tree | d9840b1dc1b865442a028c03ad7109ac67894f6e /src/uapi/proc.c | |
| parent | 6a7073e5f262db9a4578ff00b5b28e34335564ce (diff) | |
| download | kmi-bc600ecc3bdf0f189861dfb840f70c2339a7a853.tar.gz kmi-bc600ecc3bdf0f189861dfb840f70c2339a7a853.zip | |
rename common to src
+ I keep starting to type src and wondering why autocomplete won't work,
I guess src is just uncounciously a better name
Diffstat (limited to 'src/uapi/proc.c')
| -rw-r--r-- | src/uapi/proc.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/uapi/proc.c b/src/uapi/proc.c new file mode 100644 index 0000000..e7fa49d --- /dev/null +++ b/src/uapi/proc.c @@ -0,0 +1,188 @@ +/* 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)); +} |
