diff options
| author | salmonik <salmonik@tuta.io> | 2026-07-31 02:28:10 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-07-31 02:28:10 +0200 |
| commit | af8d5aa4538ac71f11a5418ef94ae478868a0484 (patch) | |
| tree | c235d89cbdd1486dd2239d08abc750be2e5a88d2 /src/ps2.rs | |
| parent | Initial commit: raisernics toy kernel (diff) | |
| download | rs-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.rs | 55 |
1 files changed, 21 insertions, 34 deletions
| @@ -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. | ||
| 183 | pub fn poll_key() -> KeyEvent { | 185 | pub 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() { |
| 193 | pub 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. |
| 209 | fn read_data() -> u8 { | 207 | pub 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 |
