diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-10-29 21:17:31 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-10-29 21:17:31 +0200 |
| commit | 5976ad390a15726c3ddfacf8c8b282c8350f9554 (patch) | |
| tree | 24a55fcd7e6f28d048ac074da59f428b54a81cb0 | |
| parent | 314bca3dc19a864c76153bfcd5a58be8c40000f9 (diff) | |
| download | kmi-5976ad390a15726c3ddfacf8c8b282c8350f9554.tar.gz kmi-5976ad390a15726c3ddfacf8c8b282c8350f9554.zip | |
start moving towards threads always being in rpc
| -rw-r--r-- | arch/riscv64/kernel/entry.S | 4 | ||||
| -rw-r--r-- | arch/riscv64/kernel/proc.c | 17 | ||||
| -rw-r--r-- | arch/riscv64/kernel/vmem.c | 11 | ||||
| -rw-r--r-- | docs/visionfive2.md | 2 | ||||
| -rw-r--r-- | include/arch/vmem.h | 2 | ||||
| -rw-r--r-- | include/kmi/bkl.h | 2 | ||||
| -rw-r--r-- | include/kmi/tcb.h | 21 | ||||
| -rw-r--r-- | src/bkl.c | 5 | ||||
| -rw-r--r-- | src/elf.c | 4 | ||||
| -rw-r--r-- | src/main.c | 1 | ||||
| -rw-r--r-- | src/orphanage.c | 4 | ||||
| -rw-r--r-- | src/panic.c | 20 | ||||
| -rw-r--r-- | src/tcb.c | 35 | ||||
| -rw-r--r-- | src/uapi/conf.c | 8 | ||||
| -rw-r--r-- | src/uapi/ipc.c | 37 |
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. * @@ -12,6 +12,11 @@ /** The Big Kernel Lock. */ static spinlock_t bkl = 0; +void bkl_init() +{ + bkl = 0; +} + void bkl_lock() { spin_lock(&bkl); @@ -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); } /** @@ -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"); @@ -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(); |
