75 lines
2.6 KiB
Rust
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);
|
|
}
|