From 4b48b6938d91a91d7b1dd242991258fe47e284f0 Mon Sep 17 00:00:00 2001 From: salmonik Date: Fri, 31 Jul 2026 02:40:18 +0200 Subject: fix: ISR dispatch calling convention + PS/2 interrupt enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: x86_64-unknown-uefi uses the Microsoft x64 calling convention where the first argument is passed in rcx, not rdi. The ISR stub was setting rdi = rsp, but isr_dispatch() read the frame pointer from rcx, getting garbage → triple fault. Also: - Enable PS/2 keyboard IRQ via controller config byte (bit 0). - Expose read_scancode() and TICKS from interrupt module. - ps2::poll_key() uses 'sti; hlt' race-free sleep pattern. --- src/ps2.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 8 deletions(-) (limited to 'src/ps2.rs') diff --git a/src/ps2.rs b/src/ps2.rs index 3a42c1a..4ea8b7a 100644 --- a/src/ps2.rs +++ b/src/ps2.rs @@ -158,9 +158,64 @@ static mut KBD: KbdState = KbdState { got_e0: false, }; -/// Initialise the PS/2 port for the keyboard — just drain stale bytes. +/// Initialise the PS/2 port: drain stale bytes + enable keyboard interrupt. pub fn init() { drain_input(); + + // Enable the keyboard interrupt on the PS/2 controller. + // Read Configuration Byte (command 0x20), set bit 0 (IRQ1 enable), + // write back (command 0x60). + unsafe { + // Tell the keyboard controller we want to read the config byte. + // Need to wait for the controller to be ready first. + wait_write(); + core::arch::asm!("out dx, al", in("dx") 0x64u16, in("al") 0x20u8, + options(nostack, preserves_flags)); + wait_read(); + let mut cfg: u8; + core::arch::asm!("in al, dx", out("al") cfg, in("dx") 0x60u16, + options(nostack, preserves_flags)); + + cfg |= 0x01; // enable keyboard interrupt + + // Write config byte back + wait_write(); + core::arch::asm!("out dx, al", in("dx") 0x64u16, in("al") 0x60u8, + options(nostack, preserves_flags)); + wait_write(); + core::arch::asm!("out dx, al", in("dx") 0x60u16, in("al") cfg, + options(nostack, preserves_flags)); + } +} + +/// Wait until the PS/2 controller is ready to receive a command. +fn wait_write() { + unsafe { + loop { + let status: u8; + core::arch::asm!("in al, dx", out("al") status, in("dx") 0x64u16, + options(nostack, preserves_flags)); + if status & 0x02 == 0 { + // Input buffer empty — controller ready to receive + break; + } + } + } +} + +/// Wait until the PS/2 controller has data available to read. +fn wait_read() { + unsafe { + loop { + let status: u8; + core::arch::asm!("in al, dx", out("al") status, in("dx") 0x64u16, + options(nostack, preserves_flags)); + if status & 0x01 != 0 { + // Output buffer full — data ready to read + break; + } + } + } } fn drain_input() { @@ -184,18 +239,11 @@ fn drain_input() { /// this function pops and decodes them. pub fn poll_key() -> KeyEvent { loop { - // Disable interrupts so the buffer-empty → hlt window is atomic. - unsafe { core::arch::asm!("cli", options(nostack, preserves_flags)); } - 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)); } -- cgit v1.2.3