浏览代码

Factor out trait for Virtio transport.

This will allow other transports (e.g. PCI) to be added in future,
in addition to the MMIO transport currently included.
Andrew Walbran 2 年之前
父节点
当前提交
fb8bff9ade
共有 9 个文件被更改,包括 176 次插入133 次删除
  1. 1 1
      src/blk.rs
  2. 1 0
      src/console.rs
  3. 1 0
      src/gpu.rs
  4. 1 0
      src/input.rs
  5. 3 2
      src/lib.rs
  6. 1 0
      src/net.rs
  7. 1 1
      src/queue.rs
  8. 48 129
      src/transport/mmio.rs
  9. 119 0
      src/transport/mod.rs

+ 1 - 1
src/blk.rs

@@ -1,6 +1,6 @@
 use super::*;
-use crate::header::VirtIOHeader;
 use crate::queue::VirtQueue;
+use crate::transport::{mmio::VirtIOHeader, Transport};
 use bitflags::*;
 use core::hint::spin_loop;
 use log::*;

+ 1 - 0
src/console.rs

@@ -1,5 +1,6 @@
 use super::*;
 use crate::queue::VirtQueue;
+use crate::transport::{mmio::VirtIOHeader, Transport};
 use bitflags::*;
 use core::{fmt, hint::spin_loop};
 use log::*;

+ 1 - 0
src/gpu.rs

@@ -1,5 +1,6 @@
 use super::*;
 use crate::queue::VirtQueue;
+use crate::transport::{mmio::VirtIOHeader, Transport};
 use bitflags::*;
 use core::{fmt, hint::spin_loop};
 use log::*;

+ 1 - 0
src/input.rs

@@ -1,4 +1,5 @@
 use super::*;
+use crate::transport::{mmio::VirtIOHeader, Transport};
 use alloc::boxed::Box;
 use bitflags::*;
 use log::*;

+ 3 - 2
src/lib.rs

@@ -11,19 +11,20 @@ mod blk;
 mod console;
 mod gpu;
 mod hal;
-mod header;
 mod input;
 mod net;
 mod queue;
+mod transport;
 
 pub use self::blk::{BlkResp, RespStatus, VirtIOBlk};
 pub use self::console::VirtIOConsole;
 pub use self::gpu::VirtIOGpu;
 pub use self::hal::{Hal, PhysAddr, VirtAddr};
-pub use self::header::*;
 pub use self::input::{InputConfigSelect, InputEvent, VirtIOInput};
 pub use self::net::VirtIONet;
 use self::queue::VirtQueue;
+pub use self::transport::mmio::VirtIOHeader;
+pub use self::transport::{DeviceStatus, DeviceType, Transport};
 use core::mem::size_of;
 use hal::*;
 

+ 1 - 0
src/net.rs

@@ -1,6 +1,7 @@
 use core::mem::{size_of, MaybeUninit};
 
 use super::*;
+use crate::transport::{mmio::VirtIOHeader, Transport};
 use bitflags::*;
 use core::hint::spin_loop;
 use log::*;

+ 1 - 1
src/queue.rs

@@ -3,7 +3,7 @@ use core::slice;
 use core::sync::atomic::{fence, Ordering};
 
 use super::*;
-use crate::header::VirtIOHeader;
+use crate::transport::{mmio::VirtIOHeader, Transport};
 use bitflags::*;
 
 use volatile::Volatile;

+ 48 - 129
src/header.rs → src/transport/mmio.rs

@@ -1,5 +1,4 @@
-use crate::PAGE_SIZE;
-use bitflags::*;
+use super::{DeviceStatus, DeviceType, Transport};
 use volatile::{ReadOnly, Volatile, WriteOnly};
 
 const MAGIC_VALUE: u32 = 0x7472_6976;
@@ -166,82 +165,6 @@ impl VirtIOHeader {
         self.vendor_id.read()
     }
 
