Hardware device drivers — every piece of hardware EVO-OS talks to has a driver here.
Device drivers are the code that makes the kernel talk to real hardware — keyboards, displays, storage, network cards, USB. They are kept in a separate repo from the kernel for critical reasons:
- Independent development velocity — a driver bug shouldn't block a kernel release
- Independent versioning — drivers can be updated when hardware vendors release new specs without touching kernel internals
- Contributor isolation — driver authors need to know the kernel's
Drivertrait API, not kernel internals - Security boundary — in the future, drivers will run in isolated userspace processes (like in seL4 or Redox OS); keeping them separate now makes that migration easier
- Testing — drivers can be unit-tested with a mock hardware abstraction
This is the same pattern used by:
- Linux:
drivers/is separate fromkernel/in the source tree - Android:
vendor/drivers separate fromplatform/kernel - Windows NT: KMD (Kernel Mode Drivers) loaded at runtime, not compiled into the kernel
| Driver | Hardware | Interface |
|---|---|---|
ps2_keyboard |
PS/2 keyboard (IRQ 1) | Port I/O (0x60, 0x64) |
ps2_mouse |
PS/2 mouse (IRQ 12) | Port I/O (0x60, 0x64) |
usb_hid |
USB keyboards + mice | USB XHCI + HID class |
Keyboard driver (ps2_keyboard.rs):
- Reads scan codes from port 0x60 on IRQ 1
- Translates scan codes → keysyms → Unicode codepoints
- Posts events to the kernel's input event queue
| Driver | Hardware | Interface |
|---|---|---|
vga_text |
VGA text mode (80×25) | Memory-mapped 0xB8000 |
framebuffer |
UEFI GOP / VESA framebuffer | Memory-mapped from boot info |
virtio_gpu |
QEMU VirtIO GPU | VirtIO MMIO |
Framebuffer driver (framebuffer.rs):
- Gets base address, width, height, pitch from
BootInfo - Provides
draw_pixel(x, y, color)andblit_rect()primitives - Used by the GUI compositor as its rendering backend
| Driver | Hardware | Interface |
|---|---|---|
ata_pio |
ATA/SATA (legacy PIO) | Port I/O |
ata_dma |
ATA/SATA DMA (UDMA) | PCI + DMA |
nvme |
NVMe SSDs | PCIe MMIO |
virtio_blk |
QEMU VirtIO block | VirtIO MMIO |
NVMe driver (nvme.rs):
- Enumerates PCI devices looking for NVMe class (0x01, 0x08, 0x02)
- Sets up Admin and I/O submission/completion queue pairs
- Implements read/write as async commands via doorbell registers
| Driver | Hardware | Interface |
|---|---|---|
e1000 |
Intel 82540 (QEMU default) | PCI MMIO |
rtl8139 |
Realtek RTL8139 | PCI port I/O |
virtio_net |
QEMU VirtIO network | VirtIO MMIO |
Virtio-net driver (virtio_net.rs):
- Negotiates virtio feature flags with QEMU
- Sets up RX/TX virtqueues
- Posts received packets to the kernel's network stack
| Driver | Component | Notes |
|---|---|---|
xhci |
XHCI host controller | USB 3.0 stack |
hid |
HID class driver | Keyboard + mouse via USB |
mass_storage |
USB Mass Storage class | USB flash drives |
| Driver | Purpose |
|---|---|
pit |
Programmable Interval Timer — scheduling ticks (IRQ 0) |
rtc |
Real Time Clock — wall clock time |
acpi |
ACPI power management, sleep states |
pci |
PCI bus enumeration and device discovery |
All drivers implement the Driver trait from the kernel:
use kernel::drivers::{Driver, DriverError, IrqHandler};
pub struct Ps2KeyboardDriver {
event_queue: EventQueue<KeyEvent>,
}
impl Driver for Ps2KeyboardDriver {
fn name(&self) -> &'static str { "ps2_keyboard" }
fn init(&mut self) -> Result<(), DriverError> {
// Send init commands to keyboard controller
port_write(0x64, 0xAE); // Enable PS/2 port 1
port_write(0x60, 0xF4); // Enable keyboard scanning
// Register our interrupt handler for IRQ 1
kernel::irq::register(1, self.handle_irq)?;
Ok(())
}
fn shutdown(&mut self) -> Result<(), DriverError> {
kernel::irq::deregister(1)
}
}
impl IrqHandler for Ps2KeyboardDriver {
fn handle_irq(&mut self) {
let scancode = unsafe { port_read(0x60) };
if let Some(key) = translate_scancode(scancode) {
self.event_queue.push(key);
}
kernel::pic::send_eoi(1); // Acknowledge interrupt
}
}Drivers MUST access hardware through the BSP HAL, not through raw port I/O in driver code:
// ❌ Don't do this — ties driver to x86
unsafe { core::arch::asm!("out dx, al", in("dx") port, in("al") value); }
// ✅ Do this — BSP provides platform-correct implementation
bsp::io::port_write_u8(port, value);This ensures drivers compile and work on ARM (which has no IN/OUT instructions) and future architectures.
# Build all drivers
cargo build --release --target x86_64-unknown-none
# Build a specific driver crate
cargo build -p evo-driver-nvme --release
# Run driver unit tests (with mock hardware)
cargo test -p evo-driver-ps2-keyboardEach driver has a mock_hw feature that replaces port I/O with an in-memory mock:
cargo test --features mock_hw# Run full OS with all drivers in QEMU
make qemu-test- Create
src/<category>/<driver_name>.rs - Implement the
Drivertrait and any device-class trait (BlockDevice,NetworkDevice, etc.) - Register in
src/lib.rsdriver registry - Write a mock hardware unit test
- Document in
docs/DRIVER_MODEL.md
| Repo | Relationship |
|---|---|
| Kernel | drivers implement kernel's Driver trait |
| bsp | drivers use BSP HAL for port I/O and MMIO |
| GUI | GUI uses framebuffer driver as rendering backend |
| filesystem | filesystem uses storage drivers for disk access |
docs/DRIVER_MODEL.md— Driver API reference- OSDev Wiki — Keyboard
- OSDev Wiki — ATA PIO
- NVMe Specification
- Virtio Specification