summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/arch/amd64/interrupts/isr.c26
-rw-r--r--src/kernel/proc.c2
-rw-r--r--src/kernel/proc.h1
3 files changed, 28 insertions, 1 deletions
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);