summaryrefslogtreecommitdiffstats
path: root/rsnix/src/interrupts.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rsnix/src/interrupts.rs')
-rw-r--r--rsnix/src/interrupts.rs36
1 files changed, 34 insertions, 2 deletions
diff --git a/rsnix/src/interrupts.rs b/rsnix/src/interrupts.rs
index 927e4f1..9872389 100644
--- a/rsnix/src/interrupts.rs
+++ b/rsnix/src/interrupts.rs
@@ -210,6 +210,10 @@ impl ByteRing {
210 210
211static KEYBUF: ByteRing = ByteRing::new(); 211static KEYBUF: ByteRing = ByteRing::new();
212static MOUSEBUF: ByteRing = ByteRing::new(); 212static MOUSEBUF: ByteRing = ByteRing::new();
213/// One-shot flag: the first unhandled interrupt logs its vector, so real
214/// hardware shows which device raised a stray IRQ (before the LAPIC EOI
215/// drops it).
216static STRAY_LOGGED: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false);
213 217
214// --------------------------------------------------------------------------- 218// ---------------------------------------------------------------------------
215// Interrupt stubs (assembly) and dispatch 219// Interrupt stubs (assembly) and dispatch
@@ -412,7 +416,7 @@ pub fn enter_dump() {
412 } 416 }
413} 417}
414 418
415fn in_dump() -> bool { 419pub(crate) fn in_dump() -> bool {
416 unsafe { IN_DUMP } 420 unsafe { IN_DUMP }
417} 421}
418 422
@@ -488,7 +492,35 @@ unsafe extern "C" fn isr_dispatch(frame: &IntFrame) -> usize {
488 } 492 }
489 crate::sched::fault_dump("exception", 0, frame) 493 crate::sched::fault_dump("exception", 0, frame)
490 } 494 }
491 _ => fp, 495 _ => {
496 // Unhandled/stray interrupt. On real hardware an
497 // IO-APIC-delivered IRQ (USB/SATA/NIC INTx) that is never
498 // EOI'd stays pending in the local APIC and re-fires the
499 // instant we iretq — an interrupt storm that starves the
500 // timer tick (higher vector priority) and freezes the whole
501 // machine with no panic. EOI the LAPIC so an
502 // edge-triggered stray drops (a genuinely-spurious LAPIC
503 // IRQ needs no EOI, so that case is a benign no-op).
504 // Level-triggered strays are additionally stopped by the
505 // drivers masking their PCI INTx / interrupt enables.
506 if !STRAY_LOGGED.swap(true, Ordering::Relaxed) {
507 crate::serial_println!("intr: stray vector {:#x} — LAPIC EOI'd", frame.vector);
508 }
509 // EOI the local APIC when it is enabled (MSR 0x1B, bit 11).
510 let (lo, hi): (u32, u32);
511 core::arch::asm!(
512 "rdmsr",
513 in("ecx") 0x1Bu32,
514 out("eax") lo,
515 out("edx") hi,
516 options(nostack, preserves_flags)
517 );
518 let apic = ((hi as u64) << 32) | lo as u64;
519 if apic & (1 << 11) != 0 {
520 core::ptr::write_volatile(0xFEE0_00B0usize as *mut u32, 0);
521 }
522 fp
523 }
492 } 524 }
493 }; 525 };
494 crate::sched::set_in_isr(false); 526 crate::sched::set_in_isr(false);