Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
aab2b9d
ps2-controller: add low-level port I/O primitives and basic read/writ…
domnudragota Jul 14, 2025
390354b
ps2-controller: add Ps2Controller stub, wire into PcComponent and IRQ…
domnudragota Jul 14, 2025
a8e6aa6
ps2-controller: implement minimal init sequence
domnudragota Jul 14, 2025
749f809
workflow: restructured ps2.rs, added buffer and better interupt calls
domnudragota Jul 15, 2025
6436ae9
ps2: full init + self-test + PIC-unmask
domnudragota Jul 15, 2025
a4ef9c6
feature: Added Hil to the PS2 Driver
Jul 15, 2025
e52a5f6
fix: ran make prepush and fixed the reported issues
domnudragota Jul 16, 2025
279fa1c
feature: added init files 4 keyboard
Jul 16, 2025
e791cca
feature: Updated dv_kb.rs + set up hil connection
Jul 17, 2025
f715b5c
feature: Removed hil ps2_kb.rs and tranfurred functions in ps2_traits…
Jul 17, 2025
1828ff3
feature: PS/2 Keyboard: implement full Set-2 decoder
domnudragota Jul 18, 2025
d6c6154
feature:PS/2 keyboard: implement Phase 2 bottom-half pump, event FIFO…
domnudragota Jul 18, 2025
c33464f
PS/2: add ps2_cmd helper with shared ACK/RESEND retry logic
domnudragota Jul 18, 2025
19f0816
PS/2: feature: refactor command helpers to common ps2_cmd::send() and…
domnudragota Jul 18, 2025
4d0cbfd
feature: add keyboard init helper + functions
domnudragota Jul 23, 2025
fe276a5
fix: removed risky ref to static_mut from main.rs
domnudragota Jul 23, 2025
8ea3003
workflow: ran make prepush
domnudragota Jul 23, 2025
eae38cb
feature add: mouse driver skeleton
Jul 23, 2025
201c47a
feature: Fixed implement issue
Jul 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions boards/qemu_i486_q35/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@
// https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)]

use core::ptr;

use capsules_core::alarm;
use capsules_core::console::{self, Console};
use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
use components::console::ConsoleComponent;
use components::debug_writer::DebugWriterComponent;
use core::ptr;
use kernel::capabilities;
use kernel::component::Component;
use kernel::debug;
Expand All @@ -28,11 +27,11 @@ use kernel::process::ProcessArray;
use kernel::scheduler::cooperative::CooperativeSched;
use kernel::syscall::SyscallDriver;
use kernel::{create_capability, static_init};

use x86::registers::bits32::paging::{PDEntry, PTEntry, PD, PT};
use x86::registers::irq;

use x86_q35::dv_kb::Keyboard;
use x86_q35::pit::{Pit, RELOAD_1KHZ};
use x86_q35::ps2::Ps2Controller;
use x86_q35::{Pc, PcComponent};

mod multiboot;
Expand Down Expand Up @@ -76,6 +75,15 @@ pub static mut PAGE_DIR: PD = [PDEntry(0); 1024];
#[link_section = ".pte"]
pub static mut PAGE_TABLE: PT = [PTEntry(0); 1024];

#[no_mangle]
pub static mut PS2: core::mem::MaybeUninit<Ps2Controller<'static>> =
core::mem::MaybeUninit::uninit();

/// Keyboard object used by chip.rs
#[no_mangle]
pub static mut KEYBOARD: core::mem::MaybeUninit<Keyboard<'static, Ps2Controller<'static>>> =
core::mem::MaybeUninit::uninit();

