diff options
Diffstat (limited to '')
| -rw-r--r-- | rsnix/src/interrupts.rs | 36 |
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 | ||
| 211 | static KEYBUF: ByteRing = ByteRing::new(); | 211 | static KEYBUF: ByteRing = ByteRing::new(); |
| 212 | static MOUSEBUF: ByteRing = ByteRing::new(); | 212 | static 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). | ||
| 216 | static 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 | ||
| 415 | fn in_dump() -> bool { | 419 | pub(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); |
