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 --- rsdos/src/main.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 3 deletions(-) (limited to 'rsdos') diff --git a/rsdos/src/main.rs b/rsdos/src/main.rs index 27dab06..0e159e6 100644 --- a/rsdos/src/main.rs +++ b/rsdos/src/main.rs @@ -247,6 +247,25 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut } rsnix::interrupts::init(); rsnix::serial_println!("intr: IDT loaded, PIC remapped, timer ~100 Hz"); + // Prove the timer actually ticks before handing the machine to the + // scheduler: if the PIC/APIC route is broken on real hardware, the + // first `hlt` (shell input, idle) never wakes and the system silently + // freezes. Spin briefly with interrupts on and require uptime to + // advance; a dead timer becomes a visible panic instead. + let t0 = rsnix::interrupts::uptime_ms(); + let mut timer_ok = false; + for _ in 0..2_000_000 { + core::hint::spin_loop(); + if rsnix::interrupts::uptime_ms() != t0 { + timer_ok = true; + break; + } + } + if timer_ok { + rsnix::serial_println!("intr: timer verified (uptime advances)"); + } else { + panic!("timer: no PIT tick within 2M spins — interrupt routing broken"); + } rsnix::gop::boot_marker("rsnix: serial+ps2+gdt+intr ok"); dump_memory_summary(); @@ -347,13 +366,50 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut rsnix::serial_println!("boot: entering shell"); rsnix::gop::boot_marker("rsnix: boot done — shell"); - // USB (xHCI) mouse is polled; fall back to PS/2 if no USB mouse. - rsnix::usb::init(); - if rsnix::ps2::mouse_present() || rsnix::usb::controller_up() { + // USB (xHCI) / EHCI mouse is polled; fall back to PS/2 if no USB mouse. + // Each stage draws its own marker: a real-hardware freeze leaves the + // last completed stage on the screen, so the hang point is identifiable + // without a serial console. + // STOPGAP: skip ALL USB host-controller init so the BIOS USB-Legacy SMI + // keeps emulating the keyboard/mouse on the 8042 (PS/2). Resetting the + // EHCI without a completed USBLEGSUP ownership handshake killed the + // firmware's legacy emulation, leaving the OptiPlex 7010 with zero input. + // While NO_USB is set, USB input is served entirely by the BIOS (IRQ1/ + // IRQ12 + our PS/2 driver) and no EHCI/xHCI/UHCI register is touched. + const NO_USB: bool = false; + rsnix::gop::boot_marker("rsnix: usb init"); + if !NO_USB { + rsnix::usb::init(); + } else { + rsnix::serial_println!("usb: init skipped (stopgap) — BIOS USB-Legacy owns input"); + } + rsnix::gop::boot_marker("rsnix: ehci init"); + if !NO_USB { + rsnix::ehci::init(); + } else { + rsnix::serial_println!("ehci: init skipped (stopgap)"); + } + rsnix::gop::boot_marker("rsnix: uhci init"); + if !NO_USB { + rsnix::uhci::init(); + } else { + rsnix::serial_println!("uhci: init skipped (stopgap)"); + } + if rsnix::ps2::mouse_present() + || rsnix::usb::controller_up() + || rsnix::ehci::controller_up() + || rsnix::uhci::controller_up() + { + rsnix::gop::boot_marker("rsnix: cursor spawn"); rsnix::cursor::spawn(); } else { rsnix::serial_println!("cursor: no mouse — overlay disabled"); } + rsnix::gop::boot_marker("rsnix: shell run"); + // The shell REPL is about to start: from here on task 0 may legitimately + // park in poll_key with a fixed frame, so the watchdog's boot-phase spin + // rule for task 0 is disarmed (boot-phase hangs already panicked). + rsnix::sched::mark_shell_running(); // Shell-entry self-check: verify the vt grid structs are sane right // before the shell's first print. The OptiPlex crashes in the first // banner write when the cells VecData (or the shadow) holds the -- cgit v1.2.3