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); }