aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xarch/riscv64/conf/initbin4128 -> 3832 bytes
-rw-r--r--arch/riscv64/conf/initrdbin4608 -> 4096 bytes
-rw-r--r--common/uapi/dispatch.c1
-rw-r--r--common/uapi/ipc.c60
-rw-r--r--include/kmi/syscalls.h3
-rw-r--r--include/kmi/uapi.h24
6 files changed, 79 insertions, 9 deletions
diff --git a/arch/riscv64/conf/init b/arch/riscv64/conf/init
index c372029..6e28b9b 100755
--- a/arch/riscv64/conf/init
+++ b/arch/riscv64/conf/init
Binary files differ
diff --git a/arch/riscv64/conf/initrd b/arch/riscv64/conf/initrd
index a489f3a..eaefce2 100644
--- a/arch/riscv64/conf/initrd
+++ b/arch/riscv64/conf/initrd
Binary files differ
diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c
index 8ffbf54..d071db3 100644
--- a/common/uapi/dispatch.c
+++ b/common/uapi/dispatch.c
@@ -61,6 +61,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
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;
diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c
index 74b5732..c2548e9 100644
--- a/common/uapi/ipc.c
+++ b/common/uapi/ipc.c
@@ -64,6 +64,9 @@ struct call_ctx {
/** Current process ID. */
id_t pid;
+
+ /** Whether this context should be skipped when responding. */
+ bool kick;
};
/**
@@ -77,6 +80,11 @@ struct stack_diff {
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.
@@ -104,9 +112,11 @@ static void finalize_rpc(struct tcb *t, struct tcb *r, struct stack_diff sd)
*
* @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 struct stack_diff enter_rpc(struct tcb *t, struct sys_ret a)
+static struct stack_diff enter_rpc(struct tcb *t, struct sys_ret a,
+ enum ipc_kind kind)
{
vm_t rpc_stack = t->rpc_stack;
if (is_rpc(t))
@@ -131,6 +141,9 @@ static struct stack_diff enter_rpc(struct tcb *t, struct sys_ret a)
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(). */
@@ -162,6 +175,14 @@ 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;
+ }
+
t->regs = ctx->regs;
/* again, get rid of args as fast as possible */
set_args(t, a);
@@ -169,7 +190,7 @@ static void leave_rpc(struct tcb *t, struct sys_ret a)
set_return(t, ctx->exec);
/* if we're returning from a failed rpc, this should essentially be a
* no-op */
- mark_rpc_accessible(t, t->rpc_stack, ctx->rpc_stack);
+ mark_rpc_accessible(t, t->rpc_stack, top);
t->rpc_stack = ctx->rpc_stack;
t->pid = ctx->pid;
t->eid = ctx->eid;
@@ -221,12 +242,15 @@ SYSCALL_DEFINE1(ipc_server)(struct tcb *t, sys_arg_t callback)
* @param d1 IPC argument 1.
* @param d2 IPC argument 2.
* @param d3 IPC argument 3.
- * @param fwd Whether to forward.
+ * @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,
@@ -234,13 +258,13 @@ static void do_ipc(struct tcb *t,
sys_arg_t d1,
sys_arg_t d2,
sys_arg_t d3,
- bool fwd)
+ enum ipc_kind kind)
{
if (unlikely(!enough_rpc_stack(t)))
return_args(t, SYS_RET1(ERR_OOMEM));
struct stack_diff sd =
- enter_rpc(t, SYS_RET6(OK, t->eid, d0, d1, d2, d3));
+ enter_rpc(t, SYS_RET6(OK, t->eid, d0, d1, d2, d3), kind);
struct tcb *r = get_tcb(pid);
if (unlikely(!r)) {
@@ -255,7 +279,7 @@ static void do_ipc(struct tcb *t,
return;
}
- if (!fwd)
+ if (kind != IPC_REQ)
t->eid = t->pid;
finalize_rpc(t, r, sd);
@@ -275,7 +299,7 @@ static void do_ipc(struct tcb *t,
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, false);
+ do_ipc(t, pid, d0, d1, d2, d3, IPC_REQ);
}
/**
@@ -287,12 +311,30 @@ SYSCALL_DEFINE5(ipc_req)(struct tcb *t, sys_arg_t pid,
* @param d1 IPC argument 1.
* @param d2 IPC argument 2.
* @param d3 IPC argument 3.
- * @return
+ * @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, true);
+ 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);
}
/**
diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h
index bb7891b..8ca6546 100644
--- a/include/kmi/syscalls.h
+++ b/include/kmi/syscalls.h
@@ -83,6 +83,9 @@ enum {
/** Forward IPC request from client. */
SYS_IPC_FWD,
+ /** Kick request handling to someone else. */
+ SYS_IPC_KICK,
+
/** IPC response from server. */
SYS_IPC_RESP,
diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h
index ad4369f..526738a 100644
--- a/include/kmi/uapi.h
+++ b/include/kmi/uapi.h
@@ -552,6 +552,30 @@ SYSCALL_DECLARE5(ipc_req, pid, d0, d1, d2, d3);
SYSCALL_DECLARE5(ipc_fwd, pid, d0, d1, d2, d3);
/**
+ * Kicking syscall.
+ * Kicks the handling of an IPC req/fwd to someone else, jumping over the
+ * current process at ipc_resp().
+ *
+ * I'm imagining that this is useful in cases where an init process connects a
+ * client to another server, and kicks the actual request handling to the
+ * server. Note that ipc_resp() returning the ID of the process that handled a
+ * request is useful in case the client and server should continue communicating
+ * with eachother instead of going through init every time.
+ *
+ * Otherwise identical to ipc_fwd().
+ *
+ * @param t Current tcb.
+ * @param pid Process to kick req/fwd to.
+ * @param d0 First argument.
+ * @param d1 Second argument.
+ * @param d2 Third argument.
+ * @param d3 Fourth argument.
+ *
+ * Doesn't return.
+ */
+SYSCALL_DECLARE5(ipc_kick, pid, d0, d1, d2, d3);
+
+/**
* Response syscall.
*
* @param t Current tcb.