#![allow(clippy::ptr_as_ptr)]
#![allow(clippy::borrow_as_ptr)]
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::cognitive_complexity)]
#![allow(clippy::map_unwrap_or)]
#![allow(clippy::useless_vec)]
#![allow(clippy::unnecessary_wraps)]
#![allow(clippy::redundant_clone)]
#![allow(clippy::unnecessary_map_or)]
#![allow(clippy::missing_fields_in_debug)]
#![allow(clippy::needless_lifetimes)]
#![allow(clippy::needless_collect)]
#![allow(mismatched_lifetime_syntaxes)]
pub mod error;
pub mod guest_mem;
pub mod queue;
pub mod split_queue;
pub use error::{Result, VirtioError};
pub use guest_mem::GuestMemWriter;
pub use queue::{AvailRing, Descriptor, UsedRing, VirtQueue};
pub use split_queue::{ChainIter, DescChain, SplitQueue, VirtqDesc};
pub use virtio_bindings;
#[derive(Clone)]
pub struct DeviceCtx {
pub mem: std::sync::Arc<GuestMemWriter>,
pub raise_irq: std::sync::Arc<dyn Fn(u32) + Send + Sync>,
}
impl std::fmt::Debug for DeviceCtx {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("DeviceCtx")
.field("mem_len", &self.mem.len())
.field("mem_gpa_base", &self.mem.gpa_base())
.field("raise_irq", &"<fn>")
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum VirtioDeviceId {
Net = 1,
Block = 2,
Console = 3,
Rng = 4,
Balloon = 5,
Scsi = 8,
Fs = 26,
Vsock = 19,
}
#[derive(Debug, Clone, Copy)]
pub struct DeviceStatus(u8);
impl DeviceStatus {
pub const ACKNOWLEDGE: u8 = virtio_bindings::virtio_config::VIRTIO_CONFIG_S_ACKNOWLEDGE as u8;
pub const DRIVER: u8 = virtio_bindings::virtio_config::VIRTIO_CONFIG_S_DRIVER as u8;
pub const DRIVER_OK: u8 = virtio_bindings::virtio_config::VIRTIO_CONFIG_S_DRIVER_OK as u8;
pub const FEATURES_OK: u8 = virtio_bindings::virtio_config::VIRTIO_CONFIG_S_FEATURES_OK as u8;
pub const DEVICE_NEEDS_RESET: u8 =
virtio_bindings::virtio_config::VIRTIO_CONFIG_S_NEEDS_RESET as u8;
pub const FAILED: u8 = virtio_bindings::virtio_config::VIRTIO_CONFIG_S_FAILED as u8;
#[must_use]
pub const fn new(status: u8) -> Self {
Self(status)
}
#[must_use]
pub const fn raw(&self) -> u8 {
self.0
}
#[must_use]
pub const fn has(&self, flag: u8) -> bool {
self.0 & flag != 0
}
pub const fn set(&mut self, flag: u8) {
self.0 |= flag;
}
pub const fn clear(&mut self, flag: u8) {
self.0 &= !flag;
}
}
pub trait VirtioDevice: Send + Sync {
fn device_id(&self) -> VirtioDeviceId;
fn features(&self) -> u64;
fn ack_features(&mut self, features: u64);
fn read_config(&self, offset: u64, data: &mut [u8]);
fn write_config(&mut self, offset: u64, data: &[u8]);
fn activate(&mut self) -> Result<()>;
fn reset(&mut self);
fn process_queue(
&mut self,
queue_idx: u16,
memory: &mut [u8],
queue_config: &QueueConfig,
) -> Result<Vec<(u16, u32)>> {
let _ = (queue_idx, memory, queue_config);
Ok(Vec::new())
}
}
#[derive(Debug, Default)]
pub struct QueueConfig {
pub desc_addr: u64,
pub avail_addr: u64,
pub used_addr: u64,
pub size: u16,
pub ready: bool,
pub gpa_base: u64,
}
#[cfg(test)]
mod tests {
use super::*;
use virtio_bindings::virtio_config;
use virtio_bindings::virtio_ids;
#[test]
fn device_id_values_match_virtio_bindings() {
assert_eq!(VirtioDeviceId::Net as u32, virtio_ids::VIRTIO_ID_NET);
assert_eq!(VirtioDeviceId::Block as u32, virtio_ids::VIRTIO_ID_BLOCK);
assert_eq!(
VirtioDeviceId::Console as u32,
virtio_ids::VIRTIO_ID_CONSOLE
);
assert_eq!(VirtioDeviceId::Rng as u32, virtio_ids::VIRTIO_ID_RNG);
assert_eq!(
VirtioDeviceId::Balloon as u32,
virtio_ids::VIRTIO_ID_BALLOON
);
assert_eq!(VirtioDeviceId::Scsi as u32, virtio_ids::VIRTIO_ID_SCSI);
assert_eq!(VirtioDeviceId::Fs as u32, virtio_ids::VIRTIO_ID_FS);
assert_eq!(VirtioDeviceId::Vsock as u32, virtio_ids::VIRTIO_ID_VSOCK);
}
#[test]
fn device_status_values_match_virtio_bindings() {
assert_eq!(
DeviceStatus::ACKNOWLEDGE as u32,
virtio_config::VIRTIO_CONFIG_S_ACKNOWLEDGE
);
assert_eq!(
DeviceStatus::DRIVER as u32,
virtio_config::VIRTIO_CONFIG_S_DRIVER
);
assert_eq!(
DeviceStatus::DRIVER_OK as u32,
virtio_config::VIRTIO_CONFIG_S_DRIVER_OK
);
assert_eq!(
DeviceStatus::FEATURES_OK as u32,
virtio_config::VIRTIO_CONFIG_S_FEATURES_OK
);
assert_eq!(
DeviceStatus::DEVICE_NEEDS_RESET as u32,
virtio_config::VIRTIO_CONFIG_S_NEEDS_RESET
);
assert_eq!(
DeviceStatus::FAILED as u32,
virtio_config::VIRTIO_CONFIG_S_FAILED
);
}
}