Skip to content

Commit

Permalink
refactor(virtio): migrate virtio-fs to VirtioFsF
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Kröning <[email protected]>
  • Loading branch information
mkroening committed May 15, 2024
1 parent d0610b7 commit d79daa1
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 303 deletions.
314 changes: 14 additions & 300 deletions src/drivers/fs/virtio_fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ use alloc::string::{String, ToString};
use alloc::vec::Vec;

use pci_types::InterruptLine;
use virtio_def::features::VirtioF;
use virtio_def::features::VirtioFsF;

use self::constants::{FeatureSet, Features};
use crate::config::VIRTIO_MAX_QUEUE_SIZE;
#[cfg(feature = "pci")]
use crate::drivers::fs::virtio_pci::FsDevCfgRaw;
Expand All @@ -25,7 +24,7 @@ use crate::fs::fuse::{self, FuseInterface};
pub(crate) struct FsDevCfg {
pub raw: &'static FsDevCfgRaw,
pub dev_id: u16,
pub features: FeatureSet,
pub features: VirtioFsF,
}

/// Virtio file system driver struct.
Expand Down Expand Up @@ -56,28 +55,12 @@ impl VirtioFsDriver {

/// Negotiates a subset of features, understood and wanted by both the OS
/// and the device.
fn negotiate_features(&mut self, wanted_features: &[Features]) -> Result<(), VirtioFsError> {
let mut driver_features = FeatureSet::new(0);
fn negotiate_features(&mut self, driver_features: VirtioFsF) -> Result<(), VirtioFsError> {
let device_features = VirtioFsF::from(self.com_cfg.dev_features());

for feature in wanted_features.iter() {
driver_features |= *feature;
}

let device_features = FeatureSet::new(self.com_cfg.dev_features().bits() as u64);

// Checks if the selected feature set is compatible with requirements for
// features according to Virtio spec. v1.1 - 5.11.3.
match FeatureSet::check_features(wanted_features) {
Ok(_) => {
debug!("Feature set wanted by filesystem driver are in conformance with specification.")
}
Err(fs_err) => return Err(fs_err),
}

if (device_features & driver_features) == driver_features {
if device_features.contains(driver_features) {
// If device supports subset of features write feature set to common config
self.com_cfg
.set_drv_features(VirtioF::from_bits_retain(u64::from(driver_features).into()));
self.com_cfg.set_drv_features(driver_features.into());
Ok(())
} else {
Err(VirtioFsError::IncompatibleFeatureSets(
Expand All @@ -102,8 +85,8 @@ impl VirtioFsDriver {
// Indicate device, that driver is able to handle it
self.com_cfg.set_drv();

let features: Vec<Features> = vec![Features::VIRTIO_F_VERSION_1];
self.negotiate_features(&features)?;
let features = VirtioFsF::VERSION_1;
self.negotiate_features(features)?;

// Indicates the device, that the current feature set is final for the driver
// and will not be changed.
Expand All @@ -116,7 +99,7 @@ impl VirtioFsDriver {
self.dev_cfg.dev_id
);
// Set feature set in device config fur future use.
self.dev_cfg.features.set_features(&features);
self.dev_cfg.features = features;
} else {
return Err(VirtioFsError::FailFeatureNeg(self.dev_cfg.dev_id));
}
Expand All @@ -135,7 +118,7 @@ impl VirtioFsDriver {
&self.notif_cfg,
VqSize::from(VIRTIO_MAX_QUEUE_SIZE),
VqIndex::from(i),
VirtioF::from_bits_retain(u64::from(self.dev_cfg.features).into()),
self.dev_cfg.features.into(),
)
.unwrap();
self.vqueues.push(Rc::new(vq));
Expand Down Expand Up @@ -176,278 +159,9 @@ impl FuseInterface for VirtioFsDriver {
}
}

pub mod constants {
use alloc::vec::Vec;
use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign};

pub use super::error::VirtioFsError;

/// Enum contains virtio's filesystem device features and general features of Virtio.
///
/// See Virtio specification v1.1. - 5.11.3
///
/// See Virtio specification v1.1. - 6
//
// WARN: In case the enum is changed, the static function of features `into_features(feature: u64) ->
// Option<Vec<Features>>` must also be adjusted to return a correct vector of features.
#[allow(dead_code, non_camel_case_types)]
#[derive(Copy, Clone, Debug)]
#[repr(u64)]
pub enum Features {
VIRTIO_F_RING_INDIRECT_DESC = 1 << 28,
VIRTIO_F_RING_EVENT_IDX = 1 << 29,
VIRTIO_F_VERSION_1 = 1 << 32,
VIRTIO_F_ACCESS_PLATFORM = 1 << 33,
VIRTIO_F_RING_PACKED = 1 << 34,
VIRTIO_F_IN_ORDER = 1 << 35,
VIRTIO_F_ORDER_PLATFORM = 1 << 36,
VIRTIO_F_SR_IOV = 1 << 37,
VIRTIO_F_NOTIFICATION_DATA = 1 << 38,
}

impl From<Features> for u64 {
fn from(val: Features) -> Self {
match val {
Features::VIRTIO_F_RING_INDIRECT_DESC => 1 << 28,
Features::VIRTIO_F_RING_EVENT_IDX => 1 << 29,
Features::VIRTIO_F_VERSION_1 => 1 << 32,
Features::VIRTIO_F_ACCESS_PLATFORM => 1 << 33,
Features::VIRTIO_F_RING_PACKED => 1 << 34,
Features::VIRTIO_F_IN_ORDER => 1 << 35,
Features::VIRTIO_F_ORDER_PLATFORM => 1 << 36,
Features::VIRTIO_F_SR_IOV => 1 << 37,
Features::VIRTIO_F_NOTIFICATION_DATA => 1 << 38,
}
}
}

impl BitOr for Features {
type Output = u64;

fn bitor(self, rhs: Self) -> Self::Output {
u64::from(self) | u64::from(rhs)
}
}

impl BitOr<Features> for u64 {
type Output = u64;

fn bitor(self, rhs: Features) -> Self::Output {
self | u64::from(rhs)
}
}

impl BitOrAssign<Features> for u64 {
fn bitor_assign(&mut self, rhs: Features) {
*self |= u64::from(rhs);
}
}

impl BitAnd for Features {
type Output = u64;

fn bitand(self, rhs: Features) -> Self::Output {
u64::from(self) & u64::from(rhs)
}
}

impl BitAnd<Features> for u64 {
type Output = u64;

fn bitand(self, rhs: Features) -> Self::Output {
self & u64::from(rhs)
}
}

impl BitAndAssign<Features> for u64 {
fn bitand_assign(&mut self, rhs: Features) {
*self &= u64::from(rhs);
}
}

impl core::fmt::Display for Features {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
Features::VIRTIO_F_RING_INDIRECT_DESC => write!(f, "VIRTIO_F_RING_INDIRECT_DESC"),
Features::VIRTIO_F_RING_EVENT_IDX => write!(f, "VIRTIO_F_RING_EVENT_IDX"),
Features::VIRTIO_F_VERSION_1 => write!(f, "VIRTIO_F_VERSION_1"),
Features::VIRTIO_F_ACCESS_PLATFORM => write!(f, "VIRTIO_F_ACCESS_PLATFORM"),
Features::VIRTIO_F_RING_PACKED => write!(f, "VIRTIO_F_RING_PACKED"),
Features::VIRTIO_F_IN_ORDER => write!(f, "VIRTIO_F_IN_ORDER"),
Features::VIRTIO_F_ORDER_PLATFORM => write!(f, "VIRTIO_F_ORDER_PLATFORM"),
Features::VIRTIO_F_SR_IOV => write!(f, "VIRTIO_F_SR_IOV"),
Features::VIRTIO_F_NOTIFICATION_DATA => write!(f, "VIRTIO_F_NOTIFICATION_DATA"),
}
}
}

impl Features {
/// Return a vector of [Features] for a given input of a u64 representation.
///
/// INFO: In case the FEATURES enum is changed, this function MUST also be adjusted to the new set!
//
// Really UGLY function, but currently the most convenienvt one to reduce the set of features for the driver easily!
pub fn from_set(feature_set: FeatureSet) -> Option<Vec<Features>> {
let mut features_vec: Vec<Features> = Vec::new();
let features = feature_set.0;

if features & (1 << 28) != 0 {
features_vec.push(Features::VIRTIO_F_RING_INDIRECT_DESC)
}
if features & (1 << 29) != 0 {
features_vec.push(Features::VIRTIO_F_RING_EVENT_IDX)
}
if features & (1 << 32) != 0 {
features_vec.push(Features::VIRTIO_F_VERSION_1)
}
if features & (1 << 33) != 0 {
features_vec.push(Features::VIRTIO_F_ACCESS_PLATFORM)
}
if features & (1 << 34) != 0 {
features_vec.push(Features::VIRTIO_F_RING_PACKED)
}
if features & (1 << 35) != 0 {
features_vec.push(Features::VIRTIO_F_IN_ORDER)
}
if features & (1 << 36) != 0 {
features_vec.push(Features::VIRTIO_F_ORDER_PLATFORM)
}
if features & (1 << 37) != 0 {
features_vec.push(Features::VIRTIO_F_SR_IOV)
}
if features & (1 << 38) != 0 {
features_vec.push(Features::VIRTIO_F_NOTIFICATION_DATA)
}

if features_vec.is_empty() {
None
} else {
Some(features_vec)
}
}
}

/// FeatureSet is new type whicih holds features for virito network devices indicated by the virtio specification
/// v1.1. - 5.1.3. and all General Features defined in Virtio specification v1.1. - 6
/// wrapping a u64.
///
/// The main functionality of this type are functions implemented on it.
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq, Eq)]
pub struct FeatureSet(u64);

impl BitOr for FeatureSet {
type Output = FeatureSet;

fn bitor(self, rhs: Self) -> Self::Output {
FeatureSet(self.0 | rhs.0)
}
}

impl BitOr<FeatureSet> for u64 {
type Output = u64;

fn bitor(self, rhs: FeatureSet) -> Self::Output {
self | u64::from(rhs)
}
}

impl BitOrAssign<FeatureSet> for u64 {
fn bitor_assign(&mut self, rhs: FeatureSet) {
*self |= u64::from(rhs);
}
}

impl BitOrAssign<Features> for FeatureSet {
fn bitor_assign(&mut self, rhs: Features) {
self.0 = self.0 | u64::from(rhs);
}
}

impl BitAnd for FeatureSet {
type Output = FeatureSet;

fn bitand(self, rhs: FeatureSet) -> Self::Output {
FeatureSet(self.0 & rhs.0)
}
}

impl BitAnd<FeatureSet> for u64 {
type Output = u64;

fn bitand(self, rhs: FeatureSet) -> Self::Output {
self & u64::from(rhs)
}
}

impl BitAndAssign<FeatureSet> for u64 {
fn bitand_assign(&mut self, rhs: FeatureSet) {
*self &= u64::from(rhs);
}
}

impl From<FeatureSet> for u64 {
fn from(feature_set: FeatureSet) -> Self {
feature_set.0
}
}

impl FeatureSet {
/// Checks if a given set of features is compatible and adheres to the
/// specfification v1.1. - 5.11.3
/// Upon an error returns the incompatible set of features by the
/// [FeatureRequirementsNotMet](super::error::VirtioFsError) error value, which
/// wraps the u64 indicating the feature set.
///
/// INFO: Iterates twice over the vector of features.
pub fn check_features(features: &[Features]) -> Result<(), VirtioFsError> {
let mut feature_bits = 0u64;

for feature in features.iter() {
feature_bits |= *feature;
}

for feature in features {
match feature {
Features::VIRTIO_F_RING_INDIRECT_DESC => continue,
Features::VIRTIO_F_RING_EVENT_IDX => continue,
Features::VIRTIO_F_VERSION_1 => continue,
Features::VIRTIO_F_ACCESS_PLATFORM => continue,
Features::VIRTIO_F_RING_PACKED => continue,
Features::VIRTIO_F_IN_ORDER => continue,
Features::VIRTIO_F_ORDER_PLATFORM => continue,
Features::VIRTIO_F_SR_IOV => continue,
Features::VIRTIO_F_NOTIFICATION_DATA => continue,
}
}

Ok(())
}

/// Checks if a given feature is set.
pub fn is_feature(self, feature: Features) -> bool {
self.0 & feature != 0
}

/// Sets features contained in features to true.
///
/// WARN: Features should be checked before using this function via the [`FeatureSet::check_features`] function.
pub fn set_features(&mut self, features: &[Features]) {
for feature in features {
self.0 |= *feature;
}
}

/// Returns a new instance of (FeatureSet)[FeatureSet] with all features
/// initialized to false.
pub fn new(val: u64) -> Self {
FeatureSet(val)
}
}
}

/// Error module of virtios filesystem driver.
pub mod error {
use super::constants::FeatureSet;
use virtio_def::features::VirtioFsF;

/// Network filesystem error enum.
#[derive(Debug, Copy, Clone)]
Expand All @@ -461,9 +175,9 @@ pub mod error {
#[cfg(feature = "pci")]
NoNotifCfg(u16),
FailFeatureNeg(u16),
/// The first u64 contains the feature bits wanted by the driver.
/// but which are incompatible with the device feature set, second u64.
IncompatibleFeatureSets(FeatureSet, FeatureSet),
/// The first field contains the feature bits wanted by the driver.
/// but which are incompatible with the device feature set, second field.
IncompatibleFeatureSets(VirtioFsF, VirtioFsF),
Unknown,
}
}
5 changes: 3 additions & 2 deletions src/drivers/fs/virtio_pci.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use alloc::vec::Vec;

use virtio_def::features::VirtioFsF;

use crate::arch::pci::PciConfigRegion;
use crate::drivers::fs::virtio_fs::constants::FeatureSet;
use crate::drivers::fs::virtio_fs::{FsDevCfg, VirtioFsDriver};
use crate::drivers::pci::PciDevice;
use crate::drivers::virtio::error::{self, VirtioError};
Expand Down Expand Up @@ -56,7 +57,7 @@ impl VirtioFsDriver {
Some(FsDevCfg {
raw: dev_cfg,
dev_id: cap.dev_id(),
features: FeatureSet::new(0),
features: VirtioFsF::empty(),
})
}

Expand Down
Loading

0 comments on commit d79daa1

Please sign in to comment.