Files
k-os/crates/hw-virtio/src/mmio.rs

75 lines
2.6 KiB
Rust

use types::address::ByteOffset;
pub trait MmioAccess {
fn read(&self, offset: ByteOffset) -> u32;
fn write(&self, offset: ByteOffset, val: u32);
}
pub const MAGIC: u32 = 0x74726976;
pub const REG_MAGIC: ByteOffset = ByteOffset::new(0x000);
pub const REG_VERSION: ByteOffset = ByteOffset::new(0x004);
pub const REG_DEVICE_ID: ByteOffset = ByteOffset::new(0x008);
pub const REG_STATUS: ByteOffset = ByteOffset::new(0x070);
pub const REG_GUEST_PAGE_SIZE: ByteOffset = ByteOffset::new(0x028);
pub const REG_FEATURES_SEL: ByteOffset = ByteOffset::new(0x014);
pub const REG_FEATURES: ByteOffset = ByteOffset::new(0x010);
pub const REG_DRIVER_FEATURES_SEL: ByteOffset = ByteOffset::new(0x024);
pub const REG_DRIVER_FEATURES: ByteOffset = ByteOffset::new(0x020);
pub const REG_QUEUE_SEL: ByteOffset = ByteOffset::new(0x030);
pub const REG_QUEUE_NUM_MAX: ByteOffset = ByteOffset::new(0x034);
pub const REG_QUEUE_NUM: ByteOffset = ByteOffset::new(0x038);
pub const REG_QUEUE_PFN: ByteOffset = ByteOffset::new(0x040);
pub const REG_QUEUE_NOTIFY: ByteOffset = ByteOffset::new(0x050);
pub const REG_INTERRUPT_STATUS: ByteOffset = ByteOffset::new(0x060);
pub const REG_INTERRUPT_ACK: ByteOffset = ByteOffset::new(0x064);
pub const STATUS_ACK: u32 = 1;
pub const STATUS_DRIVER: u32 = 2;
pub const STATUS_DRIVER_OK: u32 = 4;
pub const DEVICE_ID_BLOCK: u32 = 2;
pub const DEVICE_ID_GPU: u32 = 16;
pub const DEVICE_ID_INPUT: u32 = 18;
pub const PAGE_SIZE: usize = 4096;
/// A virtio-mmio device's registers: 32-bit accesses at register offsets.
pub struct Registers(libkos::Window);
impl Registers {
pub fn new(window: libkos::Window) -> Self {
Self(window)
}
}
impl MmioAccess for Registers {
fn read(&self, offset: ByteOffset) -> u32 {
self.0.read(offset)
}
fn write(&self, offset: ByteOffset, val: u32) {
self.0.write(offset, val)
}
}
pub fn init_legacy_device(mmio: &impl MmioAccess, queue: types::address::PhysicalAddress, queue_size: u32) {
mmio.write(REG_STATUS, 0);
while mmio.read(REG_STATUS) != 0 {}
mmio.write(REG_STATUS, STATUS_ACK);
mmio.write(REG_STATUS, mmio.read(REG_STATUS) | STATUS_DRIVER);
mmio.write(REG_GUEST_PAGE_SIZE, PAGE_SIZE as u32);
mmio.write(REG_FEATURES_SEL, 0);
mmio.write(REG_DRIVER_FEATURES_SEL, 0);
mmio.write(REG_DRIVER_FEATURES, 0);
mmio.write(REG_QUEUE_SEL, 0);
let queue_max = mmio.read(REG_QUEUE_NUM_MAX);
mmio.write(REG_QUEUE_NUM, queue_size.min(queue_max));
mmio.write(REG_QUEUE_PFN, (queue.raw() / PAGE_SIZE) as u32);
mmio.write(REG_STATUS, mmio.read(REG_STATUS) | STATUS_DRIVER_OK);
}