From af8d5aa4538ac71f11a5418ef94ae478868a0484 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 02:28:10 +0200 Subject: interrupts: IDT, PIC remap, PIT timer, PS/2 keyboard IRQ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IDT with 256 entries, loaded via lidt (CS read from current context) - PIC 8259A remapped to vectors 32-47, timer+keyboard IRQs unmasked - PIT channel 0 at ~100 Hz (mode 2, rate generator) - PS/2 keyboard IRQ (IRQ1 → vector 33): reads port 0x60, pushes byte to lock-free SPSC ring buffer - Timer IRQ (IRQ0 → vector 32): sends EOI, increments tick counter - ps2::poll_key() now reads from ring buffer with cli/sti+hlt for race-free sleep (instead of busy-polling the data port) - build.rs: use idiomatic Result<_, Box> return type - tools/qemu.sh: fix SC2207 shellcheck warning --- src/ps2.rs | 55 +++++++++++++++++++++---------------------------------- 1 file changed, 21 insertions(+), 34 deletions(-) (limited to 'src/ps2.rs') diff --git a/src/ps2.rs b/src/ps2.rs index e972658..3a42c1a 100644 --- a/src/ps2.rs +++ b/src/ps2.rs @@ -179,47 +179,34 @@ fn drain_input() { } } -/// Poll for a key event. Blocks until a key is pressed. +/// Poll for a key event. Blocks via `hlt` until a key is pressed. +/// The keyboard interrupt handler pushes raw scancodes to a ring buffer; +/// this function pops and decodes them. pub fn poll_key() -> KeyEvent { loop { - let byte = read_data(); - if let Some(ev) = process_byte(byte) { - return ev; - } - } -} + // Disable interrupts so the buffer-empty → hlt window is atomic. + unsafe { core::arch::asm!("cli", options(nostack, preserves_flags)); } -/// Non-blocking poll. -pub fn try_poll_key() -> Option { - unsafe { - let status: u8; - core::arch::asm!("in al, dx", out("al") status, in("dx") STATUS_PORT, - options(nostack, preserves_flags)); - if status & STAT_OUTPUT_FULL == 0 { - return None; + if let Some(byte) = crate::interrupts::read_scancode() { + unsafe { core::arch::asm!("sti", options(nostack, preserves_flags)); } + if let Some(ev) = process_byte(byte) { + return ev; + } + } else { + // Re-enable and halt. If a keyboard IRQ arrived between the + // buffer check and `sti`, the CPU sees a pending interrupt + // and `hlt` returns immediately. + unsafe { + core::arch::asm!("sti; hlt", options(nostack, preserves_flags)); + } } - let data: u8; - core::arch::asm!("in al, dx", out("al") data, in("dx") DATA_PORT, - options(nostack, preserves_flags)); - process_byte(data) } } -/// Read a byte from the keyboard data port (blocking). -fn read_data() -> u8 { - unsafe { - loop { - let status: u8; - core::arch::asm!("in al, dx", out("al") status, in("dx") STATUS_PORT, - options(nostack, preserves_flags)); - if status & STAT_OUTPUT_FULL != 0 { - let data: u8; - core::arch::asm!("in al, dx", out("al") data, in("dx") DATA_PORT, - options(nostack, preserves_flags)); - return data; - } - } - } +/// Non-blocking poll — read from the interrupt ring buffer if available. +pub fn try_poll_key() -> Option { + let byte = crate::interrupts::read_scancode()?; + process_byte(byte) } /// Process a single scancode byte. Returns Some(KeyEvent) when a visible -- cgit v1.2.3