feat(keyboard): clean rewrite of PS/2 driver and restore full Unix shell

This commit is contained in:
RarDog
2026-09-02 16:02:37 +03:00
parent 99b7c81385
commit 9222cd639b
2 changed files with 349 additions and 176 deletions
+130 -157
View File
@@ -1,120 +1,44 @@
//! PS/2 Keyboard Driver (IRQ 1 & Direct Polling).
//! PS/2 Keyboard Driver (IRQ 1 & Polling fallback).
//!
//! Декодирует Scancodes (полная поддержка Set 1 и Set 2) и передаёт символы в шелл.
//! Полностью переписанный драйвер PS/2 клавиатуры для x86_64 (Scancode Set 1).
use spin::Mutex;
use x86_64::instructions::port::Port;
const KEYBOARD_STATUS_PORT: u16 = 0x64;
const KEYBOARD_DATA_PORT: u16 = 0x60;
const KBD_DATA_PORT: u16 = 0x60;
const KBD_STATUS_PORT: u16 = 0x64;
const KBD_CMD_PORT: u16 = 0x64;
static KEYBOARD_BUFFER: Mutex<KeyboardBuffer> = Mutex::new(KeyboardBuffer::new());
static KEYBOARD: Mutex<KeyboardState> = Mutex::new(KeyboardState::new());
fn wait_input_empty() {
unsafe {
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
for _ in 0..100_000 {
if (status.read() & 0x02) == 0 {
return;
}
core::hint::spin_loop();
}
}
}
fn wait_output_full() -> bool {
unsafe {
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
for _ in 0..100_000 {
if (status.read() & 0x01) != 0 {
return true;
}
core::hint::spin_loop();
}
false
}
}
/// Инициализировать контроллер PS/2 клавиатуры (включить порт 1, Set 1 и сканирование).
pub fn init() {
unsafe {
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
let mut data: Port<u8> = Port::new(KEYBOARD_DATA_PORT);
// 1. Включаем первый порт PS/2 (команда 0xAE)
wait_input_empty();
status.write(0xAE);
// 2. Читаем текущий байт конфигурации 8042 (команда 0x20)
wait_input_empty();
status.write(0x20);
let mut config = 0x47; // безопасное значение по умолчанию (Translation ON, IRQ1 ON)
if wait_output_full() {
config = data.read();
}
// Бит 0 = IRQ1 enable (1)
// Бит 4 = Port 1 clock disable (0 = enabled)
// Бит 6 = Port 1 translation to Set 1 (1 = enabled)
config |= 0b0100_0001;
config &= !0b0001_0000;
// 3. Записываем обновлённый байт конфигурации (команда 0x60)
wait_input_empty();
status.write(0x60);
wait_input_empty();
data.write(config);
// 4. Отправляем клавиатуре команду Enable Scanning (0xF4)
wait_input_empty();
data.write(0xF4);
if wait_output_full() {
let _ = data.read();
}
// 5. Очищаем приёмный буфер
for _ in 0..64 {
if (status.read() & 0x01) != 0 {
let _ = data.read();
} else {
break;
}
}
}
log::info!("[keyboard] PS/2 keyboard initialized (Translation to Set 1 & Scanning enabled)");
}
struct KeyboardBuffer {
buffer: [u8; 128],
struct KeyboardState {
buffer: [u8; 256],
head: usize,
tail: usize,
shift: bool,
caps_lock: bool,
ctrl: bool,
extended: bool,
release_next: bool,
}
impl KeyboardBuffer {
impl KeyboardState {
const fn new() -> Self {
KeyboardBuffer {
buffer: [0; 128],
Self {
buffer: [0; 256],
head: 0,
tail: 0,
shift: false,
caps_lock: false,
ctrl: false,
extended: false,
release_next: false,
}
}
fn push(&mut self, ch: u8) {
let next_head = (self.head + 1) % self.buffer.len();
if next_head != self.tail {
let next = (self.head + 1) % self.buffer.len();
if next != self.tail {
self.buffer[self.head] = ch;
self.head = next_head;
self.head = next;
}
}
@@ -129,36 +53,98 @@ impl KeyboardBuffer {
}
}
/// Извлечь символ из буфера клавиатуры (с аппаратным fallback-опросом порта 0x64/0x60).
pub fn pop_char() -> Option<u8> {
x86_64::instructions::interrupts::without_interrupts(|| {
// Опрашиваем аппаратный статус PS/2 (бит 0 = Output Buffer Full) и вычитываем всё
unsafe {
let mut status: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
let mut data: Port<u8> = Port::new(KEYBOARD_DATA_PORT);
for _ in 0..16 {
let s = status.read();
if s == 0xFF || (s & 0x01) == 0 {
break;
}
let scancode = data.read();
if scancode != 0xFF && scancode != 0x00 {
process_scancode(scancode);
}
/// Ожидание готовности порта ввода (bit 1 = 0).
fn wait_input() {
unsafe {
let mut status: Port<u8> = Port::new(KBD_STATUS_PORT);
for _ in 0..10_000 {
if (status.read() & 0x02) == 0 {
return;
}
core::hint::spin_loop();
}
}
}
/// Ожидание данных в порте вывода (bit 0 = 1).
fn wait_output() -> bool {
unsafe {
let mut status: Port<u8> = Port::new(KBD_STATUS_PORT);
for _ in 0..10_000 {
let s = status.read();
if s != 0xFF && (s & 0x01) != 0 {
return true;
}
core::hint::spin_loop();
}
false
}
}
/// Инициализация контроллера i8042 и PS/2 клавиатуры.
pub fn init() {
unsafe {
let mut cmd: Port<u8> = Port::new(KBD_CMD_PORT);
let mut data: Port<u8> = Port::new(KBD_DATA_PORT);
let mut status: Port<u8> = Port::new(KBD_STATUS_PORT);
// 1. Отключаем порты на время конфигурации
wait_input();
cmd.write(0xAD); // Disable Port 1
wait_input();
cmd.write(0xA7); // Disable Port 2
// 2. Очищаем остаточные данные в буфере
for _ in 0..16 {
if (status.read() & 0x01) != 0 {
let _ = data.read();
} else {
break;
}
}
KEYBOARD_BUFFER.lock().pop()
})
// 3. Читаем байт конфигурации 8042 (команда 0x20)
wait_input();
cmd.write(0x20);
let mut config = 0x47;
if wait_output() {
config = data.read();
}
// Бит 0 = прерывания IRQ1 (1)
// Бит 4 = такт порта 1 (0 = включён)
// Бит 6 = трансляция в Scancode Set 1 (1 = включена)
config |= 0b0100_0001;
config &= !0b0001_0000;
// 4. Записываем обновлённую конфигурацию (команда 0x60)
wait_input();
cmd.write(0x60);
wait_input();
data.write(config);
// 5. Включаем первый порт PS/2 (команда 0xAE)
wait_input();
cmd.write(0xAE);
// 6. Отправляем команду клавиатуре Enable Scanning (0xF4)
wait_input();
data.write(0xF4);
if wait_output() {
let _ack = data.read();
}
}
log::info!("[keyboard] PS/2 keyboard initialized (Set 1 translation active)");
}
/// Обработчик прерывания клавиатуры (IRQ 1).
/// Обработчик аппаратного прерывания клавиатуры (IRQ 1).
pub fn handle_interrupt() {
unsafe {
let mut status_port: Port<u8> = Port::new(KEYBOARD_STATUS_PORT);
let mut data_port: Port<u8> = Port::new(KEYBOARD_DATA_PORT);
let mut status_port: Port<u8> = Port::new(KBD_STATUS_PORT);
let mut data_port: Port<u8> = Port::new(KBD_DATA_PORT);
// Вычитываем ВСЕ доступные сканкоды из буфера 8042
for _ in 0..16 {
let s = status_port.read();
if s == 0xFF || (s & 0x01) == 0 {
@@ -172,48 +158,48 @@ pub fn handle_interrupt() {
}
}
/// Обработать один сканкод.
/// Извлечь символ из очереди клавиатуры.
pub fn pop_char() -> Option<u8> {
x86_64::instructions::interrupts::without_interrupts(|| {
unsafe {
let mut status_port: Port<u8> = Port::new(KBD_STATUS_PORT);
let mut data_port: Port<u8> = Port::new(KBD_DATA_PORT);
for _ in 0..16 {
let s = status_port.read();
if s == 0xFF || (s & 0x01) == 0 {
break;
}
let scancode = data_port.read();
if scancode != 0xFF && scancode != 0x00 {
process_scancode(scancode);
}
}
}
KEYBOARD.lock().pop()
})
}
/// Декодер Scancode Set 1.
fn process_scancode(scancode: u8) {
let mut kbd = KEYBOARD_BUFFER.lock();
let mut kbd = KEYBOARD.lock();
// Префикс расширенных клавиш
if scancode == 0xE0 {
kbd.extended = true;
return;
}
// Set 2 release prefix
if scancode == 0xF0 {
kbd.release_next = true;
return;
}
if kbd.release_next {
kbd.release_next = false;
if scancode == 0x12 || scancode == 0x59 { kbd.shift = false; }
if scancode == 0x14 { kbd.ctrl = false; }
return;
}
// Set 1 Modifiers
// Обработка модификаторов нажатия / отпускания
match scancode {
0x2A | 0x36 => { kbd.shift = true; return; } // Left/Right Shift pressed
0xAA | 0xB6 => { kbd.shift = false; return; } // Left/Right Shift released
0x1D => { kbd.ctrl = true; return; } // Ctrl pressed
0x9D => { kbd.ctrl = false; return; } // Ctrl released
0x2A | 0x36 => { kbd.shift = true; return; } // Left / Right Shift press
0xAA | 0xB6 => { kbd.shift = false; return; } // Left / Right Shift release
0x1D => { kbd.ctrl = true; return; } // Ctrl press
0x9D => { kbd.ctrl = false; return; } // Ctrl release
0x3A => { kbd.caps_lock = !kbd.caps_lock; return; } // CapsLock toggle
_ => {}
}
// Set 2 Modifiers
match scancode {
0x12 | 0x59 => { kbd.shift = true; return; } // Set 2 Shift
0x14 => { kbd.ctrl = true; return; } // Set 2 Ctrl
0x58 => { kbd.caps_lock = !kbd.caps_lock; return; } // Set 2 CapsLock
_ => {}
}
// Игнорируем отпускания клавиш в Set 1 (бит 7 установлен)
// Отпускания клавиш в Set 1 имеют бит 7 = 1 (scancode >= 0x80)
if scancode >= 0x80 {
kbd.extended = false;
return;
@@ -221,9 +207,7 @@ fn process_scancode(scancode: u8) {
let upper = kbd.shift ^ kbd.caps_lock;
// Декодирование Scancode Set 1
let ch = match scancode {
// Цифры верхнего ряда
0x02 => if kbd.shift { '!' } else { '1' },
0x03 => if kbd.shift { '@' } else { '2' },
0x04 => if kbd.shift { '#' } else { '3' },
@@ -236,14 +220,8 @@ fn process_scancode(scancode: u8) {
0x0B => if kbd.shift { ')' } else { '0' },
0x0C => if kbd.shift { '_' } else { '-' },
0x0D => if kbd.shift { '+' } else { '=' },
// Управляющие клавиши
0x0E => '\x08', // Backspace
0x0F => '\t', // Tab
0x1C => '\n', // Enter
0x39 => ' ', // Space
// Верхний буквенный ряд (QWERTY)
0x10 => if upper { 'Q' } else { 'q' },
0x11 => if upper { 'W' } else { 'w' },
0x12 => if upper { 'E' } else { 'e' },
@@ -256,8 +234,7 @@ fn process_scancode(scancode: u8) {
0x19 => if upper { 'P' } else { 'p' },
0x1A => if kbd.shift { '{' } else { '[' },
0x1B => if kbd.shift { '}' } else { ']' },
// Средний буквенный ряд (ASDF)
0x1C => '\n', // Enter
0x1E => if upper { 'A' } else { 'a' },
0x1F => if upper { 'S' } else { 's' },
0x20 => if upper { 'D' } else { 'd' },
@@ -271,8 +248,6 @@ fn process_scancode(scancode: u8) {
0x28 => if kbd.shift { '"' } else { '\'' },
0x29 => if kbd.shift { '~' } else { '`' },
0x2B => if kbd.shift { '|' } else { '\\' },
// Нижний буквенный ряд (ZXCV)
0x2C => if upper { 'Z' } else { 'z' },
0x2D => if upper { 'X' } else { 'x' },
0x2E => if upper { 'C' } else {
@@ -285,8 +260,7 @@ fn process_scancode(scancode: u8) {
0x33 => if kbd.shift { '<' } else { ',' },
0x34 => if kbd.shift { '>' } else { '.' },
0x35 => if kbd.shift { '?' } else { '/' },
// Keypad (NumPad)
0x39 => ' ', // Space
0x47 => '7',
0x48 => '8',
0x49 => '9',
@@ -300,7 +274,6 @@ fn process_scancode(scancode: u8) {
0x51 => '3',
0x52 => '0',
0x53 => '.',
_ => {
kbd.extended = false;
return;