pub struct QemuI386Q35Platform {
pconsole: &'static capsules_core::process_console::ProcessConsole<
'static,
Expand Down Expand Up @@ -153,13 +161,29 @@ impl<C: Chip> KernelResources<C> for QemuI386Q35Platform {

#[no_mangle]
unsafe extern "cdecl" fn main() {
// ---------- BASIC INITIALIZATION -----------
// -------- PS/2 controller & keyboard --------
let ps2_ctrl: &'static Ps2Controller = {
let ctrl_mut: &'static mut Ps2Controller =
static_init!(Ps2Controller<'static>, Ps2Controller::new());
x86_q35::ps2_ctl::init_controller::<Ps2Controller<'static>>()
.expect("PS/2 controller init failed");
ctrl_mut
};

let kb_val: Keyboard<'static, Ps2Controller> = {
let kb = Keyboard::new(ps2_ctrl);
kb.init().expect("Keyboard init failed");
kb
};
let slot: *mut Keyboard<'static, Ps2Controller> = core::ptr::addr_of_mut!(KEYBOARD).cast();
ptr::write(slot, kb_val);

// Basic setup of the i486 platform
// -------- Chip initialisation --------
let chip = PcComponent::new(
&mut *ptr::addr_of_mut!(PAGE_DIR),
&mut *ptr::addr_of_mut!(PAGE_TABLE),
)
.with_ps2(ps2_ctrl)
.finalize(x86_q35::x86_q35_component_static!());

// Acquire required capabilities
Expand Down
92 changes: 75 additions & 17 deletions capsules/core/src/process_console.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const ESC: u8 = b'\x1B';
const EOL: u8 = b'\x00';

/// Backspace ANSI character
const BS: u8 = b'\x08';
const BACKSPACE: u8 = b'\x08';

/// Delete ANSI character
const DEL: u8 = b'\x7F';
Expand Down Expand Up @@ -103,6 +103,7 @@ enum EscKey {
Home,
End,
Delete,
Backspace,
}

/// Escape state machine to check if
Expand Down Expand Up @@ -144,7 +145,7 @@ enum EscState {
impl EscState {
fn next_state(self, data: u8) -> Self {
use self::{
EscKey::{Delete, Down, End, Home, Left, Right, Up},
EscKey::{Backspace, Delete, Down, End, Home, Left, Right, Up},
EscState::{
Bracket, Bracket3, Bypass, Complete, Started, Unrecognized, UnrecognizedDone,
},
Expand All @@ -153,7 +154,7 @@ impl EscState {
(Bypass, ESC) | (UnrecognizedDone, ESC) | (Complete(_), ESC) => Started,
// This is a short-circuit.
// ASCII DEL and ANSI Escape Sequence "Delete" should be treated the same way.
(Bypass, DEL) | (UnrecognizedDone, DEL) | (Complete(_), DEL) => Complete(Delete),
(Bypass, DEL) | (UnrecognizedDone, DEL) | (Complete(_), DEL) => Complete(Backspace),
(Bypass, _) | (UnrecognizedDone, _) | (Complete(_), _) => Bypass,
(Started, b'[') => Bracket,
(Bracket, b'A') => Complete(Up),
Expand Down Expand Up @@ -1227,7 +1228,8 @@ impl<

// Clear the displayed command
for _ in 0..index {
let _ = self.write_bytes(&[BS, SPACE, BS]);
let _ = self
.write_bytes(&[BACKSPACE, SPACE, BACKSPACE]);
}

// Display the new command
Expand All @@ -1245,7 +1247,7 @@ impl<
});
}
EscKey::Left if cursor > 0 => {
let _ = self.write_byte(BS);
let _ = self.write_byte(BACKSPACE);
self.cursor.set(cursor - 1);
}
EscKey::Right if cursor < index => {
Expand All @@ -1254,7 +1256,7 @@ impl<
}
EscKey::Home if cursor > 0 => {
for _ in 0..cursor {
let _ = self.write_byte(BS);
let _ = self.write_byte(BACKSPACE);
}

self.cursor.set(0);
Expand All @@ -1266,6 +1268,62 @@ impl<

self.cursor.set(index);
}
EscKey::Backspace if cursor > 0 && cursor <= index => {
// Move the bytes one position to left
for i in (cursor - 1)..index {
command[i] = command[i + 1];
let _ = self.write_byte(command[i]);
}

// Now that we copied all bytes to the left, we are left over with
// a duplicate "ghost" character of the last byte,
// In case we deleted the first character, this doesn't do anything as
// the duplicate is not there.
// |abcdef -> abcdef (won't enter this match case)
// a|bcdef -> bcdef
// abc|def -> abdeff -> abdef

let _ = self.write_bytes(&[BACKSPACE, SPACE, BACKSPACE]);

// The following for statements are mandatory for correctly displaying
// the command and cursor
//
// Move the cursor to the correct position (without this,
// it will get sent all the way right)
for _ in (cursor - 1)..(index - 1) {
let _ = self.write_byte(BACKSPACE);
}
// Rewrite the command, this will move the cursor right (skipping this
// step will cause the command to not get updated correctly, for example
// abc|def -> ab|cde. This is just a visual mismatch)
for i in (cursor - 1)..(index - 1) {
let _ = self.write_byte(command[i]);
}
// Move the cursor left again (previously, the cursor was sent to the
// right by the previous for statement, so we need to move it left)
for _ in (cursor - 1)..(index - 1) {
let _ = self.write_byte(BACKSPACE);
}

self.cursor.set(cursor - 1);
self.command_index.set(index - 1);

// Remove the byte from the command in order
// not to permit accumulation of the text
if COMMAND_HISTORY_LEN > 1 {
self.command_history.map(|ht| {
if ht.cmd_is_modified {
// Copy the last command into the unfinished command

ht.cmds[0].clear();
ht.write_to_first(command);
ht.cmd_is_modified = false;
} else {
ht.cmds[0].delete_byte(cursor);
}
});
}
}
EscKey::Delete if cursor < index => {
// Move the bytes one position to left
for i in cursor..(index - 1) {
Expand All @@ -1276,16 +1334,16 @@ impl<
command[index - 1] = command[index];

// Now that we copied all bytes to the left, we are left over with
// a dublicate "ghost" character of the last byte,
// a duplicate "ghost" character of the last byte,
// In case we deleted the first character, this doesn't do anything as
// the dublicate is not there.
// the duplicate is not there.
// |abcdef -> bcdef
// abc|def -> abceff -> abcef
let _ = self.write_bytes(&[SPACE, BS]);
let _ = self.write_bytes(&[SPACE, BACKSPACE]);

// Move the cursor to last position
for _ in cursor..(index - 1) {
let _ = self.write_byte(BS);
let _ = self.write_byte(BACKSPACE);
}

self.command_index.set(index - 1);
Expand Down Expand Up @@ -1329,12 +1387,12 @@ impl<
});
}
}
} else if read_buf[0] == BS {
} else if read_buf[0] == BACKSPACE {
if cursor > 0 {
// Backspace, echo and remove the byte
// preceding the cursor
// Note echo is '\b \b' to erase
let _ = self.write_bytes(&[BS, SPACE, BS]);
let _ = self.write_bytes(&[BACKSPACE, SPACE, BACKSPACE]);

// Move the bytes one position to left
for i in (cursor - 1)..(index - 1) {
Expand All @@ -1345,16 +1403,16 @@ impl<
command[index - 1] = command[index];

// Now that we copied all bytes to the left, we are left over with
// a dublicate "ghost" character of the last byte,
// a duplicate "ghost" character of the last byte,
// In case we deleted the last character, this doesn't do anything as
// the dublicate is not there.
// the duplicate is not there.
// abcdef| -> abcdef
// abcd|ef -> abceff -> abcef
let _ = self.write_bytes(&[SPACE, BS]);
let _ = self.write_bytes(&[SPACE, BACKSPACE]);

// Move the cursor to last position
for _ in cursor..index {
let _ = self.write_byte(BS);
let _ = self.write_byte(BACKSPACE);
}

self.command_index.set(index - 1);
Expand Down Expand Up @@ -1399,7 +1457,7 @@ impl<

// Move the cursor to the last position
for _ in cursor..index {
let _ = self.write_byte(BS);
let _ = self.write_byte(BACKSPACE);
}

command[cursor] = read_buf[0];
Expand Down
33 changes: 30 additions & 3 deletions chips/x86_q35/src/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@

use core::fmt::Write;
use core::mem::MaybeUninit;

use kernel::component::Component;
use kernel::hil::ps2_traits::PS2Traits;
use kernel::platform::chip::Chip;

use x86::mpu::PagingMPU;
use x86::registers::bits32::paging::{PD, PT};
use x86::support;
use x86::{Boundary, InterruptPoller};

use crate::dv_kb::Keyboard;
use crate::pit::{Pit, RELOAD_1KHZ};
use crate::serial::{SerialPort, SerialPortComponent, COM1_BASE, COM2_BASE, COM3_BASE, COM4_BASE};
extern "Rust" {
/// Global keyboard object instantiated in the board setup
static KEYBOARD: Keyboard<'static, crate::ps2::Ps2Controller<'static>>;
}

/// Interrupt constants for legacy PC peripherals
mod interrupt {
Expand All @@ -28,6 +32,9 @@ mod interrupt {

/// Interrupt number shared by COM1 and COM3 serial devices
pub(super) const COM1_COM3: u32 = (PIC1_OFFSET as u32) + 4;

/// Interrupt number for PS/2 keyboard (IRQ1)
pub(super) const KEYBOARD: u32 = (PIC1_OFFSET as u32) + 1;
}

/// Representation of a generic PC platform.
Expand All @@ -53,6 +60,9 @@ pub struct Pc<'a, const PR: u16 = RELOAD_1KHZ> {
/// Legacy PIT timer
pub pit: Pit<'a, PR>,

/// PS/2 controller (keyboard/mouse)
pub ps2: &'a crate::ps2::Ps2Controller<'a>,

/// System call context
syscall: Boundary,
paging: PagingMPU<'a>,
Expand Down Expand Up @@ -82,6 +92,13 @@ impl<'a, const PR: u16> Chip for Pc<'a, PR> {
self.com1.handle_interrupt();
self.com3.handle_interrupt();
}
interrupt::KEYBOARD => {
let _ = self.ps2.handle_interrupt();
// decode + queue KeyEvent
unsafe {
KEYBOARD.poll();
}
}
_ => unimplemented!("interrupt {num}"),
}

Expand Down Expand Up @@ -163,6 +180,7 @@ impl<'a, const PR: u16> Chip for Pc<'a, PR> {
pub struct PcComponent<'a> {
pd: &'a mut PD,
pt: &'a mut PT,
ps2: Option<&'a crate::ps2::Ps2Controller<'a>>,
}

impl<'a> PcComponent<'a> {
Expand All @@ -178,7 +196,13 @@ impl<'a> PcComponent<'a> {
///
/// See [`x86::init`] for further details.
pub unsafe fn new(pd: &'a mut PD, pt: &'a mut PT) -> Self {
Self { pd, pt }
Self { pd, pt, ps2: None }
}

/// Provide the PS/2 controller instance so `Pc` can dispatch IRQ1.
pub fn with_ps2(mut self, ps2: &'a crate::ps2::Ps2Controller<'a>) -> Self {
self.ps2 = Some(ps2);
self
}
}

Expand Down Expand Up @@ -217,12 +241,15 @@ impl Component for PcComponent<'static> {

let syscall = Boundary::new();

let ps2 = self.ps2.expect("PcComponent.with_ps2 not called");

let pc = s.4.write(Pc {
com1,
com2,
com3,
com4,
pit,
ps2,
syscall,
paging,
});
Expand Down
Loading
Loading