aboutsummaryrefslogtreecommitdiff
path: root/src/uapi
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-07-01 23:34:57 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-07-01 23:34:57 +0300
commit7ad9c01dad7b1b46eced8290b8b991383d648188 (patch)
treecd528648af552974b90117efef431659ef5f0cc6 /src/uapi
parent9ff67d879b4695e0c9910b7276f3959c005c7b19 (diff)
downloadkmi-7ad9c01dad7b1b46eced8290b8b991383d648188.tar.gz
kmi-7ad9c01dad7b1b46eced8290b8b991383d648188.zip
expand notifications into interrupt handlers
+ Terminology is still a bit poor, and will still have to write documentation + implement ipis properly
Diffstat (limited to 'src/uapi')
-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
4 files changed, 89 insertions, 19 deletions
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);
}