summaryrefslogtreecommitdiffstats
path: root/src/ps2.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-07-31 02:28:10 +0200
committersalmonik <salmonik@tuta.io>2026-07-31 02:28:10 +0200
commitaf8d5aa4538ac71f11a5418ef94ae478868a0484 (patch)
treec235d89cbdd1486dd2239d08abc750be2e5a88d2 /src/ps2.rs
parentInitial commit: raisernics toy kernel (diff)
downloadrs-dos-af8d5aa4538ac71f11a5418ef94ae478868a0484.tar.gz
rs-dos-af8d5aa4538ac71f11a5418ef94ae478868a0484.zip
interrupts: IDT, PIC remap, PIT timer, PS/2 keyboard IRQ
- 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<dyn Error>> return type - tools/qemu.sh: fix SC2207 shellcheck warning
Diffstat (limited to 'src/ps2.rs')
-rw-r--r--src/ps2.rs55
1 files changed, 21 insertions, 34 deletions
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() {
179 } 179 }
180} 180}
181 181
182/// Poll for a key event. Blocks until a key is pressed. 182/// Poll for a key event. Blocks via `hlt` until a key is pressed.
183/// The keyboard interrupt handler pushes raw scancodes to a ring buffer;
184/// this function pops and decodes them.
183pub fn poll_key() -> KeyEvent { 185pub fn poll_key() -> KeyEvent {
184 loop { 186 loop {
185 let byte = read_data(); 187 // Disable interrupts so the buffer-empty → hlt window is atomic.
186 if let Some(ev) = process_byte(byte) { 188 unsafe { core::arch::asm!("cli", options(nostack, preserves_flags)); }
187 return ev;
188 }
189 }
190}
191 189
192/// Non-blocking poll. 190 if let Some(byte) = crate::interrupts::read_scancode() {
193pub fn try_poll_key() -> Option<KeyEvent> { 191 unsafe { core::arch::asm!("sti", options(nostack, preserves_flags)); }
194 unsafe { 192 if let Some(ev) = process_byte(byte) {
195 let status: u8; 193 return ev;
196 core::arch::asm!("in al, dx", out("al") status, in("dx") STATUS_PORT, 194 }
197 options(nostack, preserves_flags)); 195 } else {
198 if status & STAT_OUTPUT_FULL == 0 { 196 // Re-enable and halt. If a keyboard IRQ arrived between the
199 return None; 197 // buffer check and `sti`, the CPU sees a pending interrupt
198 // and `hlt` returns immediately.
199 unsafe {
200 core::arch::asm!("sti; hlt", options(nostack, preserves_flags));
201 }
200 } 202 }
201 let data: u8;
202 core::arch::asm!("in al, dx", out("al") data, in("dx") DATA_PORT,
203 options(nostack, preserves_flags));
204 process_byte(data)
205 } 203 }
206} 204}
207 205
208/// Read a byte from the keyboard data port (blocking). 206/// Non-blocking poll — read from the interrupt ring buffer if available.
209fn read_data() -> u8 { 207pub fn try_poll_key() -> Option<KeyEvent> {
210 unsafe { 208 let byte = crate::interrupts::read_scancode()?;
211 loop { 209 process_byte(byte)
212 let status: u8;
213 core::arch::asm!("in al, dx", out("al") status, in("dx") STATUS_PORT,
214 options(nostack, preserves_flags));
215 if status & STAT_OUTPUT_FULL != 0 {
216 let data: u8;
217 core::arch::asm!("in al, dx", out("al") data, in("dx") DATA_PORT,
218 options(nostack, preserves_flags));
219 return data;
220 }
221 }
222 }
223} 210}
224 211
225/// Process a single scancode byte. Returns Some(KeyEvent) when a visible 212/// Process a single scancode byte. Returns Some(KeyEvent) when a visible