aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/riscv64/kernel/entry.S4
-rw-r--r--arch/riscv64/kernel/proc.c17
-rw-r--r--arch/riscv64/kernel/vmem.c11
-rw-r--r--docs/visionfive2.md2
-rw-r--r--include/arch/vmem.h2
-rw-r--r--include/kmi/bkl.h2
-rw-r--r--include/kmi/tcb.h21
-rw-r--r--src/bkl.c5
-rw-r--r--src/elf.c4
-rw-r--r--src/main.c1
-rw-r--r--src/orphanage.c4
-rw-r--r--src/panic.c20
-rw-r--r--src/tcb.c35
-rw-r--r--src/uapi/conf.c8
-rw-r--r--src/uapi/ipc.c37
15 files changed, 86 insertions, 87 deletions
diff --git a/arch/riscv64/kernel/entry.S b/arch/riscv64/kernel/entry.S
index abf3cba..0bc999e 100644
--- a/arch/riscv64/kernel/entry.S
+++ b/arch/riscv64/kernel/entry.S
@@ -107,10 +107,8 @@ handle_exception:
csrr a0, CSR_SEPC
csrr a1, CSR_STVAL
- /* not really a kernel panic but used for now to signify that something
- * happened in userspace that we can't deal with */
csrr a2, CSR_SCAUSE
- call kernel_panic
+ call unhandled_panic
j _load_context
diff --git a/arch/riscv64/kernel/proc.c b/arch/riscv64/kernel/proc.c
index d3896c1..f012b20 100644
--- a/arch/riscv64/kernel/proc.c
+++ b/arch/riscv64/kernel/proc.c
@@ -42,15 +42,14 @@ void run_init(struct tcb *t, vm_t fdt, vm_t initrd)
{
csr_write(CSR_SSCRATCH, t);
csr_write(CSR_SEPC, t->callback);
- /* gcc gives a warning 'the value of the stack pointer after an asm
- * statement must be the same as it was before the statement', so this
- * is technically speaking undefined behavior, I think.
- *
- * Could be fixed with a separate pure asm run_init, but I guess this
- * works for now.
- */
- vm_t stack_top = t->thread_stack + t->thread_stack_size;
- info("jumping to %lx\n", (long)t->callback);
+
+ /* reference main virtual memory */
+ struct tcb *r = get_rproc(t);
+ clone_uvmem(r->proc.vmem, t->rpc.vmem);
+ flush_tlb_all();
+
+ vm_t stack_top = t->rpc_stack - BASE_PAGE_SIZE;
+ info("jumping to %lx with sp = %lx\n", (long)t->callback, stack_top);
bkl_unlock();
riscv_run_init(0, t->tid, SYS_USER_SPAWNED, fdt, initrd, 1, stack_top);
diff --git a/arch/riscv64/kernel/vmem.c b/arch/riscv64/kernel/vmem.c
index 29ec3d5..cf1391e 100644
--- a/arch/riscv64/kernel/vmem.c
+++ b/arch/riscv64/kernel/vmem.c
@@ -538,7 +538,7 @@ vm_t setup_kernel_io(struct vmem *b, vm_t paddr)
}
#endif
-void clone_uvmem(struct vmem * restrict r, struct vmem * restrict b)
+void clone_uvmem(struct vmem *r, struct vmem *b)
{
size_t i = 0;
for (; i < CSTACK_PAGE; ++i) {
@@ -574,20 +574,11 @@ stat_t setup_rpc_stack(struct tcb *t)
if (!page)
return ERR_OOMEM;
- /* map both into rpc and proc spaces so we can write to the
- * current stack frame directly. Especially important when
- * returning from an rpc. Technically means that we could leak
- * memory if map_vpage() for proc.vmem allocates more and more
- * pages, but good enough for now. */
if (map_vpage(t->rpc.vmem, page,
RPC_STACK_BASE + BASE_PAGE_SIZE * i,
flags, BASE_PAGE))
return ERR_OOMEM;
- if (map_vpage(t->proc.vmem, page,
- RPC_STACK_BASE + BASE_PAGE_SIZE * i,
- flags, BASE_PAGE))
- return ERR_OOMEM;
}
/* we allocated a second order page for rpc stack usage */
diff --git a/docs/visionfive2.md b/docs/visionfive2.md
index 71f8a7e..ede887f 100644
--- a/docs/visionfive2.md
+++ b/docs/visionfive2.md
@@ -14,7 +14,7 @@ serial and ethernet booting, but I haven't looked into how they work.
2. Create three partitions on an SD card of your choice:
```
-sudo sgdisk --clean \
+sudo sgdisk \
--new=1:4096:8191 --change-name=1:"spl" --typecode=1:2E54B353-1271-4842-806F-E436D6AF6985 \
--new=2:8192:16383 --change-name=2:"uboot" --typecode=2:5B193300-FC78-40CD-8002-E86C45580B47 \
--new=3:16384:0 --change-name=3:"data" \
diff --git a/include/arch/vmem.h b/include/arch/vmem.h
index 1674e95..79c42b9 100644
--- a/include/arch/vmem.h
+++ b/include/arch/vmem.h
@@ -179,7 +179,7 @@ void destroy_vmem(struct vmem *b);
* @param r Source virtual memory of clone.
* @param b Destination virtual memory of clone.
*/
-void clone_uvmem(struct vmem * restrict r, struct vmem * restrict b);
+void clone_uvmem(struct vmem *r, struct vmem *b);
/**
* Jump into kernelspace from a physical address space.
diff --git a/include/kmi/bkl.h b/include/kmi/bkl.h
index 39e3ef9..8a56061 100644
--- a/include/kmi/bkl.h
+++ b/include/kmi/bkl.h
@@ -12,6 +12,8 @@
#include <kmi/lock.h>
+void bkl_init();
+
/** Lock the Big Kernel Lock. */
void bkl_lock();
diff --git a/include/kmi/tcb.h b/include/kmi/tcb.h
index d61845f..b12ad7e 100644
--- a/include/kmi/tcb.h
+++ b/include/kmi/tcb.h
@@ -22,6 +22,27 @@ struct tcb;
#include <arch/tcb.h>
+/** Structure for maintaining the required context data for an rpc call. */
+struct call_ctx {
+ /** Execution continuation point. */
+ vm_t exec;
+
+ /** Position in rpc stack. */
+ vm_t rpc_stack;
+
+ /** Effective process ID. */
+ id_t eid;
+
+ /** Current process ID. */
+ id_t pid;
+
+ /** If this frame was due to a notification, which means leaving the
+ * frame must restore registers as they were */
+ bool notify;
+
+ /* register save area follows this in the stack */
+};
+
/**
* Check if thread is process thread.
*
diff --git a/src/bkl.c b/src/bkl.c
index 6ee58f4..e831451 100644
--- a/src/bkl.c
+++ b/src/bkl.c
@@ -12,6 +12,11 @@
/** The Big Kernel Lock. */
static spinlock_t bkl = 0;
+void bkl_init()
+{
+ bkl = 0;
+}
+
void bkl_lock()
{
spin_lock(&bkl);
diff --git a/src/elf.c b/src/elf.c
index 29c9c09..259c77e 100644
--- a/src/elf.c
+++ b/src/elf.c
@@ -47,6 +47,8 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart,
size_t phnum, size_t phsize)
{
assert(t && is_proc(t));
+ /* temporarily visit process virtual memory */
+ use_vmem(t->proc.vmem);
/** \todo take alignment into consideration? */
/** \todo take overlapping memory regions into account, probably mostly
@@ -91,6 +93,8 @@ static void __map_exec(struct tcb *t, vm_t bin, uint8_t ei_c, vm_t phstart,
mod_vpage(t->b_r, va, paddr, uvflags);
*/
}
+
+ use_vmem(t->rpc.vmem);
}
/**
diff --git a/src/main.c b/src/main.c
index 12d8514..171d1d1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -86,6 +86,7 @@ __noreturn void kernel(void *fdt, uintptr_t load_addr, struct vmem *d)
init_proc(fdt, &proc_fdt, &proc_initrd);
/* lock kernel since we're about to start other threads as well */
+ bkl_init();
bkl_lock();
/* try to bring up other cores on system */
smp_bringup(d, fdt);
diff --git a/src/orphanage.c b/src/orphanage.c
index 797468d..6de520f 100644
--- a/src/orphanage.c
+++ b/src/orphanage.c
@@ -39,8 +39,8 @@ void unorphanize(struct tcb *t)
t->pid = 1;
t->eid = 1;
- t->proc = init->proc;
- use_vmem(t->proc.vmem);
+ clone_uvmem(init->proc.vmem, t->rpc.vmem);
+ use_vmem(t->rpc.vmem);
alloc_stack(t);
assert(init->callback);
diff --git a/src/panic.c b/src/panic.c
index 5495ebe..34bfa69 100644
--- a/src/panic.c
+++ b/src/panic.c
@@ -9,12 +9,28 @@
#include <kmi/syscalls.h>
#include <kmi/power.h>
#include <kmi/debug.h>
+#include <kmi/tcb.h>
void kernel_panic(void *pc, void *addr, long cause)
{
/* could be useful to print out register values as well? */
- error("kernel paniced at pc: %p with address %p and cause %lx\n",
- pc, addr, cause);
+ error("thread %d kernel paniced at pc: %p with address %p and cause %lx\n",
+ cur_tcb()->cpu_id, pc, addr, cause);
+
+ info("attempting to reboot\n");
+
+ poweroff(SYS_COLD_REBOOT);
+
+ /* spin if poweroff failed for some reason */
+ error("reboot failed, spinning in place\n");
+ while (1);
+}
+
+void unhandled_panic(void *pc, void *addr, long cause)
+{
+ /* could be useful to print out register values as well? */
+ error("thread %d unhandled panic at pc: %p with address %p and cause %lx\n",
+ cur_tcb()->cpu_id, pc, addr, cause);
info("attempting to reboot\n");
diff --git a/src/tcb.c b/src/tcb.c
index 70cad5a..eebaaa4 100644
--- a/src/tcb.c
+++ b/src/tcb.c
@@ -90,38 +90,22 @@ static id_t __alloc_tid(struct tcb *t)
return ERR_NF;
}
-/**
- * Setup thread stack.
- *
- * @param t Thread to setup stack for.
- * @param bytes Minimum size of stack.
- * @return Base of allocated stack.
- */
-static vm_t __setup_thread_stack(struct tcb *t, size_t bytes)
-{
- return alloc_uvmem(t, bytes, VM_V | VM_R | VM_W | VM_U);
-}
-
stat_t alloc_stack(struct tcb *t)
{
/* get parent process */
struct tcb *p = get_tcb(t->eid);
assert(p);
- t->thread_stack = __setup_thread_stack(p, thread_stack_size());
- if (!t->thread_stack)
+ if (setup_rpc_stack(t))
return ERR_OOMEM;
- /** \todo this only allows for a global stack size, what if a user wants
- * per thread stack sizes? I guess allocate them yourself in userspace
- * or something? */
- t->thread_stack_size = thread_stack_size();
+ t->regs = t->rpc_stack - sizeof(struct call_ctx);
return OK;
}
void free_stack(struct tcb *t)
{
- free_uvmem(get_proc(t), t->thread_stack);
+ destroy_rpc_stack(t);
}
static stat_t __init_free_thread(struct tcb *t)
@@ -158,10 +142,9 @@ static stat_t __init_owned_thread(struct tcb *p, struct tcb *t)
t->eid = p->rid;
t->pid = p->rid;
t->rid = p->rid;
- /** @todo I'm assuming two threads can share the same vmem
- * structure, this works on riscv but in the event that other
- * systems don't we can easily turn this into a clone_uvmem. */
- t->proc.vmem = p->proc.vmem;
+
+ /* someone else owns our vmem */
+ t->proc.vmem = NULL;
t->callback = p->callback;
if (!(t->rpc.vmem = create_vmem()))
@@ -207,7 +190,9 @@ struct tcb *create_thread(struct tcb *p)
}
- t->regs = (vm_t)t;
+ struct tcb *parent = get_rproc(t);
+ clone_uvmem(parent->proc.vmem, t->rpc.vmem);
+
reference_thread(t);
set_canary(t);
return t;
@@ -370,7 +355,7 @@ void use_tcb(struct tcb *t)
__cpu_tcb[t->cpu_id] = t;
- use_vmem(t->proc.vmem);
+ use_vmem(t->rpc.vmem);
}
struct tcb *get_tcb(id_t tid)
diff --git a/src/uapi/conf.c b/src/uapi/conf.c
index 24a4706..6706a8a 100644
--- a/src/uapi/conf.c
+++ b/src/uapi/conf.c
@@ -12,6 +12,7 @@
#include <kmi/sizes.h>
#include <kmi/uapi.h>
#include <kmi/conf.h>
+#include <kmi/bkl.h>
#include <arch/irq.h>
#include <arch/proc.h>
@@ -160,5 +161,10 @@ SYSCALL_DEFINE0(sleep)(struct tcb *t)
/* presumably we want to wake up on an interrupt */
enable_irqs();
- return_args1(t, sleep());
+
+ bkl_unlock();
+ stat_t r = sleep();
+ bkl_lock();
+
+ return_args1(t, r);
}
diff --git a/src/uapi/ipc.c b/src/uapi/ipc.c
index 5f2aad1..f1db76f 100644
--- a/src/uapi/ipc.c
+++ b/src/uapi/ipc.c
@@ -15,28 +15,6 @@
#include <kmi/irq.h>
#include <kmi/conf.h>
-/** Structure for maintaining the required context data for an rpc call. */
-struct call_ctx {
- /** Execution continuation point. */
- vm_t exec;
-
- /** Register save area. */
- vm_t regs;
-
- /** Position in rpc stack. */
- vm_t rpc_stack;
-
- /** Effective process ID. */
- id_t eid;
-
- /** Current process ID. */
- id_t pid;
-
- /** If this frame was due to a notification, which means leaving the
- * frame must restore registers as they were */
- bool notify;
-};
-
/**
* Represents difference between where rpc stack was before rpc call and during.
* Used to figure out which areas should be marked inaccessible.
@@ -76,7 +54,6 @@ static inline void finalize_rpc(struct tcb *t, struct tcb *r, vm_t s)
/* make sure updates are visible when swapping to the new virtual memory */
mark_rpc_invalid(t, s);
- use_vmem(t->rpc.vmem);
}
/**
@@ -93,11 +70,10 @@ static inline vm_t enter_rpc(struct tcb *t, struct sys_ret a,
enum ipc_flags flags)
{
/* reuse current rpc stack location if we're being kicked */
- vm_t rpc_stack = (is_set(flags, IPC_TAIL) &&
- is_rpc(t)) ? t->rpc_stack : rpc_position(t);
+ vm_t rpc_stack = (is_set(flags, IPC_TAIL) && is_rpc(t))
+ ? t->rpc_stack : rpc_position(t);
struct call_ctx *ctx = (struct call_ctx *)(rpc_stack) - 1;
- ctx->regs = t->regs;
t->regs = (vm_t)ctx;
/* try to get rid of args as fast as possible to free up registers for
@@ -242,8 +218,8 @@ 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;
+ t->regs = (vm_t)ctx;
- t->regs = ctx->regs;
/* again, get rid of args as fast as possible */
if (!ctx->notify)
set_ret(t, 6, a);
@@ -259,7 +235,7 @@ static void leave_rpc(struct tcb *t, struct sys_ret a)
rpc_stack = ctx->rpc_stack + BASE_PAGE_SIZE;
ctx = (struct call_ctx *)(rpc_stack) - 1;
- t->regs = ctx->regs;
+ t->regs = (vm_t)ctx;
r = get_tcb(ctx->pid);
/* equivalent to return_args1 but without returning so we can
@@ -283,11 +259,6 @@ static void leave_rpc(struct tcb *t, struct sys_ret a)
if (t->notify_flags)
notify(t, 0);
- if (is_rpc(t))
- use_vmem(t->rpc.vmem);
- else
- use_vmem(t->proc.vmem);
-
if (!ctx->notify) {
bkl_unlock();
ret_userspace_partial();