From a2f9ae9d4ab678fa66a2ec5d1072ea22a36a18a1 Mon Sep 17 00:00:00 2001 From: dzwdz Date: Thu, 19 Jan 2023 23:36:11 +0100 Subject: kernel: user interrupts --- src/kernel/proc.c | 27 ++++++++++++++++++++++++++- src/kernel/proc.h | 5 +++++ src/kernel/syscalls.c | 12 ++++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) (limited to 'src/kernel') diff --git a/src/kernel/proc.c b/src/kernel/proc.c index d105f66..d8c7e57 100755 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ struct process *process_fork(struct process *parent, int flags) { child->regs = parent->regs; child->state = parent->state; assert(child->state == PS_RUNNING); // not copying the state union + child->intr_fn = parent->intr_fn; child->noreap = (flags & FORK_NOREAP) > 0; @@ -188,12 +190,15 @@ void process_kill(struct process *p, int ret) { } if (p->state == PS_DYING) { - if (p->parent && proc_alive(p->parent) && !p->noreap) { + if (p->parent && proc_alive(p->parent)) { process_transition(p, PS_TOREAP); } else { process_transition(p, PS_TOMBSTONE); } } + if (p == process_first) { + assert(!p->child); + } process_tryreap(p); if (p == process_first) { @@ -271,6 +276,21 @@ void process_tryreap(struct process *dead) { } } +void process_intr(struct process *p) { + if (!p->intr_fn) return; + + /* save old rsp,rip */ + struct intr_data d; + void __user *sp = p->regs.rsp - 128 - sizeof(d); + d.ip = (void __user *)p->regs.rcx; + d.sp = p->regs.rsp; + virt_cpy_to(p->pages, sp, &d, sizeof(d)); + + /* switch to intr handler */ + p->regs.rcx = (uint64_t)p->intr_fn; + p->regs.rsp = sp; +} + /** Removes a process from the process tree. */ static void process_forget(struct process *p) { assert(p->parent); @@ -447,6 +467,11 @@ void process_transition(struct process *p, enum process_state state) { assert(p->state == PS_TOREAP || p->state == PS_DYING); } else if (state == PS_TOREAP) { assert(p->state == PS_DYING); + + assert(!p->parent || proc_alive(p->parent)); + for (struct process *it = p->child; it; it = it->sibling) { + assert(p->state != PS_TOREAP); + } } else if (state != PS_RUNNING && state != PS_DYING) { assert(p->state == PS_RUNNING); } diff --git a/src/kernel/proc.h b/src/kernel/proc.h index b95e901..041dbd0 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -81,6 +81,9 @@ struct process { /* vfs_backend controlled (not exclusively) by this process */ struct vfs_backend *controlled; + /* interrupt handler */ + void __user *intr_fn; + struct { void *buf; size_t len; @@ -100,6 +103,8 @@ void process_filicide(struct process *proc, int ret); /** Tries to reap a dead process / free a tombstone. */ void process_tryreap(struct process *dead); +void process_intr(struct process *proc); + /** Switches execution to any running process. */ _Noreturn void process_switch_any(void); diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 3ebda61..8327b68 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -378,6 +378,16 @@ void _syscall_filicide(void) { process_filicide(process_current, -1); } +void _syscall_intr(void) { + for (struct process *p = process_current->child; p; p = process_next(p, process_current)) { + process_intr(p); + } +} + +void _syscall_intr_set(void __user *ip) { + process_current->intr_fn = ip; +} + long _syscall_execbuf(void __user *ubuf, size_t len) { if (len == 0) SYSCALL_RETURN(0); if (len > EXECBUF_MAX_LEN) @@ -428,6 +438,8 @@ long _syscall(long num, long a, long b, long c, long d, long e) { break; case _SYSCALL_PIPE: _syscall_pipe((userptr_t)a, b); break; case _SYSCALL_SLEEP: _syscall_sleep(a); break; case _SYSCALL_FILICIDE: _syscall_filicide(); + break; case _SYSCALL_INTR: _syscall_intr(); + break; case _SYSCALL_INTR_SET: _syscall_intr_set((userptr_t)a); break; case _SYSCALL_EXECBUF: _syscall_execbuf((userptr_t)a, b); break; case _SYSCALL_DEBUG_KLOG: _syscall_debug_klog((userptr_t)a, b); break; -- cgit v1.2.3