Browse Source

Support modern as well as legacy MMIO devices in example.

Andrew Walbran 2 years ago
parent
commit
b33bd5c3b3
5 changed files with 88 additions and 36 deletions
  1. 15 1
      examples/riscv/Makefile
  2. 42 25
      examples/riscv/src/main.rs
  3. 1 1
      src/lib.rs
  4. 27 9
      src/transport/mmio.rs
  5. 3 0
      src/transport/mod.rs

+ 15 - 1
examples/riscv/Makefile

@@ -36,12 +36,26 @@ header:
 clean:
 	cargo clean
 
+qemu-legacy: kernel $(img)
+	qemu-system-$(arch) \
+		-machine virt \
+		-serial mon:stdio \
+		-bios default \
+		-kernel $(kernel) \
+		-drive file=$(img),if=none,format=raw,id=x0 \
+		-device virtio-blk-device,drive=x0 \
+		-device virtio-gpu-device \
+		-device virtio-mouse-device \
+		# -netdev type=tap,id=net0,script=no,downscript=no \
+		# -device virtio-net-device,netdev=net0
+
 qemu: kernel $(img)
 	qemu-system-$(arch) \
 		-machine virt \
 		-serial mon:stdio \
 		-bios default \
 		-kernel $(kernel) \
+		-global virtio-mmio.force-legacy=false \
 		-drive file=$(img),if=none,format=raw,id=x0 \
 		-device virtio-blk-device,drive=x0 \
 		-device virtio-gpu-device \
@@ -52,4 +66,4 @@ qemu: kernel $(img)
 $(img):
 	dd if=/dev/zero of=$@ bs=512 count=32
 
-run: build qemu
+run: build qemu-legacy qemu

+ 42 - 25
examples/riscv/src/main.rs

@@ -8,7 +8,7 @@ extern crate opensbi_rt;
 use alloc::vec;
 use device_tree::util::SliceRead;
 use device_tree::{DeviceTree, Node};
-use log::{info, warn, LevelFilter};
+use log::{error, info, warn, LevelFilter};
 use virtio_drivers::*;
 use virtio_impl::HalImpl;
 
@@ -55,26 +55,45 @@ 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 LegacyMmioTransport) };
-        info!(
-            "Detected virtio device with vendor id {:#X}, device type {:?}",
-            header.vendor_id(),
-            header.device_type(),
-        );
         info!("Device tree node {:?}", node);
-        match header.device_type() {
-            DeviceType::Block => virtio_blk(header),
-            DeviceType::GPU => virtio_gpu(header),
-            DeviceType::Input => virtio_input(header),
-            DeviceType::Network => virtio_net(header),
-            t => warn!("Unrecognized virtio device: {:?}", t),
+        let header = vaddr as *mut VirtIOHeader;
+        match unsafe { (*header).version() } {
+            Some(1) => {
+                let transport = unsafe { &mut *(header as *mut LegacyMmioTransport) };
+                info!(
+                    "Detected virtio legacy MMIO device with vendor id {:#X}, device type {:?}",
+                    transport.vendor_id(),
+                    transport.device_type(),
+                );
+                virtio_device(transport);
+            }
+            Some(2) => {
+                let transport = unsafe { &mut *(header as *mut MmioTransport) };
+                info!(
+                    "Detected virtio MMIO device with vendor id {:#X}, device type {:?}",
+                    transport.vendor_id(),
+                    transport.device_type(),
+                );
+                virtio_device(transport);
+            }
+            Some(version) => warn!("Unsupported virtio MMIO version {}", version),
+            None => error!("Invalid magic value for virtio device"),
         }
     }
 }
 
