summaryrefslogtreecommitdiffstats
path: root/src/ps2.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-07-31 02:40:18 +0200
committersalmonik <salmonik@tuta.io>2026-07-31 02:40:18 +0200
commit4b48b6938d91a91d7b1dd242991258fe47e284f0 (patch)
treed0d32321e9384370b72b3bda4105daaea6853196 /src/ps2.rs
parentinterrupts: IDT, PIC remap, PIT timer, PS/2 keyboard IRQ (diff)
downloadrs-dos-4b48b6938d91a91d7b1dd242991258fe47e284f0.tar.gz
rs-dos-4b48b6938d91a91d7b1dd242991258fe47e284f0.zip
fix: ISR dispatch calling convention + PS/2 interrupt enable
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.
Diffstat (limited to '')
-rw-r--r--src/ps2.rs64
1 files changed, 56 insertions, 8 deletions
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 {
158 got_e0: false, 158 got_e0: false,
159}; 159};
160 160
161/// Initialise the PS/2 port for the keyboard — just drain stale bytes. 161/// Initialise the PS/2 port: drain stale bytes + enable keyboard interrupt.
162pub fn init() { 162pub fn init() {
163 drain_input(); 163 drain_input();
164
165 // Enable the keyboard interrupt on the PS/2 controller.
166 // Read Configuration Byte (command 0x20), set bit 0 (IRQ1 enable),
167 // write back (command 0x60).
168 unsafe {
169 // Tell the keyboard controller we want to read the config byte.
170 // Need to wait for the controller to be ready first.
171 wait_write();
172 core::arch::asm!("out dx, al", in("dx") 0x64u16, in("al") 0x20u8,
173 options(nostack, preserves_flags));
174 wait_read();
175 let mut cfg: u8;
176 core::arch::asm!("in al, dx", out("al") cfg, in("dx") 0x60u16,
177 options(nostack, preserves_flags));
178
179 cfg |= 0x01; // enable keyboard interrupt
180
181 // Write config byte back
182 wait_write();
183 core::arch::asm!("out dx, al", in("dx") 0x64u16, in("al") 0x60u8,
184 options(nostack, preserves_flags));
185 wait_write();
186 core::arch::asm!("out dx, al", in("dx") 0x60u16, in("al") cfg,
187 options(nostack, preserves_flags));
188 }
189}
190
191/// Wait until the PS/2 controller is ready to receive a command.
192fn wait_write() {
193 unsafe {
194 loop {
195 let status: u8;
196 core::arch::asm!("in al, dx", out("al") status, in("dx") 0x64u16,
197 options(nostack, preserves_flags));
198 if status & 0x02 == 0 {
199 // Input buffer empty — controller ready to receive
200 break;
201 }
202 }
203 }
204}
205
206/// Wait until the PS/2 controller has data available to read.
207fn wait_read() {
208 unsafe {
209 loop {
210 let status: u8;
211 core::arch::asm!("in al, dx", out("al") status, in("dx") 0x64u16,
212 options(nostack, preserves_flags));
213 if status & 0x01 != 0 {
214 // Output buffer full — data ready to read
215 break;
216 }
217 }
218 }
164} 219}
165 220
166fn drain_input() { 221fn drain_input() {
@@ -184,18 +239,11 @@ fn drain_input() {
184/// this function pops and decodes them. 239/// this function pops and decodes them.
185pub fn poll_key() -> KeyEvent { 240pub fn poll_key() -> KeyEvent {
186 loop { 241 loop {
187 // Disable interrupts so the buffer-empty → hlt window is atomic.
188 unsafe { core::arch::asm!("cli", options(nostack, preserves_flags)); }
189
190 if let Some(byte) = crate::interrupts::read_scancode() { 242 if let Some(byte) = crate::interrupts::read_scancode() {
191 unsafe { core::arch::asm!("sti", options(nostack, preserves_flags)); }
192 if let Some(ev) = process_byte(byte) { 243 if let Some(ev) = process_byte(byte) {
193 return ev; 244 return ev;
194 } 245 }
195 } else { 246 } else {
196 // Re-enable and halt. If a keyboard IRQ arrived between the
197 // buffer check and `sti`, the CPU sees a pending interrupt
198 // and `hlt` returns immediately.
199 unsafe { 247 unsafe {
200 core::arch::asm!("sti; hlt", options(nostack, preserves_flags)); 248 core::arch::asm!("sti; hlt", options(nostack, preserves_flags));
201 } 249 }