diff options
author | dzwdz | 2024-08-03 02:04:58 +0200 |
---|---|---|
committer | dzwdz | 2024-08-03 02:04:58 +0200 |
commit | 27b8676963d5d69353f44fde7faaa9a4dfe1567b (patch) | |
tree | 7c5decd1bc4b4a43a1ee331e671681830eb1d1da /src | |
parent | 974c2581c9524aa7546f5863ecc26065e328cd54 (diff) |
kernel: send user interrupt on page fault
I really should just rename interrupts to something else.
This is inspired by Plan9 and meant to make debugging easier, as the
dying process can take a stacktrace etc.
It kinda sucks that the default handler now depends on fprintf, which is quite
a bit of code, but whatever.
Diffstat (limited to 'src')
-rw-r--r-- | src/cmd/crash.c | 7 | ||||
-rw-r--r-- | src/kernel/arch/amd64/interrupts/isr.c | 26 | ||||
-rw-r--r-- | src/kernel/proc.c | 2 | ||||
-rw-r--r-- | src/kernel/proc.h | 1 | ||||
-rw-r--r-- | src/libc/intr.c | 22 |
5 files changed, 55 insertions, 3 deletions
diff --git a/src/cmd/crash.c b/src/cmd/crash.c new file mode 100644 index 0000000..a644eed --- /dev/null +++ b/src/cmd/crash.c @@ -0,0 +1,7 @@ +int +main(void) +{ + // TODO flags to write into kernel mem / nonexistent mem, read/write + volatile int *thing = (void*)0xF000BAAA; + *thing = 1337; +} diff --git a/src/kernel/arch/amd64/interrupts/isr.c b/src/kernel/arch/amd64/interrupts/isr.c index 15993b2..75e9dc6 100644 --- a/src/kernel/arch/amd64/interrupts/isr.c +++ b/src/kernel/arch/amd64/interrupts/isr.c @@ -74,6 +74,32 @@ isr_stage3(uint8_t inr, IsrFrame *sf) log_interrupt(inr, sf); cpu_halt(); } else { /* in user */ + if (inr == PageFault) { + char buf[64]; + int len = snprintf( + buf, sizeof(buf), + "sys: fault %s ip=%p cr2=%p", /* format inspired by plan9 */ + (sf->errcode & 2) ? "write" : "read", + sf->iret.ip, + getcr2() + ); + + /* save registers (ignoring SSE) */ + proc_cur->regs = sf->regs; + proc_cur->regs.rsp = sf->iret.sp; + proc_cur->regs.rip = sf->iret.ip; + proc_cur->regs.flags = sf->iret.flags; + + proc_intr(proc_cur, buf, len); + proc_intr_deliver(proc_cur); + + /* restore */ + sf->regs = proc_cur->regs; + sf->iret.sp = proc_cur->regs.rsp; + sf->iret.ip = proc_cur->regs.rip; + sf->iret.flags = proc_cur->regs.flags; + return; + } proc_kill(proc_cur, inr); proc_switch_any(); } diff --git a/src/kernel/proc.c b/src/kernel/proc.c index abe0d04..278b2bc 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -383,7 +383,7 @@ void proc_intr(Proc *p, const char *buf, size_t len) { memcpy(p->queuedintr->buf, buf, len); } -static void proc_intr_deliver(Proc *p) { +void proc_intr_deliver(Proc *p) { assert(p->state == PS_RUNNING); Intr *intr = p->queuedintr; diff --git a/src/kernel/proc.h b/src/kernel/proc.h index bd4c961..0de740f 100644 --- a/src/kernel/proc.h +++ b/src/kernel/proc.h @@ -126,6 +126,7 @@ void proc_tryreap(Proc *dead); /** Send an interupt to a process. */ void proc_intr(Proc *p, const char *buf, size_t len); +void proc_intr_deliver(Proc *p); /** Switches execution to any running process. */ _Noreturn void proc_switch_any(void); diff --git a/src/libc/intr.c b/src/libc/intr.c index 12e6f4c..e751fa1 100644 --- a/src/libc/intr.c +++ b/src/libc/intr.c @@ -1,4 +1,5 @@ #include <camellia/intr.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> @@ -9,6 +10,23 @@ void intr_set(void (*fn)(struct intr_data *)) { _intr = fn ? fn : intr_null; } -void intr_default(struct intr_data *) { - exit(-1); +/* does haystack begin with needle? */ +static +bool strprefix(const char *haystack, const char *needle) +{ + for (;; haystack++, needle++) { + if (*needle == '\0') return true; + /* note that *haystack == '\0' implies *needle != *haystack */ + if (*needle != *haystack) return false; + } +} + +__attribute__((visibility("hidden"))) +extern char __executable_start[]; + +void intr_default(struct intr_data *d) { + if (strprefix(d->msg, "sys: ")) { + fprintf(stderr, "%s: %s (base %p)\n", getprogname(), d->msg, __executable_start); + } + exit(1); } |