diff options
Diffstat (limited to 'src/kernel')
-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 |
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); |