diff options
Diffstat (limited to 'rsdos/src/main.rs')
| -rw-r--r-- | rsdos/src/main.rs | 62 |
1 files changed, 59 insertions, 3 deletions
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 | |||
| 247 | } | 247 | } |
| 248 | rsnix::interrupts::init(); | 248 | rsnix::interrupts::init(); |
| 249 | rsnix::serial_println!("intr: IDT loaded, PIC remapped, timer ~100 Hz"); | 249 | rsnix::serial_println!("intr: IDT loaded, PIC remapped, timer ~100 Hz"); |
| 250 | // Prove the timer actually ticks before handing the machine to the | ||
| 251 | // scheduler: if the PIC/APIC route is broken on real hardware, the | ||
| 252 | // first `hlt` (shell input, idle) never wakes and the system silently | ||
| 253 | // freezes. Spin briefly with interrupts on and require uptime to | ||
| 254 | // advance; a dead timer becomes a visible panic instead. | ||
| 255 | let t0 = rsnix::interrupts::uptime_ms(); | ||
| 256 | let mut timer_ok = false; | ||
| 257 | for _ in 0..2_000_000 { | ||
| 258 | core::hint::spin_loop(); | ||
| 259 | if rsnix::interrupts::uptime_ms() != t0 { | ||
| 260 | timer_ok = true; | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | if timer_ok { | ||
| 265 | rsnix::serial_println!("intr: timer verified (uptime advances)"); | ||
| 266 | } else { | ||
| 267 | panic!("timer: no PIT tick within 2M spins — interrupt routing broken"); | ||
| 268 | } | ||
| 250 | rsnix::gop::boot_marker("rsnix: serial+ps2+gdt+intr ok"); | 269 | rsnix::gop::boot_marker("rsnix: serial+ps2+gdt+intr ok"); |
| 251 | 270 | ||
| 252 | dump_memory_summary(); | 271 | dump_memory_summary(); |
| @@ -347,13 +366,50 @@ pub unsafe extern "efiapi" fn efi_main(image_handle: Handle, system_table: *mut | |||
| 347 | 366 | ||
| 348 | rsnix::serial_println!("boot: entering shell"); | 367 | rsnix::serial_println!("boot: entering shell"); |
| 349 | rsnix::gop::boot_marker("rsnix: boot done — shell"); | 368 | rsnix::gop::boot_marker("rsnix: boot done — shell"); |
| 350 | // USB (xHCI) mouse is polled; fall back to PS/2 if no USB mouse. | 369 | // USB (xHCI) / EHCI mouse is polled; fall back to PS/2 if no USB mouse. |
| 351 | rsnix::usb::init(); | 370 | // Each stage draws its own marker: a real-hardware freeze leaves the |
| 352 | if rsnix::ps2::mouse_present() || rsnix::usb::controller_up() { | 371 | // last completed stage on the screen, so the hang point is identifiable |
| 372 | // without a serial console. | ||
| 373 | // STOPGAP: skip ALL USB host-controller init so the BIOS USB-Legacy SMI | ||
| 374 | // keeps emulating the keyboard/mouse on the 8042 (PS/2). Resetting the | ||
| 375 | // EHCI without a completed USBLEGSUP ownership handshake killed the | ||
| 376 | // firmware's legacy emulation, leaving the OptiPlex 7010 with zero input. | ||
| 377 | // While NO_USB is set, USB input is served entirely by the BIOS (IRQ1/ | ||
| 378 | // IRQ12 + our PS/2 driver) and no EHCI/xHCI/UHCI register is touched. | ||
| 379 | const NO_USB: bool = false; | ||
| 380 | rsnix::gop::boot_marker("rsnix: usb init"); | ||
| 381 | if !NO_USB { | ||
| 382 | rsnix::usb::init(); | ||
| 383 | } else { | ||
| 384 | rsnix::serial_println!("usb: init skipped (stopgap) — BIOS USB-Legacy owns input"); | ||
| 385 | } | ||
| 386 | rsnix::gop::boot_marker("rsnix: ehci init"); | ||
| 387 | if !NO_USB { | ||
| 388 | rsnix::ehci::init(); | ||
| 389 | } else { | ||
| 390 | rsnix::serial_println!("ehci: init skipped (stopgap)"); | ||
| 391 | } | ||
| 392 | rsnix::gop::boot_marker("rsnix: uhci init"); | ||
| 393 | if !NO_USB { | ||
| 394 | rsnix::uhci::init(); | ||
| 395 | } else { | ||
| 396 | rsnix::serial_println!("uhci: init skipped (stopgap)"); | ||
| 397 | } | ||
| 398 | if rsnix::ps2::mouse_present() | ||
| 399 | || rsnix::usb::controller_up() | ||
| 400 | || rsnix::ehci::controller_up() | ||
| 401 | || rsnix::uhci::controller_up() | ||
| 402 | { | ||
| 403 | rsnix::gop::boot_marker("rsnix: cursor spawn"); | ||
| 353 | rsnix::cursor::spawn(); | 404 | rsnix::cursor::spawn(); |
| 354 | } else { | 405 | } else { |
| 355 | rsnix::serial_println!("cursor: no mouse — overlay disabled"); | 406 | rsnix::serial_println!("cursor: no mouse — overlay disabled"); |
| 356 | } | 407 | } |
| 408 | rsnix::gop::boot_marker("rsnix: shell run"); | ||
| 409 | // The shell REPL is about to start: from here on task 0 may legitimately | ||
| 410 | // park in poll_key with a fixed frame, so the watchdog's boot-phase spin | ||
| 411 | // rule for task 0 is disarmed (boot-phase hangs already panicked). | ||
| 412 | rsnix::sched::mark_shell_running(); | ||
| 357 | // Shell-entry self-check: verify the vt grid structs are sane right | 413 | // Shell-entry self-check: verify the vt grid structs are sane right |
| 358 | // before the shell's first print. The OptiPlex crashes in the first | 414 | // before the shell's first print. The OptiPlex crashes in the first |
| 359 | // banner write when the cells VecData (or the shadow) holds the | 415 | // banner write when the cells VecData (or the shadow) holds the |
