aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2022-11-09 16:27:23 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2022-11-09 17:27:11 +0200
commita3e45d5dcaf1bf3a9e684b5fcc301413ec994a9b (patch)
treeae319c8f389e7ca39bbdd4b114655f8604563305
parent2b5533aefef026fe7bada314ebdb2651b809979a (diff)
downloadkmi-a3e45d5dcaf1bf3a9e684b5fcc301413ec994a9b.tar.gz
kmi-a3e45d5dcaf1bf3a9e684b5fcc301413ec994a9b.zip
add basic IPI structure
-rw-r--r--arch/riscv64/kernel/cpu.c34
-rw-r--r--arch/riscv64/kernel/entry.S14
-rw-r--r--arch/riscv64/kernel/proc.c23
-rw-r--r--arch/riscv64/kernel/sbi.h20
-rw-r--r--common/dispatch.c12
-rw-r--r--common/ipi.c32
-rw-r--r--common/tcb.c16
-rw-r--r--common/uapi/dispatch.c9
-rw-r--r--common/uapi/ipc.c42
-rw-r--r--include/apos/ipi.h37
-rw-r--r--include/apos/tcb.h19
-rw-r--r--include/apos/uapi.h10
-rw-r--r--include/arch/cpu.h7
-rw-r--r--include/arch/proc.h21
14 files changed, 250 insertions, 46 deletions
diff --git a/arch/riscv64/kernel/cpu.c b/arch/riscv64/kernel/cpu.c
index d6d07ec..60140e6 100644
--- a/arch/riscv64/kernel/cpu.c
+++ b/arch/riscv64/kernel/cpu.c
@@ -11,6 +11,8 @@
#include <arch/cpu.h>
+#include "sbi.h"
+
/** Keeps track of initialized cpus. */
static atomic_long cpus = 0;
@@ -40,3 +42,35 @@ struct tcb *cur_tcb()
register struct tcb *t __asm__ ("tp");
return t;
}
+
+/**
+ * Helper for cpu_send_ipi() to convert linear \p cpu_id to SBI \c
+ * hart_mask_base.
+ *
+ * @param cpu_id CPU id to convert.
+ * @return Corresponding \c hart_mask_base.
+ */
+static long __cpu_offset(id_t cpu_id)
+{
+ return cpu_id / (sizeof(long) * 8);
+}
+
+/**
+ * Helper for cpu_send_ipi() to convert linear \p cpu_id to SBI \c
+ * hart_mask.
+ *
+ * @param cpu_id CPU id to convert.
+ * @param offset Offset from __cpu_offset().
+ * @return Corresponding \c hart_mask.
+ */
+static long __cpu_mask(id_t cpu_id, long offset)
+{
+ return cpu_id - offset * sizeof(long) * 8;
+}
+
+void cpu_send_ipi(id_t cpu_id)
+{
+ long offset = __cpu_offset(cpu_id);
+ long mask = __cpu_mask(cpu_id, offset);
+ sbi_send_ipi(mask, offset);
+}
diff --git a/arch/riscv64/kernel/entry.S b/arch/riscv64/kernel/entry.S
index db662bb..355cd3d 100644
--- a/arch/riscv64/kernel/entry.S
+++ b/arch/riscv64/kernel/entry.S
@@ -77,17 +77,14 @@ _save_context:
handle_exception:
li t0, EXC_SYSCALL
- /* system exceptions fall through, syscalls jump */
+ /* system exceptions fall through, syscalls and ipis jump */
/* temp, at some point we want to handle system exceptions as well */
- beq s4, t0, handle_syscall
+ beq s4, t0, handle_dispatch
j restore_all
-handle_syscall:
- /* add 4 (size of ecall) to EPC to avoid running the same instruction
- * twice */
- csrr s0, CSR_SEPC
- addi s0, s0, 4
+handle_dispatch:
/* store execution continuation point */
+ csrr s0, CSR_SEPC
sr s0, 0(tp)
/* allocate space for sys_ret structure on stack and shift argument
* registers down one to make room for the pointer to this structure */
@@ -99,7 +96,8 @@ handle_syscall:
mv a2, a1
mv a1, a0
mv a0, sp
- jal syscall_dispatch
+ /* jump to C */
+ jal dispatch
/* move structure from stack into registers. */
lr a0, offsetof_s(sp)
lr a1, offsetof_ar0(sp)
diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c
index ed8bf93..d2b8dfb 100644
--- a/arch/riscv64/kernel/proc.c
+++ b/arch/riscv64/kernel/proc.c
@@ -8,6 +8,7 @@
#include <apos/tcb.h>
#include <apos/elf.h>
+#include <apos/string.h>
#include <arch/proc.h>
@@ -54,3 +55,25 @@ void set_thread(struct tcb *t)
r->sp = (long)t->thread_stack_top;
r->tp = (long)t->thread_storage;
}
+
+void save_regs(struct tcb *t, void *p)
+{
+ struct riscv_regs *r = (struct riscv_regs *)(t++);
+ memcpy(p, r, sizeof(*r));
+}
+
+void load_regs(void *p, struct tcb *t)
+{
+ struct riscv_regs *r = (struct riscv_regs *)(t++);
+ memcpy(r, p, sizeof(*r));
+}
+
+void adjust_ipi(struct tcb *t)
+{
+ UNUSED(t);
+}
+
+void adjust_syscall(struct tcb *t)
+{
+ t->exec += 4;
+}
diff --git a/arch/riscv64/kernel/sbi.h b/arch/riscv64/kernel/sbi.h
index 2add35f..19cc595 100644
--- a/arch/riscv64/kernel/sbi.h
+++ b/arch/riscv64/kernel/sbi.h
@@ -106,4 +106,24 @@ static inline struct sbiret sbi_system_reset(uint32_t reset_type,
0);
}
+/** Supervisor IPI extension ID. */
+#define EID_sPI 0x735049
+
+/** Supervisor IPI function ID. */
+#define FID_IPI 0
+
+/**
+ * Send IPI.
+ *
+ * @param hart_mask Bitmap of harts to send IPI to.
+ * @param hart_mask_base Base of \p hart_mask.
+ * @return SBI call return. \see sbiret.
+ */
+static inline struct sbiret sbi_send_ipi(unsigned long hart_mask,
+ unsigned long hart_mask_base)
+{
+ return sbi_ecall(EID_sPI, FID_IPI, hart_mask, hart_mask_base, 0, 0, 0,
+ 0);
+}
+
#endif /* APOS_RISCV_SBI_H */
diff --git a/common/dispatch.c b/common/dispatch.c
new file mode 100644
index 0000000..1325d62
--- /dev/null
+++ b/common/dispatch.c
@@ -0,0 +1,12 @@
+#include <apos/uapi.h>
+#include <apos/ipi.h>
+
+struct sys_ret dispatch(sys_arg_t a, sys_arg_t b, sys_arg_t c,
+ sys_arg_t d, sys_arg_t e, sys_arg_t f)
+{
+ struct tcb *t = cur_tcb();
+ if (clear_ipi(t))
+ return handle_ipi(t);
+
+ return handle_syscall(t, a, b, c, d, e, f);
+}
diff --git a/common/ipi.c b/common/ipi.c
new file mode 100644
index 0000000..32f1432
--- /dev/null
+++ b/common/ipi.c
@@ -0,0 +1,32 @@
+#include <apos/ipi.h>
+#include <arch/cpu.h>
+
+#include <arch/proc.h>
+
+/**
+ * @file ipi.c
+ *
+ * IPI function implementations.
+ */
+
+bool clear_ipi(struct tcb *t)
+{
+ bool r = t->ipi;
+ t->ipi = false;
+ return r;
+}
+
+void send_ipi(struct tcb *t)
+{
+ t->ipi = true;
+ cpu_send_ipi(t->cpu_id);
+}
+
+struct sys_ret handle_ipi(struct tcb *t)
+{
+ adjust_ipi(t);
+
+ /** @todo use rpc stack */
+ set_return(t, t->callback);
+ return get_args(t);
+}
diff --git a/common/tcb.c b/common/tcb.c
index 9000941..417ca45 100644
--- a/common/tcb.c
+++ b/common/tcb.c
@@ -36,7 +36,7 @@ static struct tcb **tcbs;
* \todo If we ever support systems with massive amounts of cpus, this should probably
* be allocated at runtime.
*/
-static struct tcb *cpu_tcb[MAX_CPUS] = { 0 };
+static struct tcb *__cpu_tcb[MAX_CPUS] = { 0 };
void init_tcbs()
{
@@ -294,7 +294,12 @@ DEFINE_DETACH(detach_proc, proc);
/* weak to allow optimisation on risc-v, but provide fallback for future */
__weak struct tcb *cur_tcb()
{
- return cpu_tcb[cpu_id()];
+ return cpu_tcb(cpu_id());
+}
+
+struct tcb *cpu_tcb(id_t cpu_id)
+{
+ return __cpu_tcb[cpu_id];
}
struct tcb *cur_proc()
@@ -313,7 +318,7 @@ void use_tcb(struct tcb *t)
{
cpu_assign(t);
- cpu_tcb[t->cpu_id] = t;
+ __cpu_tcb[t->cpu_id] = t;
use_vmem(t->proc.vmem);
}
@@ -355,3 +360,8 @@ void set_return(struct tcb *t, vm_t v)
{
t->exec = v;
}
+
+bool running(struct tcb *t)
+{
+ return cpu_tcb(t->cpu_id) == t;
+}
diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c
index 27cc001..2cf19fb 100644
--- a/common/uapi/dispatch.c
+++ b/common/uapi/dispatch.c
@@ -10,6 +10,8 @@
#include <apos/debug.h>
#include <apos/uapi.h>
+#include <arch/proc.h>
+
/** Syscall number to syscall handler conversion. */
static const sys_t syscall_table[] = {
/* noop */
@@ -79,10 +81,11 @@ SYSCALL_DEFINE1(putch)(sys_arg_t a){
return SYS_RET1(OK);
}
-struct sys_ret syscall_dispatch(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 sys_ret handle_syscall(struct tcb *t,
+ 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 = cur_tcb();
+ adjust_syscall(t);
size_t sc = syscall;
if (sc >= ARRAY_SIZE(syscall_table)) {
diff --git a/common/uapi/ipc.c b/common/uapi/ipc.c
index 34f707a..cb53ee3 100644
--- a/common/uapi/ipc.c
+++ b/common/uapi/ipc.c
@@ -8,6 +8,7 @@
#include <apos/uapi.h>
#include <apos/tcb.h>
+#include <apos/ipi.h>
/**
* IPC server notification syscall handler.
@@ -114,36 +115,21 @@ SYSCALL_DEFINE4(ipc_resp)(sys_arg_t d0, sys_arg_t d1, sys_arg_t d2,
* \todo Implement.
*
* @param tid Thread ID to notify.
- * @param swap Whether to swap immediately if possible.
* @return \ref OK and 0.
*/
-SYSCALL_DEFINE2(ipc_notify)(sys_arg_t tid, sys_arg_t swap){
- /** \todo masquerade as kernel call, set from to 0 and set us as
- * notify type, no arguments as that would require too much state
- * handling for my liking. Instead, a server and a client have to agree
- * on some rpc API, and ipc_notify is just used to asynchronously inform
- * the client that it should check the status of its async operations.
- * Arguably slower than directly telling the client which operation was
- * finished, but this would require the kernel to keep track of a notify
- * stack. While not impossible, probably too complex. */
+SYSCALL_DEFINE1(ipc_notify)(sys_arg_t tid){
+ struct tcb *t = get_tcb(tid);
+ if (t->notify_state == NOTIFY_QUEUED)
+ return SYS_RET1(OK);
+
+ if (t->notify_state == NOTIFY_RUNNING) {
+ t->notify_state = NOTIFY_QUEUED;
+ return SYS_RET1(OK);
+ }
+
+ t->notify_state = NOTIFY_QUEUED;
+ if (running(t))
+ send_ipi(t);
- /* Something like
- *
- * struct tcb *t = get_tcb(tid);
- * if (t->notify_state == NOTIFY_QUEUED)
- * return;
- *
- * if (t->notify_state == NOTIFY_RUNNING) {
- * t->notify = NOTIFY_QUEUED;
- * return;
- * }
- *
- * t->notify_state = NOTIFY_QUEUED;
- * if (swap)
- * do_swap(); // clears t->notify when swapped to
- * // if already running in base state, interrupt,
- * otherwise wait for return from rpc. If not running,
- * just queue the interrupt.
- */
return SYS_RET1(OK);
}
diff --git a/include/apos/ipi.h b/include/apos/ipi.h
new file mode 100644
index 0000000..c895d58
--- /dev/null
+++ b/include/apos/ipi.h
@@ -0,0 +1,37 @@
+#ifndef APOS_IPI_H
+#define APOS_IPI_H
+
+/**
+ * @file ipi.h
+ *
+ * IPI function definitions.
+ */
+
+#include <apos/types.h>
+#include <apos/uapi.h>
+#include <apos/tcb.h>
+
+/**
+ * Clear potential IPI in \p t, and return its value.
+ *
+ * @param t \ref tcb to clear possible IPI status of.
+ * @return \ref true if \p was interrupted by IPI, \ref false otherwise.
+ */
+bool clear_ipi(struct tcb *t);
+
+/**
+ * Send IPI to \p t. Assumes \c running(t).
+ *
+ * @param t \ref tcb to send IPI to.
+ */
+void send_ipi(struct tcb *t);
+
+/**
+ * Handle IPI.
+ *
+ * @param t Thread who was interrupted by IPI.
+ * @return Possible arguments to IPI.
+ */
+struct sys_ret handle_ipi(struct tcb *t);
+
+#endif /* APOS_IPI_H */
diff --git a/include/apos/tcb.h b/include/apos/tcb.h
index b92cd10..0368957 100644
--- a/include/apos/tcb.h
+++ b/include/apos/tcb.h
@@ -146,6 +146,9 @@ struct tcb {
/** Notifcation state of thread. */
enum tcb_notify notify_state;
+
+ /** Whether thread has gotten an IPI */
+ bool ipi;
};
/**
@@ -266,6 +269,14 @@ stat_t detach_proc(struct tcb *r, struct tcb *t);
struct tcb *cur_tcb();
/**
+ * Get thread currently running on cpu \p cpu_id.
+ *
+ * @param cpu_id CPU whose currently running thread to get.
+ * @return \ref tcb running on cpu.
+ */
+struct tcb *cpu_tcb(id_t cpu_id);
+
+/**
* Get currently executing process.
*
* @return Effective process \ref tcb.
@@ -337,4 +348,12 @@ stat_t alloc_stacks(struct tcb *t);
*/
void set_return(struct tcb *t, vm_t r);
+/**
+ * Check whether \p t is currently running on some cpu.
+ *
+ * @param t \ref tcb to check.
+ * @return \c true if it is running, \c false otherwise.
+ */
+bool running(struct tcb *t);
+
#endif /* APOS_TCB_H */
diff --git a/include/apos/uapi.h b/include/apos/uapi.h
index 084c1fa..83de7eb 100644
--- a/include/apos/uapi.h
+++ b/include/apos/uapi.h
@@ -500,13 +500,13 @@ SYSCALL_DECLARE4(ipc_resp, d0, d1, d2, d3);
* Notify thread syscall.
*
* @param tid Thread ID to notify.
- * @param swap Whether to immediately swap.
+ * @param b Unused.
* @param c Unused.
* @param d Unused.
* @param e Unused.
* @return \ref OK and 0.
*/
-SYSCALL_DECLARE2(ipc_notify, tid, swap);
+SYSCALL_DECLARE1(ipc_notify, tid);
/** @} */
/** @name Process handling syscalls. */
@@ -683,6 +683,7 @@ SYSCALL_DECLARE1(poweroff, type);
/**
* Dispatch to correct syscall handler.
*
+ * @param t Thread to do syscall on.
* @param syscall Syscall number.
* @param a Syscall argument 0.
* @param b Syscall argument 1.
@@ -691,8 +692,9 @@ SYSCALL_DECLARE1(poweroff, type);
* @param e Syscall argument 4.
* @return Whatever the specified syscall returns.
*/
-struct sys_ret syscall_dispatch(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 sys_ret handle_syscall(struct tcb *t,
+ sys_arg_t syscall, sys_arg_t a, sys_arg_t b,
+ sys_arg_t c, sys_arg_t d, sys_arg_t e);
/** \todo Should I add variable names as well, to make the documentation a bit
* more readable? */
diff --git a/include/arch/cpu.h b/include/arch/cpu.h
index 66d5d45..c5a83d5 100644
--- a/include/arch/cpu.h
+++ b/include/arch/cpu.h
@@ -36,4 +36,11 @@ id_t cpu_id();
*/
void cpu_assign(struct tcb *t);
+/**
+ * Send inter-processor interrupt to cpu \p cpu_id.
+ *
+ * @param cpu_id CPU to send ipi to.
+ */
+void cpu_send_ipi(id_t cpu_id);
+
#endif /* APOS_CPU_H */
diff --git a/include/arch/proc.h b/include/arch/proc.h
index 5047eab..d01674d 100644
--- a/include/arch/proc.h
+++ b/include/arch/proc.h
@@ -49,6 +49,27 @@ struct sys_ret get_args(struct tcb *t);
void set_thread(struct tcb *t);
/**
+ * Copy registers from tcb save area to address \p p.
+ * Intended to be used for copying thread state to rpc stack.
+ *
+ * @param t Thread whose registers to save.
+ * @param p Address to save to.
+ */
+void save_regs(struct tcb *t, void *p);
+
+/**
+ * Copy registers from address \p p to tcb save registers.
+ * Intended to be used for copying thread state from rpc stack.
+ *
+ * @param p Address to load from.
+ * @param t Thread whose registers to load.
+ */
+void load_regs(void *p, struct tcb *t);
+
+void adjust_ipi(struct tcb *t);
+void adjust_syscall(struct tcb *t);
+
+/**
* Run \c init program.
*
* @param t Thread that \c init is attached to.