Kill a faulting user process instead of halting the machine

A CPU exception raised in ring 3 by a scheduled process now kills that
process - IRQ bindings, IPC handles, and address space reclaimed, a
client it owed a reply to failed with the new -EPEER instead of hung -
and the core reschedules (docs/resilience.md step 2). Kernel-mode
faults, NMI, double fault, and machine check stay terminal, as does the
borrowed-thread isolation probe. Proven by the new fault-recovery QEMU
test: init keeps heartbeating after a process page-faults to death.
This commit is contained in:
Daniel Samson
2026-07-11 04:57:02 +01:00
parent 59104dd988
commit 6b3ae0c997
8 changed files with 198 additions and 35 deletions
+8 -5
View File
@@ -3,9 +3,11 @@
//! triple-faults and silently resets the machine. With it, the CPU vectors into
//! our stubs, which capture the register state and hand it to a dispatcher.
//!
//! Vectors split in two: 0-31 are CPU exceptions (terminal — reported and
//! halted); 32+ are device interrupts (a registered handler runs, the APIC is
//! acknowledged, and we return to the interrupted code).
//! Vectors split in two: 0-31 are CPU exceptions, handed to the `on_fault` hook
//! and never returned from (the kernel's handler kills a faulting user process
//! and reschedules, or halts the core for a kernel-mode fault); 32+ are device
//! interrupts (a registered handler runs, the APIC is acknowledged, and we
//! return to the interrupted code).
const gdt = @import("gdt.zig");
const tss = @import("tss.zig");
@@ -162,8 +164,9 @@ pub fn loadOnThisCpu() void {
}
/// Called by isr_common (isr.s) with a pointer to the trap frame. Exported so the
/// assembly stubs can `call` it by name. Exceptions are terminal; device
/// interrupts run their handler, get acknowledged, and return.
/// assembly stubs can `call` it by name. Exceptions never return here (on_fault
/// kills the faulting process or halts the core); device interrupts run their
/// handler, get acknowledged, and return.
export fn interruptDispatch(state: *CpuState) callconv(.c) void {
if (state.vector < 32) {
on_fault(state); // CPU exception — never returns