-    /// Begin initializing the device.
-    ///
-    /// Ref: virtio 3.1.1 Device Initialization
-    pub fn begin_init(&mut self, negotiate_features: impl FnOnce(u64) -> u64) {
-        self.status.write(DeviceStatus::ACKNOWLEDGE);
-        self.status.write(DeviceStatus::DRIVER);
-
-        let features = self.read_device_features();
-        self.write_driver_features(negotiate_features(features));
-        self.status.write(DeviceStatus::FEATURES_OK);
-
-        self.guest_page_size.write(PAGE_SIZE as u32);
-    }
-
-    /// Finish initializing the device.
-    pub fn finish_init(&mut self) {
-        self.status.write(DeviceStatus::DRIVER_OK);
-    }
-
-    /// Read device features.
-    fn read_device_features(&mut self) -> u64 {
-        self.device_features_sel.write(0); // device features [0, 32)
-        let mut device_features_bits = self.device_features.read().into();
-        self.device_features_sel.write(1); // device features [32, 64)
-        device_features_bits += (self.device_features.read() as u64) << 32;
-        device_features_bits
-    }
-
-    /// Write device features.
-    fn write_driver_features(&mut self, driver_features: u64) {
-        self.driver_features_sel.write(0); // driver features [0, 32)
-        self.driver_features.write(driver_features as u32);
-        self.driver_features_sel.write(1); // driver features [32, 64)
-        self.driver_features.write((driver_features >> 32) as u32);
-    }
-
-    /// Set queue.
-    pub fn queue_set(&mut self, queue: u32, size: u32, align: u32, pfn: u32) {
-        self.queue_sel.write(queue);
-        self.queue_num.write(size);
-        self.queue_align.write(align);
-        self.queue_pfn.write(pfn);
-    }
-
-    /// Get guest physical page number of the virtual queue.
-    pub fn queue_physical_page_number(&mut self, queue: u32) -> u32 {
-        self.queue_sel.write(queue);
-        self.queue_pfn.read()
-    }
-
-    /// Whether the queue is in used.
-    pub fn queue_used(&mut self, queue: u32) -> bool {
-        self.queue_physical_page_number(queue) != 0
-    }
-
-    /// Get the max size of queue.
-    pub fn max_queue_size(&self) -> u32 {
-        self.queue_num_max.read()
-    }
-
-    /// Notify device.
-    pub fn notify(&mut self, queue: u32) {
-        self.queue_notify.write(queue);
-    }
-
-    /// Acknowledge interrupt and return true if success.
-    pub fn ack_interrupt(&mut self) -> bool {
-        let interrupt = self.interrupt_status.read();
-        if interrupt != 0 {
-            self.interrupt_ack.write(interrupt);
-            true
-        } else {
-            false
-        }
-    }
-
     /// Get the pointer to config space (at offset 0x100)
     pub fn config_space(&self) -> *mut u64 {
         (self as *const _ as usize + CONFIG_SPACE_OFFSET) as _
@@ -295,63 +218,59 @@ impl VirtIOHeader {
     }
 }
 
