diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-07-31 22:24:29 +0300 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2023-07-31 22:24:29 +0300 |
| commit | 6ad1b899ed93f8bc110cdec7a722c8740f9f8d66 (patch) | |
| tree | 99fe36028ffc4583c59e77d03bea2ade7a6c5ace | |
| parent | 3212707a9ab549119ad0ad6441a07fe774c99f3b (diff) | |
| download | kmi-6ad1b899ed93f8bc110cdec7a722c8740f9f8d66.tar.gz kmi-6ad1b899ed93f8bc110cdec7a722c8740f9f8d66.zip | |
start working on irqs
| -rw-r--r-- | TODO | 1 | ||||
| -rw-r--r-- | arch/riscv64/kernel/entry.S | 22 | ||||
| -rw-r--r-- | arch/riscv64/kernel/irq.c | 66 | ||||
| -rw-r--r-- | common/ipi.c | 4 | ||||
| -rw-r--r-- | common/irq.c | 66 | ||||
| -rw-r--r-- | common/main.c | 2 | ||||
| -rw-r--r-- | common/panic.c | 24 | ||||
| -rw-r--r-- | common/timer.c | 2 | ||||
| -rw-r--r-- | common/uapi/dispatch.c | 1 | ||||
| -rw-r--r-- | common/uapi/irq.c | 28 | ||||
| -rw-r--r-- | common/uapi/proc.c | 1 | ||||
| -rw-r--r-- | include/arch/cpu.h | 6 | ||||
| -rw-r--r-- | include/arch/irq.h | 43 | ||||
| -rw-r--r-- | include/arch/proc.h | 2 | ||||
| -rw-r--r-- | include/kmi/caps.h | 3 | ||||
| -rw-r--r-- | include/kmi/ipi.h | 9 | ||||
| -rw-r--r-- | include/kmi/irq.h | 42 | ||||
| -rw-r--r-- | include/kmi/panic.h | 22 | ||||
| -rw-r--r-- | include/kmi/syscalls.h | 4 | ||||
| -rw-r--r-- | include/kmi/timer.h | 2 | ||||
| -rw-r--r-- | include/kmi/uapi.h | 134 |
21 files changed, 442 insertions, 42 deletions
@@ -51,6 +51,7 @@ associated program. Easy. (started) + Start working on proper context swaps and RPC swaps. (which thread ID should be visible from cur_tcb() when in an RPC? should I use some kind of effective tid instead of cur_tcb()?) ++ Export VM flags to userspace, separate header or something? !!! FUTURE: + Cache locality? diff --git a/arch/riscv64/kernel/entry.S b/arch/riscv64/kernel/entry.S index 9d4d951..698dae7 100644 --- a/arch/riscv64/kernel/entry.S +++ b/arch/riscv64/kernel/entry.S @@ -62,15 +62,18 @@ sr t4, offsetof_t4(sp) .endm -.global handle_irq -handle_irq: +.global handle_trap +handle_trap: csrrw tp, CSR_SSCRATCH, tp - bnez tp, continue_irq - /* the exception came from the kernel, should probably handle but for - * now just spin in place */ - 1: j 1b + bnez tp, continue_trap + /* the trap came from the kernel, should never happen so just panic + * and abort or whatever */ + csrr a0, CSR_SEPC + csrr a1, CSR_STVAL + csrr a2, CSR_SCAUSE + call kernel_panic -continue_irq: +continue_trap: sr sp, offsetof_tcbd(tp) lr sp, offsetof_regs(tp) addi sp, sp, -sizeof_registers @@ -88,12 +91,15 @@ continue_irq: /* load supervisor cause */ csrr t5, CSR_SCAUSE /* interrupts fall through, exceptions jump */ + /* (leading 1 means the value is interpreted as negative) */ bge t5, zero, handle_exception save_regs save_args - /* TODO: handle interrupts */ + mv t5, a0 + call riscv_handle_interrupt + j _load_context handle_exception: diff --git a/arch/riscv64/kernel/irq.c b/arch/riscv64/kernel/irq.c index 698a834..964401f 100644 --- a/arch/riscv64/kernel/irq.c +++ b/arch/riscv64/kernel/irq.c @@ -8,34 +8,78 @@ #include <kmi/attrs.h> #include <kmi/debug.h> -#include <arch/irq.h> +#include <kmi/timer.h> +#include <kmi/ipi.h> +#include <kmi/irq.h> #include "csr.h" /** Defined in arch/riscv64/kernel/entry.S. */ -extern void handle_irq(); +extern void handle_trap(); -/** Called from arch/riscv64/kernel/entry.S. */ -void handle_sys_irq() -{ -} - -void init_irq(void *fdt) +void setup_irq(void *fdt) { UNUSED(fdt); - csr_write(CSR_STVEC, &handle_irq); + csr_write(CSR_STVEC, &handle_trap); long s = 0; csr_read(CSR_SIE, s); info("CSR_SIE: %lx\n", s); } +stat_t activate_irq(irq_t id) +{ + /** @todo implement plic */ + return OK; +} + +stat_t deactivate_irq(irq_t id) +{ + /** @todo implement plic */ + return OK; +} + /* very simple for now */ -void enable_irq() +void enable_irqs() { csr_set(CSR_SSTATUS, CSR_SIE); } -void disable_irq() +void disable_irqs() { csr_clear(CSR_SSTATUS, CSR_SIE); } + +irq_t get_irq() +{ + /** @todo implement */ + return 0; +} + +/** + * Prints out a bug message about unknown interrupt cause. + * + * @param id ID of interrupt. + */ +static void riscv_unknown_interrupt(long id) +{ + bug("unknown interrupt: %llu\n", (unsigned long long)id); +} + +/** + * Handle RISCV interrupt. + * Branches out to correct interrupt handler. + * + * @param id ID of interrupt, with interrupt bit still set. + */ +void riscv_handle_interrupt(long id) +{ + id = -id; + + switch (id) { + /* I think */ + case 1: handle_ipi(); break; + case 5: handle_timer(); break; + case 9: handle_irq(); break; + default: riscv_unknown_interrupt(id); break; + } +} diff --git a/common/ipi.c b/common/ipi.c index a5435a3..59f9fd1 100644 --- a/common/ipi.c +++ b/common/ipi.c @@ -25,11 +25,11 @@ void send_ipi(struct tcb *t) cpu_send_ipi(t->cpu_id); } -struct sys_ret handle_ipi(struct tcb *t) +void handle_ipi() { + struct tcb *t = cur_tcb(); adjust_ipi(t); /** @todo use rpc stack */ set_return(t, t->callback); - return get_args(t); } diff --git a/common/irq.c b/common/irq.c new file mode 100644 index 0000000..9c538a2 --- /dev/null +++ b/common/irq.c @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ + +/** + * @file irq.c + * Common IRQ handling stuff implementations. + */ + +#include <kmi/irq.h> +#include <kmi/pmem.h> +#include <kmi/debug.h> +#include <kmi/assert.h> +#include <kmi/string.h> +#include <arch/irq.h> + +/** Hold maximum IRQ id supported by system. */ +static size_t max_irq; + +/** Hold map of IRD ID -> thread id. @todo process id? */ +static id_t *irq_map; + +void init_irq(void *fdt) +{ + /** @todo check arch max irq and adjust accordingly */ + irq_map = (id_t *)alloc_page(MM_O0); + memset(irq_map, 0, order_size(MM_O0)); + max_irq = order_size(MM_O0) / sizeof(irq_map[0]); + + setup_irq(fdt); +} + +stat_t register_irq(struct tcb *t, irq_t id) +{ + if (id >= max_irq) + return ERR_INVAL; + + if (irq_map[id]) + return ERR_EXT; + + irq_map[id] = t->tid; + return activate_irq(id); +} + +stat_t unregister_irq(struct tcb *t, irq_t id) +{ + id_t tid = irq_map[id]; + if (tid != t->tid) + return ERR_PERM; + + irq_map[id] = 0; + return deactivate_irq(id); +} + +void handle_irq() +{ + irq_t id = get_irq(); + hard_assert(id < max_irq, RETURN_VOID); + + id_t tid = irq_map[id]; + + if (!tid) { + bug("unregistered irq: %llu\n", (unsigned long long)id); + return; + } + + /** @todo switch to thread */ +} diff --git a/common/main.c b/common/main.c index 9eb6414..30d9ed5 100644 --- a/common/main.c +++ b/common/main.c @@ -12,9 +12,9 @@ #include <kmi/proc.h> #include <kmi/debug.h> #include <kmi/vmem.h> +#include <kmi/irq.h> #include <arch/arch.h> #include <arch/proc.h> -#include <arch/irq.h> #include <libfdt.h> /** diff --git a/common/panic.c b/common/panic.c new file mode 100644 index 0000000..c2b6948 --- /dev/null +++ b/common/panic.c @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ + +/** + * @file panic.c + * Kernel panic handler implementation. + */ + +#include <kmi/power.h> +#include <kmi/debug.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); + + info("attempting to reboot\n"); + + poweroff(COLD_REBOOT); + + /* spin if poweroff failed for some reason */ + error("reboot failed, spinning in place\n"); + while (1); +} diff --git a/common/timer.c b/common/timer.c index 50ec237..272ba02 100644 --- a/common/timer.c +++ b/common/timer.c @@ -195,7 +195,7 @@ ticks_t nsecs_to_ticks(tunit_t nsecs) } /* call to this function from exception handlers */ -void update_timers() +void handle_timer() { struct timer *t = newest_timer(); remove_timer(t); diff --git a/common/uapi/dispatch.c b/common/uapi/dispatch.c index a9caa1e..5b523cc 100644 --- a/common/uapi/dispatch.c +++ b/common/uapi/dispatch.c @@ -76,6 +76,7 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, case SYS_GET_CAP: sys_get_cap(t, a, b, c, d, e); break; case SYS_CLEAR_CAP: sys_clear_cap(t, a, b, c, d, e); break; case SYS_POWEROFF: sys_poweroff(t, a, b, c, d, e); break; + case SYS_IRQ_REQ: sys_irq_req(t, a, b, c, d, e); break; default: error("Syscall %zu outside allowed range [0 - %i]\n", syscall, SYS_NUM - 1); diff --git a/common/uapi/irq.c b/common/uapi/irq.c new file mode 100644 index 0000000..3aa040e --- /dev/null +++ b/common/uapi/irq.c @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ + +/** + * @file irq.c + * IRQ request syscall handling implementation. + */ + +#include <kmi/uapi.h> +#include <kmi/irq.h> + +/** + * 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. + */ +SYSCALL_DEFINE1(irq_req)(struct tcb *t, sys_arg_t id) +{ + if (!has_cap(t->caps, CAP_IRQ)) + return_args1(t, ERR_PERM); + + if (!t->callback) + return_args1(t, ERR_NF); + + return_args1(t, register_irq(t, id)); +} diff --git a/common/uapi/proc.c b/common/uapi/proc.c index 0ec19fb..b6018b8 100644 --- a/common/uapi/proc.c +++ b/common/uapi/proc.c @@ -151,6 +151,7 @@ SYSCALL_DEFINE1(kill)(struct tcb *t, sys_arg_t tid) return_args1(t, ERR_PERM); /** @todo implement */ + /** @todo remember to unregister IRQ handlers */ return_args1(t, OK); } diff --git a/include/arch/cpu.h b/include/arch/cpu.h index d142433..1fd146e 100644 --- a/include/arch/cpu.h +++ b/include/arch/cpu.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: copyleft-next-0.3.1 */ /* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ -#ifndef KMI_CPU_H -#define KMI_CPU_H +#ifndef KMI_ARCH_CPU_H +#define KMI_ARCH_CPU_H /** * @file cpu.h @@ -43,4 +43,4 @@ void cpu_assign(struct tcb *t); */ void cpu_send_ipi(id_t cpu_id); -#endif /* KMI_CPU_H */ +#endif /* KMI_ARCH_CPU_H */ diff --git a/include/arch/irq.h b/include/arch/irq.h index 72b998e..85a7360 100644 --- a/include/arch/irq.h +++ b/include/arch/irq.h @@ -1,8 +1,11 @@ /* SPDX-License-Identifier: copyleft-next-0.3.1 */ /* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ -#ifndef KMI_IRQ_H -#define KMI_IRQ_H +#ifndef KMI_ARCH_IRQ_H +#define KMI_ARCH_IRQ_H + +/** Type for IRQ id. */ +typedef uint_fast32_t irq_t; /** * @file irq.h @@ -19,16 +22,42 @@ #endif /** - * Initialize IRQ subsystem. + * Initialize arch-specific IRQ stuff. * * @param fdt Global FDT pointer. */ -void init_irq(void *fdt); +void setup_irq(void *fdt); + +/** + * Activate IRQ for \p id. + * Assumes there's one interrupt controller for the whole system, which might be + * an oversimplification. + * + * @param id IRQ id to deactivate. + * @return OK on success, non-zero otherwise. + */ +stat_t activate_irq(irq_t id); + +/** + * Deactivates IRQ for \p id. + * + * @param id IRQ id to deactivate. + * @return OK on success, non-zero otherwise. + */ +stat_t deactivate_irq(irq_t id); /** Enable IRQs. */ -void enable_irq(); +void enable_irqs(); /** Disable IRQs. */ -void disable_irq(); +void disable_irqs(); + +/** Get IRQ to handle. + * + * @return ID of IRQ to handle. + * + * @todo what about illegal IRQs due to bug or something? + */ +irq_t get_irq(); -#endif /* KMI_IRQ_H */ +#endif /* KMI_ARCH_IRQ_H */ diff --git a/include/arch/proc.h b/include/arch/proc.h index 79b099e..341a2f4 100644 --- a/include/arch/proc.h +++ b/include/arch/proc.h @@ -21,6 +21,8 @@ * Attach argument data to thread. * * @param t Thread that will run after return. + * @param n How many of the arguments to attach. Might micro-optimize some + * stuff. * @param a Arguments to attach. */ void set_args(struct tcb *t, size_t n, struct sys_ret a); diff --git a/include/kmi/caps.h b/include/kmi/caps.h index 078dd3d..2813634 100644 --- a/include/kmi/caps.h +++ b/include/kmi/caps.h @@ -34,6 +34,9 @@ enum { /** Thread is allowed to access configuration parameters. */ CAP_CONF = (1 << 4), + + /** Thread is allowed to request to handle IRQs. */ + CAP_IRQ = (1 << 5), }; /** diff --git a/include/kmi/ipi.h b/include/kmi/ipi.h index 4567edb..72b54b9 100644 --- a/include/kmi/ipi.h +++ b/include/kmi/ipi.h @@ -29,12 +29,7 @@ bool clear_ipi(struct tcb *t); */ 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); +/** Handle IPI. */ +void handle_ipi(); #endif /* KMI_IPI_H */ diff --git a/include/kmi/irq.h b/include/kmi/irq.h new file mode 100644 index 0000000..ccc654b --- /dev/null +++ b/include/kmi/irq.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ + +#ifndef KMI_IRQ_H +#define KMI_IRQ_H + +/** + * @file irq.h + * Common IRQ handling stuff. + */ + +#include <kmi/tcb.h> +#include <arch/irq.h> + +/** + * Initialize IRQ subsystem. + * + * @param fdt Flattened device tree. + */ +void init_irq(void *fdt); + +/** Handle irq. */ +void handle_irq(); + +/** + * Register IRQ with thread \p t. + * + * @param t Thread to register IRQ \p id to. + * @param id IRQ id to register to \p t. + * @return OK on success, non-zero otherwise. + */ +stat_t register_irq(struct tcb *t, irq_t id); + +/** + * Unregister IRQ with thread \p t. + * + * @param t Thread to unregister \p id from. + * @param id IRQ id to unregister from \p t. + * @return OK on success, non-zero otherwise. + */ +stat_t unregister_irq(struct tcb *t, irq_t id); + +#endif /* KMI_IRQ_H */ diff --git a/include/kmi/panic.h b/include/kmi/panic.h new file mode 100644 index 0000000..44593a3 --- /dev/null +++ b/include/kmi/panic.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ + +#ifndef KMI_PANIC_H +#define KMI_PANIC_H + +/** + * @file panic.h + * Kernel panic handler. + */ + +/** + * Call on kernel panic, tries to reboot the system. Failing that, spin. + * Ideally registers and kernel state would be printed, but keep things simple + * for now. + * + * @param pc Address where fault occured. Should preferably be in the kernel. + * @param addr Possibly associated address. + * @param cause Possible error code associated with panic. Page fault, etc. + */ +__noreturn void kernel_panic(void *pc, void *addr, long cause); + +#endif /* KMI_PANIC_H */ diff --git a/include/kmi/syscalls.h b/include/kmi/syscalls.h index 8ca6546..79cd692 100644 --- a/include/kmi/syscalls.h +++ b/include/kmi/syscalls.h @@ -134,6 +134,10 @@ enum { /** Shutdown, reboot, etc. */ SYS_POWEROFF, + + /** Request to handle IRQ. */ + SYS_IRQ_REQ, + /** @} */ SYS_NUM, diff --git a/include/kmi/timer.h b/include/kmi/timer.h index c0855e4..c1a07a2 100644 --- a/include/kmi/timer.h +++ b/include/kmi/timer.h @@ -133,4 +133,6 @@ static inline ticks_t secs_to_ticks(tunit_t secs) return msecs_to_ticks(secs * 1000); } +void handle_timer(); + #endif /* KMI_TIMER_H */ diff --git a/include/kmi/uapi.h b/include/kmi/uapi.h index 477e315..891b5f9 100644 --- a/include/kmi/uapi.h +++ b/include/kmi/uapi.h @@ -796,6 +796,21 @@ SYSCALL_DECLARE3(clear_cap, tid, off, cap); * Shouldn't return at all. */ SYSCALL_DECLARE1(poweroff, type); + +/** + * Request to handle IRQ. + * + * @param t Current tcb. + * @param id ID if IRQ to handle. + * @param b Unused. + * @param c Unused. + * @param d Unused. + * @param e Unused. + * + * Returns OK on success, non-zero otherwise. + * @todo document error codes better. + */ +SYSCALL_DECLARE1(irq_req, id); /** @} */ /** @@ -818,32 +833,147 @@ void handle_syscall(sys_arg_t syscall, sys_arg_t a, sys_arg_t b, #include <arch/proc.h> +/** + * Set one argument to pass to thread when returning to userspace. + * + * @param t Thread whose arguments to set. + * @param a First argument. + */ #define set_args1(t, a) set_args(t, 1, SYS_RET1(a)) + +/** + * Set two arguments to pass to thread when returning to userspace. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + */ #define set_args2(t, a, b) set_args(t, 2, SYS_RET2(a, b)) + +/** + * Set three arguments to pass to thread when returning to userspace. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + */ #define set_args3(t, a, b, c) set_args(t, 3, SYS_RET3(a, b, c)) + +/** + * Set four arguments to pass to thread when returning to userspace. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + * @param d Fourth argument. + */ #define set_args4(t, a, b, c, d) set_args(t, 4, SYS_RET4(a, b, c, d)) + +/** + * Set five arguments to pass to thread when returning to userspace. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + * @param d Fourth argument. + * @param e Fifth argument. + */ #define set_args5(t, a, b, c, d, e) set_args(t, 5, SYS_RET5(a, b, c, d, e)) -#define set_args6(t, a, b, c, d, e, f) set_args(t, 6, \ - SYS_RET6(a, b, c, d, e, f)) +/** + * Set six arguments to pass to thread when returning to userspace. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + * @param d Fourth argument. + * @param e Fifth argument. + * @param f Sixth argument. + */ +#define set_args6(t, a, b, c, d, e, f) \ + set_args(t, 6, SYS_RET6(a, b, c, d, e, f)) + +/** + * Set one argument and return from uapi function. + * Essentially a beauty macro and slight micro-optimization, avoiding setting + * registers to zero when not required. + * + * @param t Thread whose arguments to set. + * @param a First argument. + */ #define return_args1(t, a) \ {set_args1(t, a); return;} +/** + * Set two arguments and return from uapi function. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + */ #define return_args2(t, a, b) \ {set_args2(t, a, b); return;} +/** + * Set three arguments and return from uapi function. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + */ #define return_args3(t, a, b, c) \ {set_args3(t, a, b, c); return;} +/** + * Set four arguments and return from uapi function. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + * @param d Fourth argument. + */ #define return_args4(t, a, b, c, d) \ {set_args4(t, a, b, c, d); return;} +/** + * Set five arguments and return from uapi function. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + * @param d Fourth argument. + * @param e Fifth argument. + */ #define return_args5(t, a, b, c, d, e) \ {set_args5(t, a, b, c, d, e); return;} +/** + * Set six arguments and return from uapi function. + * + * @param t Thread whose arguments to set. + * @param a First argument. + * @param b Second argument. + * @param c Third argument. + * @param d Fourth argument. + * @param e Fifth argument. + * @param f Sixth argument. + */ #define return_args6(t, a, b, c, d, e, f) \ {set_args6(t, a, b, c, d, e, f); return;} +/** + * Set all arguments and return from uapi function. + * + * @param t Thread whose arguments to set. + * @param x Arguments to set. + */ #define return_args(t, x) {set_args((t), 6, (x)); return;} #endif /* KMI_UAPI_H */ |
