From 100ff9abd4754c8c5783da1414706d7a17e1ba79 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 16:33:00 +1000 Subject: [PATCH] virtio: add `check_device_feature` and `ack_driver_feature` for `StandardTransport`. Signed-off-by: Anhad Singh --- virtiod/src/lib.rs | 18 +++++++++--------- virtiod/src/main.rs | 22 ++++++++++++++++------ virtiod/src/transport.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 virtiod/src/transport.rs diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs index ee0658c079..ee820f957a 100644 --- a/virtiod/src/lib.rs +++ b/virtiod/src/lib.rs @@ -3,6 +3,8 @@ use core::cell::UnsafeCell; use static_assertions::const_assert_eq; +pub mod transport; + #[derive(Debug, Copy, Clone)] #[repr(u8)] pub enum CfgType { @@ -116,16 +118,14 @@ pub struct Descriptor { const_assert_eq!(core::mem::size_of::(), 16); +/// This indicates compliance with the version 1 VirtIO specification. +/// +/// See `6.1 Driver Requirements: Reserved Feature Bits` section of the VirtIO +/// specification for more information. +pub const VIRTIO_F_VERSION_1: u32 = 32; + pub struct VirtQueue {} -pub struct StandardTransport {} - -impl StandardTransport { - pub fn new() -> Self { - Self {} - } -} - #[derive(Debug)] #[repr(transparent)] pub struct VolatileCell { @@ -141,7 +141,7 @@ impl VolatileCell { /// Sets the contained value. #[inline] - pub fn set(&self, value: T) { + pub fn set(&mut self, value: T) { unsafe { core::ptr::write_volatile(self.value.get(), value) } } } diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index fb5f55de73..31761b29f2 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -2,6 +2,8 @@ use core::ptr::NonNull; use static_assertions::const_assert_eq; use thiserror::Error; + +use virtiod::transport::StandardTransport; use virtiod::*; use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; @@ -14,11 +16,14 @@ use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; // TODO(andypython): // -// cc 3.1.1 Driver Requirements: Device Initialization -// Reset the device. -// Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. [done] -// Set the DRIVER status bit: the guest OS knows how to drive the device. [done] -// setup interrupts [done] +// cc 3.1.1 Driver Requirements: Device Initialization +// +// ================ Generic ================= +// * Reset the device. [done] +// * Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. [done] +// * Set the DRIVER status bit: the guest OS knows how to drive the device. [done] +// * setup interrupts [done] +// =============== Driver Specific=============== // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. @@ -313,7 +318,12 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { log::info!("virtio: using standard PCI transport"); - let _transport = StandardTransport::new(); + let mut transport = StandardTransport::new(pci_header, common); + + // Check VirtIO version 1 compliance. + assert!(transport.check_device_feature(VIRTIO_F_VERSION_1)); + transport.ack_driver_feature(VIRTIO_F_VERSION_1); + loop {} } diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs new file mode 100644 index 0000000000..3141e135b8 --- /dev/null +++ b/virtiod/src/transport.rs @@ -0,0 +1,28 @@ +use pcid_interface::PciHeader; + +use crate::CommonCfg; + +pub struct StandardTransport<'a> { + header: PciHeader, + common: &'a mut CommonCfg, +} + +impl<'a> StandardTransport<'a> { + pub fn new(header: PciHeader, common: &'a mut CommonCfg) -> Self { + Self { header, common } + } + + pub fn check_device_feature(&mut self, feature: u32) -> bool { + self.common.device_feature_select.set(feature >> 5); + (self.common.device_feature.get() & (1 << (feature & 31))) != 0 + } + + pub fn ack_driver_feature(&mut self, feature: u32) { + self.common.driver_feature_select.set(feature >> 5); + + let current = self.common.driver_feature.get(); + self.common + .driver_feature + .set(current | (1 << (feature & 31))); + } +}