-fn virtio_blk(header: &'static mut LegacyMmioTransport) {
-    let mut blk = VirtIOBlk::<HalImpl, LegacyMmioTransport>::new(header)
-        .expect("failed to create blk driver");
+fn virtio_device(transport: &'static mut impl Transport) {
+    match transport.device_type() {
+        DeviceType::Block => virtio_blk(transport),
+        DeviceType::GPU => virtio_gpu(transport),
+        DeviceType::Input => virtio_input(transport),
+        DeviceType::Network => virtio_net(transport),
+        t => warn!("Unrecognized virtio device: {:?}", t),
+    }
+}
+
+fn virtio_blk<T: Transport>(transport: &'static mut T) {
+    let mut blk = VirtIOBlk::<HalImpl, T>::new(transport).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 +107,8 @@ fn virtio_blk(header: &'static mut LegacyMmioTransport) {
     info!("virtio-blk test finished");
 }
 
-fn virtio_gpu(header: &'static mut LegacyMmioTransport) {
-    let mut gpu = VirtIOGpu::<HalImpl, LegacyMmioTransport>::new(header)
-        .expect("failed to create gpu driver");
+fn virtio_gpu<T: Transport>(transport: &'static mut T) {
+    let mut gpu = VirtIOGpu::<HalImpl, T>::new(transport).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 +122,10 @@ fn virtio_gpu(header: &'static mut LegacyMmioTransport) {
     info!("virtio-gpu test finished");
 }
 
-fn virtio_input(header: &'static mut LegacyMmioTransport) {
+fn virtio_input<T: Transport>(transport: &'static mut T) {
     //let mut event_buf = [0u64; 32];
-    let mut _input = VirtIOInput::<HalImpl, LegacyMmioTransport>::new(header)
-        .expect("failed to create input driver");
+    let mut _input =
+        VirtIOInput::<HalImpl, T>::new(transport).expect("failed to create input driver");
     // loop {
     //     input.ack_interrupt().expect("failed to ack");
     //     info!("mouse: {:?}", input.mouse_xy());
@@ -115,9 +133,8 @@ fn virtio_input(header: &'static mut LegacyMmioTransport) {
     // TODO: handle external interrupt
 }
 
-fn virtio_net(header: &'static mut LegacyMmioTransport) {
-    let mut net = VirtIONet::<HalImpl, LegacyMmioTransport>::new(header)
-        .expect("failed to create net driver");
+fn virtio_net<T: Transport>(transport: &'static mut T) {
+    let mut net = VirtIONet::<HalImpl, T>::new(transport).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::{LegacyMmioTransport, MmioTransport};
+pub use self::transport::mmio::{LegacyMmioTransport, MmioTransport, VirtIOHeader};
 pub use self::transport::{DeviceStatus, DeviceType, Transport};
 use core::mem::size_of;
 use hal::*;

+ 27 - 9
src/transport/mmio.rs

@@ -12,7 +12,7 @@ const CONFIG_SPACE_OFFSET: usize = 0x100;
 ///
 /// Ref: 4.2.2 MMIO Device Register Layout and 4.2.4 Legacy interface
 #[repr(C)]
-struct VirtIOHeader {
+pub struct VirtIOHeader {
     /// Magic value
     magic: ReadOnly<u32>,
 
@@ -152,6 +152,24 @@ struct VirtIOHeader {
 }
 
 impl VirtIOHeader {
+    /// Checks the magic value and the version.
+    ///
+    /// Returns `None` if the magic value is incorrect, otherwise returns the version.
+    pub fn version(&self) -> Option<u32> {
+        if self.magic.read() == MAGIC_VALUE {
+            Some(self.version.read())
+        } else {
+            None
+        }
+    }
+
+    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,
+        }
+    }
+
     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();
@@ -256,14 +274,6 @@ impl LegacyMmioTransport {
             && 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()
@@ -287,6 +297,10 @@ impl LegacyMmioTransport {
 }
 
 impl Transport for LegacyMmioTransport {
+    fn device_type(&self) -> DeviceType {
+        self.0.device_type()
+    }
+
     fn read_device_features(&mut self) -> u64 {
         self.0.read_device_features()
     }
@@ -397,6 +411,10 @@ impl MmioTransport {
 }
 
 impl Transport for MmioTransport {
+    fn device_type(&self) -> DeviceType {
+        self.0.device_type()
+    }
+
     fn read_device_features(&mut self) -> u64 {
         self.0.read_device_features()
     }

+ 3 - 0
src/transport/mod.rs

@@ -5,6 +5,9 @@ use bitflags::bitflags;
 
 /// A VirtIO transport layer.
 pub trait Transport {
+    /// Gets the device type.
+    fn device_type(&self) -> DeviceType;
+
     /// Reads device features.
     fn read_device_features(&mut self) -> u64;