diff options
| author | salmonik <salmonik@tuta.io> | 2026-08-17 14:53:52 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-08-17 14:53:52 +0200 |
| commit | be868a43185826b02bf6d091019bb779678525bb (patch) | |
| tree | 586988c15f1d700b1621c7f0208584b30878a56c /rsnix/src/interrupts.rs | |
| parent | v0.5.10: change em-dashes to dashes (diff) | |
| download | rs-dos-be868a43185826b02bf6d091019bb779678525bb.tar.gz rs-dos-be868a43185826b02bf6d091019bb779678525bb.zip | |
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
Diffstat (limited to 'rsnix/src/interrupts.rs')
| -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); |