-bitflags! {
-    /// The device status field.
-    struct DeviceStatus: u32 {
-        /// Indicates that the guest OS has found the device and recognized it
-        /// as a valid virtio device.
-        const ACKNOWLEDGE = 1;
+impl Transport for VirtIOHeader {
+    fn read_device_features(&mut self) -> u64 {
+        self.device_features_sel.write(0); // device features [0, 32)
+        let mut device_features_bits = self.device_features.read().into();
+        self.device_features_sel.write(1); // device features [32, 64)
+        device_features_bits += (self.device_features.read() as u64) << 32;
+        device_features_bits
+    }
+
+    fn write_driver_features(&mut self, driver_features: u64) {
+        self.driver_features_sel.write(0); // driver features [0, 32)
+        self.driver_features.write(driver_features as u32);
+        self.driver_features_sel.write(1); // driver features [32, 64)
+        self.driver_features.write((driver_features >> 32) as u32);
+    }
+
+    fn max_queue_size(&self) -> u32 {
+        self.queue_num_max.read()
+    }
+
+    fn notify(&mut self, queue: u32) {
+        self.queue_notify.write(queue);
+    }
 
-        /// Indicates that the guest OS knows how to drive the device.
-        const DRIVER = 2;
+    fn set_status(&mut self, status: DeviceStatus) {
+        self.status.write(status);
+    }
 
-        /// Indicates that something went wrong in the guest, and it has given
-        /// up on the device. This could be an internal error, or the driver
-        /// didn’t like the device for some reason, or even a fatal error
-        /// during device operation.
-        const FAILED = 128;
+    fn set_guest_page_size(&mut self, guest_page_size: u32) {
+        self.guest_page_size.write(guest_page_size);
+    }
 
-        /// Indicates that the driver has acknowledged all the features it
-        /// understands, and feature negotiation is complete.
-        const FEATURES_OK = 8;
+    fn queue_set(&mut self, queue: u32, size: u32, align: u32, pfn: u32) {
+        self.queue_sel.write(queue);
+        self.queue_num.write(size);
+        self.queue_align.write(align);
+        self.queue_pfn.write(pfn);
+    }
 
-        /// Indicates that the driver is set up and ready to drive the device.
-        const DRIVER_OK = 4;
+    fn queue_physical_page_number(&mut self, queue: u32) -> u32 {
+        self.queue_sel.write(queue);
+        self.queue_pfn.read()
+    }
 
-        /// Indicates that the device has experienced an error from which it
-        /// can’t recover.
-        const DEVICE_NEEDS_RESET = 64;
+    fn ack_interrupt(&mut self) -> bool {
+        let interrupt = self.interrupt_status.read();
+        if interrupt != 0 {
+            self.interrupt_ack.write(interrupt);
+            true
+        } else {
+            false
+        }
     }
 }
 
 const CONFIG_SPACE_OFFSET: usize = 0x100;
-
-/// Types of virtio devices.
-#[repr(u8)]
-#[derive(Debug, Eq, PartialEq)]
-#[allow(missing_docs)]
-pub enum DeviceType {
-    Invalid = 0,
-    Network = 1,
-    Block = 2,
-    Console = 3,
-    EntropySource = 4,
-    MemoryBallooning = 5,
-    IoMemory = 6,
-    Rpmsg = 7,
-    ScsiHost = 8,
-    _9P = 9,
-    Mac80211 = 10,
-    RprocSerial = 11,
-    VirtioCAIF = 12,
-    MemoryBalloon = 13,
-    GPU = 16,
-    Timer = 17,
-    Input = 18,
-    Socket = 19,
-    Crypto = 20,
-    SignalDistributionModule = 21,
-    Pstore = 22,
-    IOMMU = 23,
-    Memory = 24,
-}

+ 119 - 0
src/transport/mod.rs

@@ -0,0 +1,119 @@
+pub mod mmio;
+
+use crate::PAGE_SIZE;
+use bitflags::bitflags;
+
+/// A VirtIO transport layer.
+pub trait Transport {
+    /// Reads device features.
+    fn read_device_features(&mut self) -> u64;
+
+    /// Writes device features.
+    fn write_driver_features(&mut self, driver_features: u64);
+
+    /// Gets the max size of queue.
+    fn max_queue_size(&self) -> u32;
+
+    /// Notifies the given queue on the device.
+    fn notify(&mut self, queue: u32);
+
+    /// Sets the device status.
+    fn set_status(&mut self, status: DeviceStatus);
+
+    /// Sets the guest page size.
+    fn set_guest_page_size(&mut self, guest_page_size: u32);
+
+    /// Sets up the given queue.
+    fn queue_set(&mut self, queue: u32, size: u32, align: u32, pfn: u32);
+
+    /// Gets the guest physical page number of the given virtual queue.
+    fn queue_physical_page_number(&mut self, queue: u32) -> u32;
+
+    /// Acknowledges an interrupt.
+    ///
+    /// Returns true on success.
+    fn ack_interrupt(&mut self) -> bool;
+
+    /// Begins initializing the device.
+    ///
+    /// Ref: virtio 3.1.1 Device Initialization
+    fn begin_init(&mut self, negotiate_features: impl FnOnce(u64) -> u64) {
+        self.set_status(DeviceStatus::ACKNOWLEDGE);
+        self.set_status(DeviceStatus::DRIVER);
+
+        let features = self.read_device_features();
+        self.write_driver_features(negotiate_features(features));
+        self.set_status(DeviceStatus::FEATURES_OK);
+
+        self.set_guest_page_size(PAGE_SIZE as u32);
+    }
+
+    /// Finishes initializing the device.
+    fn finish_init(&mut self) {
+        self.set_status(DeviceStatus::DRIVER_OK);
+    }
+
+    /// Returns whether the queue is in use, i.e. has a nonzero PFN.
+    fn queue_used(&mut self, queue: u32) -> bool {
+        self.queue_physical_page_number(queue) != 0
+    }
+}
+
+bitflags! {
+    /// The device status field.
+    pub struct DeviceStatus: u32 {
+        /// Indicates that the guest OS has found the device and recognized it
+        /// as a valid virtio device.
+        const ACKNOWLEDGE = 1;
+
+        /// Indicates that the guest OS knows how to drive the device.
+        const DRIVER = 2;
+
+        /// Indicates that something went wrong in the guest, and it has given
+        /// up on the device. This could be an internal error, or the driver
+        /// didn’t like the device for some reason, or even a fatal error
+        /// during device operation.
+        const FAILED = 128;
+
+        /// Indicates that the driver has acknowledged all the features it
+        /// understands, and feature negotiation is complete.
+        const FEATURES_OK = 8;
+
+        /// Indicates that the driver is set up and ready to drive the device.
+        const DRIVER_OK = 4;
+
+        /// Indicates that the device has experienced an error from which it
+        /// can’t recover.
+        const DEVICE_NEEDS_RESET = 64;
+    }
+}
+
+/// Types of virtio devices.
+#[repr(u8)]
+#[derive(Debug, Eq, PartialEq)]
+#[allow(missing_docs)]
+pub enum DeviceType {
+    Invalid = 0,
+    Network = 1,
+    Block = 2,
+    Console = 3,
+    EntropySource = 4,
+    MemoryBallooning = 5,
+    IoMemory = 6,
+    Rpmsg = 7,
+    ScsiHost = 8,
+    _9P = 9,
+    Mac80211 = 10,
+    RprocSerial = 11,
+    VirtioCAIF = 12,
+    MemoryBalloon = 13,
+    GPU = 16,
+    Timer = 17,
+    Input = 18,
+    Socket = 19,
+    Crypto = 20,
+    SignalDistributionModule = 21,
+    Pstore = 22,
+    IOMMU = 23,
+    Memory = 24,
+}