aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ipi.c10
-rw-r--r--src/irq.c15
-rw-r--r--src/proc.c2
-rw-r--r--src/timer.c9
-rw-r--r--src/uapi/dispatch.c2
-rw-r--r--src/uapi/ipc.c89
-rw-r--r--src/uapi/irq.c14
-rw-r--r--src/uapi/proc.c3
8 files changed, 118 insertions, 26 deletions
diff --git a/src/ipi.c b/src/ipi.c
index 59f9fd1..79b363f 100644
--- a/src/ipi.c
+++ b/src/ipi.c
@@ -1,10 +1,11 @@
/* SPDX-License-Identifier: copyleft-next-0.3.1 */
/* Copyright 2023 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
+#include <kmi/notify.h>
#include <kmi/ipi.h>
-#include <arch/cpu.h>
#include <arch/proc.h>
+#include <arch/cpu.h>
/**
* @file ipi.c
@@ -30,6 +31,9 @@ void handle_ipi()
struct tcb *t = cur_tcb();
adjust_ipi(t);
- /** @todo use rpc stack */
- set_return(t, t->callback);
+ /** @todo how do we get the target thread? What if multiple threads send
+ * ipis at the same time? */
+ struct tcb *r = NULL;
+ notify(r);
+ /* notify didn't take for whatever reason so return whence we came from */
}
diff --git a/src/irq.c b/src/irq.c
index db90d34..8d01fbd 100644
--- a/src/irq.c
+++ b/src/irq.c
@@ -10,6 +10,7 @@
#include <kmi/pmem.h>
#include <kmi/debug.h>
#include <kmi/assert.h>
+#include <kmi/notify.h>
#include <kmi/string.h>
#include <arch/irq.h>
@@ -59,9 +60,19 @@ void handle_irq()
id_t tid = irq_map[id];
if (!tid) {
- bug("unregistered irq: %llu\n", (unsigned long long)id);
+ bug("unregistered irq %llu\n", (unsigned long long)id);
return;
}
- /** @todo switch to thread */
+ struct tcb *t = get_tcb(tid);
+ if (!t) {
+ error("tcb %llu dead at irq %llu\n",
+ (unsigned long long)tid,
+ (unsigned long long)id);
+ return;
+ }
+
+ disable_irqs();
+ notify(t);
+ error("misc error when trying to notify irq");
}
diff --git a/src/proc.c b/src/proc.c
index b91c486..7bfab0a 100644
--- a/src/proc.c
+++ b/src/proc.c
@@ -48,6 +48,8 @@ stat_t init_proc(void *fdt)
/* init process has all capabilities */
set_caps(t->caps, 0, CAP_CAPS | CAP_PROC | CAP_CALL | CAP_POWER);
+ t->notify_id = t->tid;
+
/* allocate stacks after ELF file to make sure nothing of importance
* clashes */
return prepare_proc(t, get_init_base(fdt), 0);
diff --git a/src/timer.c b/src/timer.c
index 474d995..5af03e8 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -16,12 +16,13 @@
*/
#include <kmi/sp_tree.h>
+#include <arch/timer.h>
#include <kmi/string.h>
+#include <kmi/notify.h>
#include <kmi/nodes.h>
#include <kmi/utils.h>
#include <kmi/timer.h>
#include <kmi/debug.h>
-#include <arch/timer.h>
#include <arch/cpu.h>
/** Timer resolution. */
@@ -199,5 +200,9 @@ void handle_timer()
struct timer *t = newest_timer();
remove_timer(t);
- /** \todo handle timer thread ID */
+ struct tcb *r = get_tcb(t->tid);
+ if (!r)
+ return;
+
+ notify(r);
}
diff --git a/src/uapi/dispatch.c b/src/uapi/dispatch.c
index f160091..a7f0322 100644
--- a/src/uapi/dispatch.c
+++ b/src/uapi/dispatch.c
@@ -56,6 +56,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
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_NOTIFICATION: sys_req_notification(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;
@@ -63,6 +64,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
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_GHOST: sys_ipc_ghost(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;
diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c
index bc836fc..8df0e3f 100644
--- a/src/uapi/ipc.c
+++ b/src/uapi/ipc.c
@@ -9,6 +9,7 @@
#include <kmi/uapi.h>
#include <kmi/tcb.h>
#include <kmi/ipi.h>
+#include <kmi/irq.h>
#include <kmi/conf.h>
/** Structure for maintaining the required context data for an rpc call. */
@@ -120,7 +121,48 @@ static vm_t enter_rpc(struct tcb *t, struct sys_ret a,
}
/**
+ * 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;
+}
+
+void notify(struct tcb *t)
+{
+ /* some duplication from do_ipc, but not too bad I guess */
+ struct tcb *notify = get_tcb(t->notify_id);
+ if (!notify || !notify->callback) {
+ t->notify_state = NOTIFY_WAITING;
+ return;
+ }
+
+ if (unlikely(!enough_rpc_stack(t))) {
+ t->notify_state = NOTIFY_WAITING;
+ return;
+ }
+
+ /* signal to whoever is receiving us that we're from the kernel
+ * ("pid 0"), and we are notifying the current thread */
+ vm_t s = enter_rpc(t, SYS_RET4(0, SYS_USER_NOTIFY, t->eid, t->tid), IPC_REQ);
+ finalize_rpc(t, notify, s);
+ t->notify_state = NOTIFY_RUNNING;
+ ret_userspace_fast();
+ unreachable();
+}
+
+/**
* Jump back to process where rpc came from, assuming such a thing exists.
+ * If we're queued for a notification, jump to it instead.
*
* @param t Thread to do return migration on.
* @param a Arguments to pass along.
@@ -150,27 +192,23 @@ static void leave_rpc(struct tcb *t, struct sys_ret a)
t->pid = ctx->pid;
t->eid = ctx->eid;
- if (is_rpc(t))
+ if (is_rpc(t)) {
use_vmem(t->rpc.vmem);
- else
+ return;
+ }
+
+ if (t->notify_state != NOTIFY_QUEUED) {
+ /* turn a potential NOTIFY_RUNNING into NOTIFY_WAITING */
+ t->notify_state = NOTIFY_WAITING;
use_vmem(t->proc.vmem);
-}
+ return;
+ }
-/**
- * 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);
+ notify(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;
+ /* we failed in notifying the thread, so just return back to the
+ * process normally */
+ use_vmem(t->proc.vmem);
}
/**
@@ -320,6 +358,16 @@ SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1,
leave_rpc(t, SYS_RET6(OK, t->pid, d0, d1, d2, d3));
}
+SYSCALL_DEFINE0(ipc_ghost)(struct tcb *t)
+{
+ if (unlikely(!is_rpc(t)))
+ return_args1(t, ERR_MISC);
+
+ /** @todo this should also enable interrupts when leaving kernel */
+ enable_irqs();
+ leave_rpc(t, get_args(t));
+}
+
/**
* Notify syscall handler.
*
@@ -330,6 +378,10 @@ SYSCALL_DEFINE4(ipc_resp)(struct tcb *t, sys_arg_t d0, sys_arg_t d1,
* @return \ref OK and 0.
*/
SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){
+ if (t->tid == tid) {
+ /** @todo notify self */
+ }
+
if (!has_cap(t->caps, CAP_CALL))
return_args1(t, ERR_PERM);
@@ -343,7 +395,8 @@ SYSCALL_DEFINE1(ipc_notify)(struct tcb *t, sys_arg_t tid){
}
r->notify_state = NOTIFY_QUEUED;
- if (running(r))
+ /* only interrupt if thread is in owning process */
+ if (running(r) && r->rid == r->pid)
send_ipi(r);
return_args1(t, OK);
diff --git a/src/uapi/irq.c b/src/uapi/irq.c
index 6687826..9bd8ec1 100644
--- a/src/uapi/irq.c
+++ b/src/uapi/irq.c
@@ -13,7 +13,6 @@
* 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.
*/
@@ -27,3 +26,16 @@ SYSCALL_DEFINE1(irq_req)(struct tcb *t, sys_arg_t id)
return_args1(t, register_irq(t, id));
}
+
+SYSCALL_DEFINE2(req_notification)(struct tcb *t, sys_arg_t tid, sys_arg_t pid)
+{
+ if (!has_cap(t->caps, CAP_NOTIFICATION))
+ return_args1(t, ERR_PERM);
+
+ struct tcb *r = get_tcb(tid);
+ if (!r)
+ return_args1(t, ERR_INVAL);
+
+ t->notify_id = pid;
+ return_args1(t, OK);
+}
diff --git a/src/uapi/proc.c b/src/uapi/proc.c
index e7fa49d..153b183 100644
--- a/src/uapi/proc.c
+++ b/src/uapi/proc.c
@@ -37,6 +37,7 @@ SYSCALL_DEFINE5(create)(struct tcb *t, sys_arg_t func,
set_args5(c, c->tid, d0, d1, d2, d3);
set_return(c, func);
+ c->notify_id = t->notify_id;
return_args2(t, OK, c->tid);
}
@@ -70,6 +71,7 @@ SYSCALL_DEFINE0(fork)(struct tcb *t)
* parent ID as third return value */
set_args3(n, OK, 0, get_eproc(t)->pid);
+ n->notify_id = c->notify_id;
return_args2(t, OK, n->pid);
}
@@ -132,6 +134,7 @@ SYSCALL_DEFINE2(spawn)(struct tcb *t, sys_arg_t bin, sys_arg_t interp)
if (!n)
return_args1(t, ERR_OOMEM);
+ n->notify_id = c->notify_id;
return_args2(t, prepare_proc(n, bin, interp), n->pid);
}