diff options
-rwxr-xr-x | src/kernel/proc.c | 27 | ||||
-rw-r--r-- | src/kernel/proc.h | 5 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 12 | ||||
-rw-r--r-- | src/shared/include/camellia/syscalls.h | 4 | ||||
-rw-r--r-- | src/shared/include/camellia/types.h | 5 | ||||
-rw-r--r-- | src/user/app/ext2fs/main.c | 3 | ||||
-rw-r--r-- | src/user/app/init/driver/initctl.c | 4 | ||||
-rw-r--r-- | src/user/app/init/init.c | 22 | ||||
-rw-r--r-- | src/user/app/shell/shell.c | 1 | ||||
-rw-r--r-- | src/user/lib/_start2.c | 4 | ||||
-rw-r--r-- | src/user/lib/include/unistd.h | 3 | ||||
-rw-r--r-- | src/user/lib/intr.s | 20 | ||||
-rw-r--r-- | src/user/lib/syscall.c | 8 | ||||
-rw-r--r-- | src/user/lib/unistd.c | 11 |
14 files changed, 123 insertions, 6 deletions
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 <kernel/arch/generic.h> #include <kernel/execbuf.h> #include <kernel/mem/alloc.h> +#include <kernel/mem/virt.h> #include <kernel/panic.h> #include <kernel/proc.h> #include <kernel/vfs/mount.h> @@ -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; diff --git a/src/shared/include/camellia/syscalls.h b/src/shared/include/camellia/syscalls.h index 690e928..1de5368 100644 --- a/src/shared/include/camellia/syscalls.h +++ b/src/shared/include/camellia/syscalls.h @@ -17,6 +17,8 @@ #define _SYSCALL_PIPE 14 #define _SYSCALL_SLEEP 15 #define _SYSCALL_FILICIDE 16 +#define _SYSCALL_INTR 17 +#define _SYSCALL_INTR_SET 18 #define _SYSCALL_EXECBUF 100 #define _SYSCALL_DEBUG_KLOG 101 @@ -74,6 +76,8 @@ long _syscall_pipe(handle_t __user user_ends[2], int flags); void _syscall_sleep(long ms); void _syscall_filicide(void); +void _syscall_intr(void); +void _syscall_intr_set(void __user *ip); /* see shared/execbuf.h */ long _syscall_execbuf(void __user *buf, size_t len); diff --git a/src/shared/include/camellia/types.h b/src/shared/include/camellia/types.h index be34783..bd17e51 100644 --- a/src/shared/include/camellia/types.h +++ b/src/shared/include/camellia/types.h @@ -30,3 +30,8 @@ struct ufs_request { long offset; int flags; }; + +struct intr_data { + void __user *ip; + void __user *sp; /* last for pop %rsp */ +}; diff --git a/src/user/app/ext2fs/main.c b/src/user/app/ext2fs/main.c index f6d65cc..65e7460 100644 --- a/src/user/app/ext2fs/main.c +++ b/src/user/app/ext2fs/main.c @@ -12,6 +12,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> struct handle { uint32_t n; @@ -191,6 +192,8 @@ err: int main(int argc, char **argv) { + intr_set(NULL); + if (argc < 2) errx(1, "bad usage"); // TODO pread/pwrite for normal handles FILE *disk = fopen(argv[1], "r+"); diff --git a/src/user/app/init/driver/initctl.c b/src/user/app/init/driver/initctl.c index 76d1b1b..67c8ade 100644 --- a/src/user/app/init/driver/initctl.c +++ b/src/user/app/init/driver/initctl.c @@ -29,7 +29,9 @@ void initctl_drv(handle_t killswitch) { } if (!strcmp(buf, "halt")) { _syscall_write(killswitch, "halt", 4, 0, 0); - exit(1); + } + if (!strcmp(buf, "intr")) { + _syscall_write(killswitch, "intr", 4, 0, 0); } c0_fs_respond(NULL, res.len, 0); break; diff --git a/src/user/app/init/init.c b/src/user/app/init/init.c index 350d9a0..0114ac5 100644 --- a/src/user/app/init/init.c +++ b/src/user/app/init/init.c @@ -3,6 +3,7 @@ #include <camellia/syscalls.h> #include <stdint.h> #include <stdio.h> +#include <string.h> #include <unistd.h> #include <camellia/fs/misc.h> @@ -29,7 +30,7 @@ void redirect(const char *exe, const char *out, const char *in) { exit(1); } _syscall_await(); - _syscall_filicide(); + _syscall_intr(); } } } @@ -39,7 +40,7 @@ int main(void) { freopen("/kdev/com1", "a+", stdout); freopen("/kdev/com1", "a+", stderr); - printf("in init (stage 2), main at %p\n", &main); + printf("[init] stage 2, main at %p\n", &main); MOUNT_AT("/keyboard") { MOUNT_AT("/") { fs_whitelist((const char*[]){"/kdev/ps2/kb", NULL}); } @@ -104,7 +105,22 @@ int main(void) { exit(1); } - _syscall_read(killswitch_pipe[0], NULL, 0, 0); + char buf[128]; + for (;;) { + if (_syscall_read(killswitch_pipe[0], buf, 128, 0) != 4) { + break; + } + if (memcmp(buf, "intr", 4) == 0) { + _syscall_intr(); + } else if (memcmp(buf, "halt", 4) == 0) { + break; + } + } + printf("[init] intr\n"); + _syscall_intr(); + _syscall_sleep(1000); + printf("[init] filicide\n"); _syscall_filicide(); + printf("[init] goodbye\n"); return 0; } diff --git a/src/user/app/shell/shell.c b/src/user/app/shell/shell.c index 3dad1bd..564daa8 100644 --- a/src/user/app/shell/shell.c +++ b/src/user/app/shell/shell.c @@ -144,7 +144,6 @@ static void run(char *cmd) { } } - int main(int argc, char **argv) { static char buf[256]; FILE *f = stdin; diff --git a/src/user/lib/_start2.c b/src/user/lib/_start2.c index ba3b6b0..495f046 100644 --- a/src/user/lib/_start2.c +++ b/src/user/lib/_start2.c @@ -17,9 +17,13 @@ const char *shortname(const char *path) { return path; } +void intr_trampoline(void); /* intr.s */ + _Noreturn void _start2(struct execdata *ed) { const char *progname; elf_selfreloc(); + _syscall_intr_set(intr_trampoline); + intr_set(intr_default); __setinitialcwd(ed->cwd); progname = shortname(ed->argv[0]); diff --git a/src/user/lib/include/unistd.h b/src/user/lib/include/unistd.h index f49c337..d13767b 100644 --- a/src/user/lib/include/unistd.h +++ b/src/user/lib/include/unistd.h @@ -26,3 +26,6 @@ size_t absolutepath(char *out, const char *in, size_t size); // TODO put in an internal libc header void __setinitialcwd(const char *c); + +void intr_set(void (*fn)(void)); +void intr_default(void); diff --git a/src/user/lib/intr.s b/src/user/lib/intr.s new file mode 100644 index 0000000..008387d --- /dev/null +++ b/src/user/lib/intr.s @@ -0,0 +1,20 @@ +.section .text +.global intr_trampoline +.type intr_trampoline, @function +intr_trampoline: + push %rax + push %rdx + call *_intr(%rip) + pop %rdx + pop %rax + pop tmprip(%rip) + pop %rsp + jmp *tmprip(%rip) + +.section .bss +tmprip: + .skip 8 + +.global _intr +_intr: + .skip 8 diff --git a/src/user/lib/syscall.c b/src/user/lib/syscall.c index d6ed0af..d42c2ee 100644 --- a/src/user/lib/syscall.c +++ b/src/user/lib/syscall.c @@ -74,6 +74,14 @@ void _syscall_filicide(void) { return (void)_syscall(_SYSCALL_FILICIDE, 0, 0, 0, 0, 0); } +void _syscall_intr(void) { + return (void)_syscall(_SYSCALL_INTR, 0, 0, 0, 0, 0); +} + +void _syscall_intr_set(void __user *ip) { + return (void)_syscall(_SYSCALL_INTR_SET, (long)ip, 0, 0, 0, 0); +} + long _syscall_execbuf(void __user *buf, size_t len) { return _syscall(_SYSCALL_EXECBUF, (long)buf, (long)len, 0, 0, 0); } diff --git a/src/user/lib/unistd.c b/src/user/lib/unistd.c index 01aa94f..cb862f8 100644 --- a/src/user/lib/unistd.c +++ b/src/user/lib/unistd.c @@ -161,3 +161,14 @@ size_t absolutepath(char *out, const char *in, size_t size) { void __setinitialcwd(const char *s) { __initialcwd = s; } + +static void intr_null(void) { } + +extern void (*volatile _intr)(void); +void intr_set(void (*fn)(void)) { + _intr = fn ? fn : intr_null; +} + +void intr_default(void) { + exit(-1); +} |