From be868a43185826b02bf6d091019bb779678525bb Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 17 Aug 2026 14:53:52 +0200 Subject: USB2/1.1 (EHCI/UHCI) drivers + real-hardware bring-up hardening - Add polled EHCI (USB2) and UHCI (USB1.1) host-controller drivers with HID boot mouse support, wired into cursor polling and the 'usb' shell cmd - Add USB Legacy ownership handoff (claim_usb_legacy) plus config_write_byte - Harden boot: verify the PIT/timer ticks before shell entry, EOI stray interrupts in the LAPIC to stop interrupt storms, bound PS/2 controller waits, and INTx-disable AHCI (polled driver) - Add boot stage markers, klog screen echo, and QR lock; scheduler mark_shell_running; NO_USB stopgap to keep BIOS USB-Legacy input alive - alloc_pages_above for DMA buffers that must avoid low conventional memory - Expand DEBUG_NOTES with EHCI/QEMU bring-up findings --- rsnix/src/interrupts.rs | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) (limited to 'rsnix/src/interrupts.rs') 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 { static KEYBUF: ByteRing = ByteRing::new(); static MOUSEBUF: ByteRing = ByteRing::new(); +/// One-shot flag: the first unhandled interrupt logs its vector, so real +/// hardware shows which device raised a stray IRQ (before the LAPIC EOI +/// drops it). +static STRAY_LOGGED: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false); // --------------------------------------------------------------------------- // Interrupt stubs (assembly) and dispatch @@ -412,7 +416,7 @@ pub fn enter_dump() { } } -fn in_dump() -> bool { +pub(crate) fn in_dump() -> bool { unsafe { IN_DUMP } } @@ -488,7 +492,35 @@ unsafe extern "C" fn isr_dispatch(frame: &IntFrame) -> usize { } crate::sched::fault_dump("exception", 0, frame) } - _ => fp, + _ => { + // Unhandled/stray interrupt. On real hardware an + // IO-APIC-delivered IRQ (USB/SATA/NIC INTx) that is never + // EOI'd stays pending in the local APIC and re-fires the + // instant we iretq — an interrupt storm that starves the + // timer tick (higher vector priority) and freezes the whole + // machine with no panic. EOI the LAPIC so an + // edge-triggered stray drops (a genuinely-spurious LAPIC + // IRQ needs no EOI, so that case is a benign no-op). + // Level-triggered strays are additionally stopped by the + // drivers masking their PCI INTx / interrupt enables. + if !STRAY_LOGGED.swap(true, Ordering::Relaxed) { + crate::serial_println!("intr: stray vector {:#x} — LAPIC EOI'd", frame.vector); + } + // EOI the local APIC when it is enabled (MSR 0x1B, bit 11). + let (lo, hi): (u32, u32); + core::arch::asm!( + "rdmsr", + in("ecx") 0x1Bu32, + out("eax") lo, + out("edx") hi, + options(nostack, preserves_flags) + ); + let apic = ((hi as u64) << 32) | lo as u64; + if apic & (1 << 11) != 0 { + core::ptr::write_volatile(0xFEE0_00B0usize as *mut u32, 0); + } + fp + } } }; crate::sched::set_in_isr(false); -- cgit v1.2.3