Prechádzať zdrojové kódy

Add wrapper struct for legacy MMIO interface.

Andrew Walbran 2 rokov pred
rodič
commit
55200d895e
4 zmenil súbory, kde vykonal 88 pridanie a 63 odobranie
  1. 13 13
      examples/riscv/src/main.rs
  2. 1 1
      src/lib.rs
  3. 6 6
      src/queue.rs
  4. 68 43
      src/transport/mmio.rs

+ 13 - 13
examples/riscv/src/main.rs

@@ -55,7 +55,7 @@ fn virtio_probe(node: &Node) {
         let size = reg.as_slice().read_be_u64(8).unwrap();
         let vaddr = paddr;
         info!("walk dt addr={:#x}, size={:#x}", paddr, size);
-        let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
+        let header = unsafe { &mut *(vaddr as *mut LegacyMmioTransport) };
         info!(
             "Detected virtio device with vendor id {:#X}, device type {:?}",
             header.vendor_id(),
@@ -72,9 +72,9 @@ fn virtio_probe(node: &Node) {
     }
 }
 
-fn virtio_blk(header: &'static mut VirtIOHeader) {
-    let mut blk =
-        VirtIOBlk::<HalImpl, VirtIOHeader>::new(header).expect("failed to create blk driver");
+fn virtio_blk(header: &'static mut LegacyMmioTransport) {
+    let mut blk = VirtIOBlk::<HalImpl, LegacyMmioTransport>::new(header)
+        .expect("failed to create blk driver");
     let mut input = vec![0xffu8; 512];
     let mut output = vec![0; 512];
     for i in 0..32 {
@@ -88,9 +88,9 @@ fn virtio_blk(header: &'static mut VirtIOHeader) {
     info!("virtio-blk test finished");
 }
 
-fn virtio_gpu(header: &'static mut VirtIOHeader) {
-    let mut gpu =
-        VirtIOGpu::<HalImpl, VirtIOHeader>::new(header).expect("failed to create gpu driver");
+fn virtio_gpu(header: &'static mut LegacyMmioTransport) {
+    let mut gpu = VirtIOGpu::<HalImpl, LegacyMmioTransport>::new(header)
+        .expect("failed to create gpu driver");
     let fb = gpu.setup_framebuffer().expect("failed to get fb");
     for y in 0..768 {
         for x in 0..1024 {
@@ -104,10 +104,10 @@ fn virtio_gpu(header: &'static mut VirtIOHeader) {
     info!("virtio-gpu test finished");
 }
 
-fn virtio_input(header: &'static mut VirtIOHeader) {
+fn virtio_input(header: &'static mut LegacyMmioTransport) {
     //let mut event_buf = [0u64; 32];
-    let mut _input =
-        VirtIOInput::<HalImpl, VirtIOHeader>::new(header).expect("failed to create input driver");
+    let mut _input = VirtIOInput::<HalImpl, LegacyMmioTransport>::new(header)
+        .expect("failed to create input driver");
     // loop {
     //     input.ack_interrupt().expect("failed to ack");
     //     info!("mouse: {:?}", input.mouse_xy());
@@ -115,9 +115,9 @@ fn virtio_input(header: &'static mut VirtIOHeader) {
     // TODO: handle external interrupt
 }
 
-fn virtio_net(header: &'static mut VirtIOHeader) {
-    let mut net =
-        VirtIONet::<HalImpl, VirtIOHeader>::new(header).expect("failed to create net driver");
+fn virtio_net(header: &'static mut LegacyMmioTransport) {
+    let mut net = VirtIONet::<HalImpl, LegacyMmioTransport>::new(header)
+        .expect("failed to create net driver");
     let mut buf = [0u8; 0x100];
     let len = net.recv(&mut buf).expect("failed to recv");
     info!("recv: {:?}", &buf[..len]);

+ 1 - 1
src/lib.rs

@@ -23,7 +23,7 @@ pub use self::hal::{Hal, PhysAddr, VirtAddr};
 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::mmio::LegacyMmioTransport;
 pub use self::transport::{DeviceStatus, DeviceType, Transport};
 use core::mem::size_of;
 use hal::*;

+ 6 - 6
src/queue.rs

@@ -277,7 +277,7 @@ mod tests {
 
     #[test]
     fn invalid_queue_size() {
-        let mut header = VirtIOHeader::make_fake_header(0, 0, 0, 4);
+        let mut header = LegacyMmioTransport::make_fake_header(0, 0, 0, 4);
         // Size not a power of 2.
         assert_eq!(
             VirtQueue::<FakeHal>::new(&mut header, 0, 3).unwrap_err(),
@@ -287,7 +287,7 @@ mod tests {
 
     #[test]
     fn queue_too_big() {
-        let mut header = VirtIOHeader::make_fake_header(0, 0, 0, 4);
+        let mut header = LegacyMmioTransport::make_fake_header(0, 0, 0, 4);
         assert_eq!(
             VirtQueue::<FakeHal>::new(&mut header, 0, 5).unwrap_err(),
             Error::InvalidParam
@@ -296,7 +296,7 @@ mod tests {
 
     #[test]
     fn queue_already_used() {
-        let mut header = VirtIOHeader::make_fake_header(0, 0, 0, 4);
+        let mut header = LegacyMmioTransport::make_fake_header(0, 0, 0, 4);
         VirtQueue::<FakeHal>::new(&mut header, 0, 4).unwrap();
         assert_eq!(
             VirtQueue::<FakeHal>::new(&mut header, 0, 4).unwrap_err(),
@@ -306,14 +306,14 @@ mod tests {
 
     #[test]
     fn add_empty() {
-        let mut header = VirtIOHeader::make_fake_header(0, 0, 0, 4);
+        let mut header = LegacyMmioTransport::make_fake_header(0, 0, 0, 4);
         let mut queue = VirtQueue::<FakeHal>::new(&mut header, 0, 4).unwrap();
         assert_eq!(queue.add(&[], &[]).unwrap_err(), Error::InvalidParam);
     }
 
     #[test]
     fn add_too_big() {
-        let mut header = VirtIOHeader::make_fake_header(0, 0, 0, 4);
+        let mut header = LegacyMmioTransport::make_fake_header(0, 0, 0, 4);
         let mut queue = VirtQueue::<FakeHal>::new(&mut header, 0, 4).unwrap();
         assert_eq!(queue.available_desc(), 4);
         assert_eq!(
@@ -326,7 +326,7 @@ mod tests {
 
     #[test]
     fn add_buffers() {
-        let mut header = VirtIOHeader::make_fake_header(0, 0, 0, 4);
+        let mut header = LegacyMmioTransport::make_fake_header(0, 0, 0, 4);
         let mut queue = VirtQueue::<FakeHal>::new(&mut header, 0, 4).unwrap();
         assert_eq!(queue.size(), 4);
         assert_eq!(queue.available_desc(), 4);

+ 68 - 43
src/transport/mmio.rs

@@ -6,11 +6,11 @@ use volatile::{ReadOnly, Volatile, WriteOnly};
 const MAGIC_VALUE: u32 = 0x7472_6976;
 const CONFIG_SPACE_OFFSET: usize = 0x100;
 
-/// MMIO Device Legacy Register Interface.
+/// MMIO Device Register Interface, both legacy and modern.
 ///
-/// Ref: 4.2.4 Legacy interface
+/// Ref: 4.2.2 MMIO Device Register Layout and 4.2.4 Legacy interface
 #[repr(C)]
-pub struct VirtIOHeader {
+struct VirtIOHeader {
     /// Magic value
     magic: ReadOnly<u32>,
 
@@ -150,27 +150,9 @@ pub struct VirtIOHeader {
 }
 
 impl VirtIOHeader {
-    /// Verify a valid header.
-    pub fn verify(&self) -> bool {
-        self.magic.read() == MAGIC_VALUE && self.version.read() == 1 && self.device_id.read() != 0
-    }
-
-    /// Get the device type.
-    pub fn device_type(&self) -> DeviceType {
-        match self.device_id.read() {
-            x @ 1..=13 | x @ 16..=24 => unsafe { core::mem::transmute(x as u8) },
-            _ => DeviceType::Invalid,
-        }
-    }
-
-    /// Get the vendor ID.
-    pub fn vendor_id(&self) -> u32 {
-        self.vendor_id.read()
-    }
-
     /// Constructs a fake virtio header for use in unit tests.
     #[cfg(test)]
-    pub fn make_fake_header(
+    fn make_fake_header(
         device_id: u32,
         vendor_id: u32,
         device_features: u32,
@@ -216,36 +198,79 @@ impl VirtIOHeader {
     }
 }
 
-impl Transport for VirtIOHeader {
+/// MMIO Device Legacy Register Interface.
+///
+/// Ref: 4.2.4 Legacy interface
+#[repr(transparent)]
+pub struct LegacyMmioTransport(VirtIOHeader);
+
+impl LegacyMmioTransport {
+    /// Verify a valid header.
+    pub fn verify(&self) -> bool {
+        self.0.magic.read() == MAGIC_VALUE
+            && self.0.version.read() == 1
+            && self.0.device_id.read() != 0
+    }
+
+    /// Get the device type.
+    pub fn device_type(&self) -> DeviceType {
+        match self.0.device_id.read() {
+            x @ 1..=13 | x @ 16..=24 => unsafe { core::mem::transmute(x as u8) },
+            _ => DeviceType::Invalid,
+        }
+    }
+
+    /// Get the vendor ID.
+    pub fn vendor_id(&self) -> u32 {
+        self.0.vendor_id.read()
+    }
+
+    #[cfg(test)]
+    pub fn make_fake_header(
+        device_id: u32,
+        vendor_id: u32,
+        device_features: u32,
+        queue_num_max: u32,
+    ) -> Self {
+        Self(VirtIOHeader::make_fake_header(
+            device_id,
+            vendor_id,
+            device_features,
+            queue_num_max,
+        ))
+    }
+}
+
+impl Transport for LegacyMmioTransport {
     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;
+        self.0.device_features_sel.write(0); // device features [0, 32)
+        let mut device_features_bits = self.0.device_features.read().into();
+        self.0.device_features_sel.write(1); // device features [32, 64)
+        device_features_bits += (self.0.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);
+        self.0.driver_features_sel.write(0); // driver features [0, 32)
+        self.0.driver_features.write(driver_features as u32);
+        self.0.driver_features_sel.write(1); // driver features [32, 64)
+        self.0.driver_features.write((driver_features >> 32) as u32);
     }
 
     fn max_queue_size(&self) -> u32 {
-        self.queue_num_max.read()
+        self.0.queue_num_max.read()
     }
 
     fn notify(&mut self, queue: u32) {
-        self.queue_notify.write(queue);
+        self.0.queue_notify.write(queue);
     }
 
     fn set_status(&mut self, status: DeviceStatus) {
-        self.status.write(status);
+        self.0.status.write(status);
     }
 
     fn set_guest_page_size(&mut self, guest_page_size: u32) {
-        self.legacy_guest_page_size.write(guest_page_size);
+        self.0.legacy_guest_page_size.write(guest_page_size);
     }
 
     fn queue_set(
@@ -268,21 +293,21 @@ impl Transport for VirtIOHeader {
         );
         let align = PAGE_SIZE as u32;
         let pfn = (descriptors / PAGE_SIZE) as u32;
-        self.queue_sel.write(queue);
-        self.queue_num.write(size);
-        self.legacy_queue_align.write(align);
-        self.legacy_queue_pfn.write(pfn);
+        self.0.queue_sel.write(queue);
+        self.0.queue_num.write(size);
+        self.0.legacy_queue_align.write(align);
+        self.0.legacy_queue_pfn.write(pfn);
     }
 
     fn queue_used(&mut self, queue: u32) -> bool {
-        self.queue_sel.write(queue);
-        self.legacy_queue_pfn.read() != 0
+        self.0.queue_sel.write(queue);
+        self.0.legacy_queue_pfn.read() != 0
     }
 
     fn ack_interrupt(&mut self) -> bool {
-        let interrupt = self.interrupt_status.read();
+        let interrupt = self.0.interrupt_status.read();
         if interrupt != 0 {
-            self.interrupt_ack.write(interrupt);
+            self.0.interrupt_ack.write(interrupt);
             true
         } else {
             false