From 22f37485deb1e6c897706ee5547a1e63953a4ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Sun, 31 May 2026 22:01:00 +0200 Subject: [PATCH] refactor(virtio): make devices generic over transport Instead of relying on importing one of the PCI and MMIO transport modules that implement identically named structs to select the transport used by VIRTIO device drivers, use generics. This is in preparation for removing the mutual exclusivity of PCI and MMIO-based devices. --- src/arch/aarch64/kernel/mmio.rs | 49 +++++---- src/arch/riscv64/kernel/mmio.rs | 25 +++-- src/arch/x86_64/kernel/mmio.rs | 25 +++-- src/drivers/console/mmio.rs | 10 +- src/drivers/console/mod.rs | 56 +++++----- src/drivers/console/pci.rs | 8 +- src/drivers/fs/mmio.rs | 8 +- src/drivers/fs/mod.rs | 32 +++--- src/drivers/fs/pci.rs | 8 +- src/drivers/net/virtio/mmio.rs | 10 +- src/drivers/net/virtio/mod.rs | 104 +++++++++--------- src/drivers/net/virtio/pci.rs | 9 +- src/drivers/pci.rs | 30 ++++-- src/drivers/virtio/transport/mmio.rs | 143 ++++++++++++++++--------- src/drivers/virtio/transport/mod.rs | 63 +++++++++++ src/drivers/virtio/transport/pci.rs | 116 +++++++++++++------- src/drivers/virtio/virtqueue/mod.rs | 7 +- src/drivers/virtio/virtqueue/packed.rs | 58 +++++----- src/drivers/virtio/virtqueue/split.rs | 37 +++---- src/drivers/vsock/mmio.rs | 12 +-- src/drivers/vsock/mod.rs | 60 +++++------ src/drivers/vsock/pci.rs | 6 +- 22 files changed, 512 insertions(+), 364 deletions(-) diff --git a/src/arch/aarch64/kernel/mmio.rs b/src/arch/aarch64/kernel/mmio.rs index 153bde370f..5be786d6f7 100644 --- a/src/arch/aarch64/kernel/mmio.rs +++ b/src/arch/aarch64/kernel/mmio.rs @@ -32,7 +32,7 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; feature = "virtio-net", feature = "virtio-vsock", ))] -use crate::drivers::virtio::transport::mmio::VirtioDriver; +use crate::drivers::virtio::transport::mmio::{Transport, VirtioDriver}; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; #[cfg(feature = "virtio-net")] @@ -45,16 +45,16 @@ pub(crate) static MMIO_DRIVERS: InitCell> = InitCell::new(Vec::n #[allow(clippy::enum_variant_names)] pub(crate) enum MmioDriver { #[cfg(feature = "virtio-console")] - VirtioConsole(InterruptTicketMutex), + VirtioConsole(InterruptTicketMutex>), #[cfg(feature = "virtio-fs")] - VirtioFs(InterruptTicketMutex), + VirtioFs(InterruptTicketMutex>), #[cfg(feature = "virtio-vsock")] - VirtioVsock(InterruptTicketMutex), + VirtioVsock(InterruptTicketMutex>), } impl MmioDriver { #[cfg(feature = "virtio-console")] - fn get_console_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_console_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioConsole(drv) => Some(drv), @@ -63,7 +63,7 @@ impl MmioDriver { } #[cfg(feature = "virtio-fs")] - fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioFs(drv) => Some(drv), @@ -72,7 +72,7 @@ impl MmioDriver { } #[cfg(feature = "virtio-vsock")] - fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioVsock(drv) => Some(drv), @@ -81,16 +81,21 @@ impl MmioDriver { } } -#[cfg(any(feature = "virtio-console", feature = "virtio-fs", feature = "virtio-vsock"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock" +))] pub(crate) fn register_driver(drv: MmioDriver) { MMIO_DRIVERS.with(|mmio_drivers| mmio_drivers.unwrap().push(drv)); } #[cfg(feature = "virtio-net")] -pub(crate) type NetworkDevice = VirtioNetDriver; +pub(crate) type NetworkDevice = VirtioNetDriver; #[cfg(feature = "virtio-console")] -pub(crate) fn get_console_driver() -> Option<&'static InterruptTicketMutex> { +pub(crate) fn get_console_driver() +-> Option<&'static InterruptTicketMutex>> { MMIO_DRIVERS .get()? .iter() @@ -98,7 +103,8 @@ pub(crate) fn get_console_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { +pub(crate) fn get_filesystem_driver() +-> Option<&'static InterruptTicketMutex>> { MMIO_DRIVERS .get()? .iter() @@ -106,7 +112,8 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { +pub(crate) fn get_vsock_driver() +-> Option<&'static InterruptTicketMutex>> { MMIO_DRIVERS .get()? .iter() @@ -209,15 +216,19 @@ pub fn init_drivers() { } else { panic!("Invalid interrupt type"); }; - gic.set_interrupt_priority(virtio_irqid, Some(cpu_id), 0x00).unwrap(); + gic.set_interrupt_priority(virtio_irqid, Some(cpu_id), 0x00) + .unwrap(); if (irqflags & 0xf) == 4 || (irqflags & 0xf) == 8 { - gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Level).unwrap(); + gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Level) + .unwrap(); } else if (irqflags & 0xf) == 2 || (irqflags & 0xf) == 1 { - gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Edge).unwrap(); + gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Edge) + .unwrap(); } else { panic!("Invalid interrupt level!"); } - gic.enable_interrupt(virtio_irqid, Some(cpu_id), true).unwrap(); + gic.enable_interrupt(virtio_irqid, Some(cpu_id), true) + .unwrap(); match drv { #[cfg(feature = "virtio-console")] @@ -225,9 +236,9 @@ pub fn init_drivers() { InterruptTicketMutex::new(*drv), )), #[cfg(feature = "virtio-fs")] - VirtioDriver::Fs(drv) => register_driver(MmioDriver::VirtioFs( - InterruptTicketMutex::new(*drv), - )), + VirtioDriver::Fs(drv) => { + register_driver(MmioDriver::VirtioFs(InterruptTicketMutex::new(*drv))) + } #[cfg(feature = "virtio-net")] VirtioDriver::Net(drv) => *NETWORK_DEVICE.lock() = Some(*drv), #[cfg(feature = "virtio-vsock")] diff --git a/src/arch/riscv64/kernel/mmio.rs b/src/arch/riscv64/kernel/mmio.rs index 67928a388e..cb1d376cb9 100644 --- a/src/arch/riscv64/kernel/mmio.rs +++ b/src/arch/riscv64/kernel/mmio.rs @@ -15,6 +15,8 @@ use crate::drivers::fs::VirtioFsDriver; use crate::drivers::net::gem::GEMDriver; #[cfg(all(not(feature = "gem-net"), feature = "virtio-net"))] use crate::drivers::net::virtio::VirtioNetDriver; +#[cfg(feature = "virtio")] +use crate::drivers::virtio::transport::mmio::Transport; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; use crate::init_cell::InitCell; @@ -24,16 +26,16 @@ pub(crate) static MMIO_DRIVERS: InitCell> = InitCell::new(Vec::n #[allow(clippy::enum_variant_names)] pub(crate) enum MmioDriver { #[cfg(feature = "virtio-console")] - VirtioConsole(InterruptSpinMutex), + VirtioConsole(InterruptSpinMutex>), #[cfg(feature = "virtio-fs")] - VirtioFs(InterruptSpinMutex), + VirtioFs(InterruptSpinMutex>), #[cfg(feature = "virtio-vsock")] - VirtioVsock(InterruptSpinMutex), + VirtioVsock(InterruptSpinMutex>), } impl MmioDriver { #[cfg(feature = "virtio-console")] - fn get_console_driver(&self) -> Option<&InterruptSpinMutex> { + fn get_console_driver(&self) -> Option<&InterruptSpinMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioConsole(drv) => Some(drv), @@ -42,7 +44,7 @@ impl MmioDriver { } #[cfg(feature = "virtio-fs")] - fn get_filesystem_driver(&self) -> Option<&InterruptSpinMutex> { + fn get_filesystem_driver(&self) -> Option<&InterruptSpinMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioFs(drv) => Some(drv), @@ -51,7 +53,7 @@ impl MmioDriver { } #[cfg(feature = "virtio-vsock")] - fn get_vsock_driver(&self) -> Option<&InterruptSpinMutex> { + fn get_vsock_driver(&self) -> Option<&InterruptSpinMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioVsock(drv) => Some(drv), @@ -73,10 +75,11 @@ pub(crate) fn register_driver(drv: MmioDriver) { pub(crate) type NetworkDevice = GEMDriver; #[cfg(all(not(feature = "gem-net"), feature = "virtio-net"))] -pub(crate) type NetworkDevice = VirtioNetDriver; +pub(crate) type NetworkDevice = VirtioNetDriver; #[cfg(feature = "virtio-console")] -pub(crate) fn get_console_driver() -> Option<&'static InterruptSpinMutex> { +pub(crate) fn get_console_driver() +-> Option<&'static InterruptSpinMutex>> { MMIO_DRIVERS .get()? .iter() @@ -84,7 +87,8 @@ pub(crate) fn get_console_driver() -> Option<&'static InterruptSpinMutex Option<&'static InterruptSpinMutex> { +pub(crate) fn get_filesystem_driver() +-> Option<&'static InterruptSpinMutex>> { MMIO_DRIVERS .get()? .iter() @@ -92,7 +96,8 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptSpinMutex Option<&'static InterruptSpinMutex> { +pub(crate) fn get_vsock_driver() -> Option<&'static InterruptSpinMutex>> +{ MMIO_DRIVERS .get()? .iter() diff --git a/src/arch/x86_64/kernel/mmio.rs b/src/arch/x86_64/kernel/mmio.rs index db17b31098..4a6ae80849 100644 --- a/src/arch/x86_64/kernel/mmio.rs +++ b/src/arch/x86_64/kernel/mmio.rs @@ -33,7 +33,7 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; feature = "virtio-net", feature = "virtio-vsock", ))] -use crate::drivers::virtio::transport::mmio::VirtioDriver; +use crate::drivers::virtio::transport::mmio::{Transport, VirtioDriver}; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; use crate::env; @@ -49,16 +49,16 @@ static MMIO_DRIVERS: InitCell> = InitCell::new(Vec::new()); #[allow(clippy::enum_variant_names)] pub(crate) enum MmioDriver { #[cfg(feature = "virtio-console")] - VirtioConsole(InterruptTicketMutex), + VirtioConsole(InterruptTicketMutex>), #[cfg(feature = "virtio-fs")] - VirtioFs(InterruptTicketMutex), + VirtioFs(InterruptTicketMutex>), #[cfg(feature = "virtio-vsock")] - VirtioVsock(InterruptTicketMutex), + VirtioVsock(InterruptTicketMutex>), } impl MmioDriver { #[cfg(feature = "virtio-console")] - fn get_console_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_console_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioConsole(drv) => Some(drv), @@ -67,7 +67,7 @@ impl MmioDriver { } #[cfg(feature = "virtio-fs")] - fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioFs(drv) => Some(drv), @@ -76,7 +76,7 @@ impl MmioDriver { } #[cfg(feature = "virtio-vsock")] - fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioVsock(drv) => Some(drv), @@ -191,10 +191,11 @@ pub(crate) fn register_driver(drv: MmioDriver) { } #[cfg(feature = "virtio-net")] -pub(crate) type NetworkDevice = VirtioNetDriver; +pub(crate) type NetworkDevice = VirtioNetDriver; #[cfg(feature = "virtio-console")] -pub(crate) fn get_console_driver() -> Option<&'static InterruptTicketMutex> { +pub(crate) fn get_console_driver() +-> Option<&'static InterruptTicketMutex>> { MMIO_DRIVERS .get()? .iter() @@ -202,7 +203,8 @@ pub(crate) fn get_console_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { +pub(crate) fn get_filesystem_driver() +-> Option<&'static InterruptTicketMutex>> { MMIO_DRIVERS .get()? .iter() @@ -210,7 +212,8 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { +pub(crate) fn get_vsock_driver() +-> Option<&'static InterruptTicketMutex>> { MMIO_DRIVERS .get()? .iter() diff --git a/src/drivers/console/mmio.rs b/src/drivers/console/mmio.rs index 7bef82ea95..4ad5abc6b0 100644 --- a/src/drivers/console/mmio.rs +++ b/src/drivers/console/mmio.rs @@ -5,15 +5,15 @@ use volatile::VolatileRef; use crate::drivers::InterruptLine; use crate::drivers::console::{ConsoleDevCfg, RxQueue, TxQueue, VirtioConsoleDriver}; use crate::drivers::virtio::error::VirtioError; -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg, Transport}; // Backend-dependent interface for Virtio console driver -impl VirtioConsoleDriver { +impl VirtioConsoleDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result { + ) -> Result { let dev_cfg_raw: &'static Config = unsafe { &*registers .borrow_mut() @@ -32,7 +32,7 @@ impl VirtioConsoleDriver { let isr_stat = IsrStatus::new(registers.borrow_mut()); let notif_cfg = NotifCfg::new(registers.borrow_mut()); - Ok(VirtioConsoleDriver { + Ok(Self { dev_cfg, com_cfg: ComCfg::new(registers), isr_stat, @@ -52,7 +52,7 @@ impl VirtioConsoleDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result { + ) -> Result { let mut drv = VirtioConsoleDriver::new(dev_id, registers, irq)?; drv.init_dev().map_err(VirtioError::ConsoleDriver)?; drv.com_cfg.print_information(); diff --git a/src/drivers/console/mod.rs b/src/drivers/console/mod.rs index 01b0f731e5..94d882fa7d 100644 --- a/src/drivers/console/mod.rs +++ b/src/drivers/console/mod.rs @@ -32,10 +32,7 @@ use crate::drivers::mmio::get_console_driver; use crate::drivers::pci::get_console_driver; use crate::drivers::virtio::ControlRegisters; use crate::drivers::virtio::error::VirtioConsoleError; -#[cfg(not(feature = "pci"))] -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; -#[cfg(feature = "pci")] -use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::{ComCfg, IsrStatus, Transport}; use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, VirtQueue, Virtq, @@ -44,7 +41,7 @@ use crate::drivers::{Driver, InterruptLine}; use crate::errno::Errno; use crate::mm::device_alloc::DeviceAlloc; -fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { +fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { for _ in 0..num_packets { let buff_tkn = match AvailBufferToken::new(SmallVec::new(), { let mut vec = SmallVec::new(); @@ -114,12 +111,12 @@ impl Write for VirtioUART { } } -pub(crate) struct RxQueue { - vq: Option, +pub(crate) struct RxQueue { + vq: Option>, packet_size: u32, } -impl RxQueue { +impl RxQueue { pub fn new() -> Self { Self { vq: None, @@ -128,7 +125,7 @@ impl RxQueue { } } - pub fn add(&mut self, mut vq: VirtQueue) { + pub fn add(&mut self, mut vq: VirtQueue) { const BUFF_PER_PACKET: u16 = 2; let num_packets = vq.size() / BUFF_PER_PACKET; fill_queue(&mut vq, num_packets, self.packet_size); @@ -178,14 +175,14 @@ impl RxQueue { } } -pub(crate) struct TxQueue { - vq: Option, +pub(crate) struct TxQueue { + vq: Option>, /// Indicates, whether the Driver/Device are using multiple /// queues for communication. packet_length: u32, } -impl TxQueue { +impl TxQueue { pub fn new() -> Self { Self { vq: None, @@ -193,7 +190,7 @@ impl TxQueue { } } - pub fn add(&mut self, vq: VirtQueue) { + pub fn add(&mut self, vq: VirtQueue) { self.vq = Some(vq); } @@ -257,18 +254,18 @@ pub(crate) struct ConsoleDevCfg { pub features: virtio::console::F, } -pub(crate) struct VirtioConsoleDriver { +pub(crate) struct VirtioConsoleDriver { pub(super) dev_cfg: ConsoleDevCfg, - pub(super) com_cfg: ComCfg, - pub(super) isr_stat: IsrStatus, - pub(super) notif_cfg: NotifCfg, + pub(super) com_cfg: T::ComCfg, + pub(super) isr_stat: T::IsrStatus, + pub(super) notif_cfg: T::NotifCfg, pub(super) irq: InterruptLine, - pub(super) recv_vq: RxQueue, - pub(super) send_vq: TxQueue, + pub(super) recv_vq: RxQueue, + pub(super) send_vq: TxQueue, } -impl Driver for VirtioConsoleDriver { +impl Driver for VirtioConsoleDriver { fn get_interrupt_number(&self) -> InterruptLine { self.irq } @@ -278,7 +275,7 @@ impl Driver for VirtioConsoleDriver { } } -impl VirtioConsoleDriver { +impl VirtioConsoleDriver { pub fn has_packet(&self) -> bool { self.recv_vq.has_packet() } @@ -287,14 +284,9 @@ impl VirtioConsoleDriver { pub fn handle_interrupt(&mut self) { let status = self.isr_stat.acknowledge(); - #[cfg(not(feature = "pci"))] - if status.contains(virtio::mmio::InterruptStatus::CONFIGURATION_CHANGE_NOTIFICATION) { - info!("Configuration changes are not possible! Aborting"); - todo!("Implement possibility to change config on the fly...") - } - - #[cfg(feature = "pci")] - if status.contains(virtio::pci::IsrStatus::DEVICE_CONFIGURATION_INTERRUPT) { + if status & ::CONFIGURATION_CHANGE + == ::CONFIGURATION_CHANGE + { info!("Configuration changes are not possible! Aborting"); todo!("Implement possibility to change config on the fly...") } @@ -379,11 +371,11 @@ impl VirtioConsoleDriver { } } -impl ErrorType for VirtioConsoleDriver { +impl ErrorType for VirtioConsoleDriver { type Error = Errno; } -impl Read for VirtioConsoleDriver { +impl Read for VirtioConsoleDriver { fn read(&mut self, buf: &mut [u8]) -> Result { self.recv_vq .process_packet(|src| { @@ -394,7 +386,7 @@ impl Read for VirtioConsoleDriver { } } -impl Write for VirtioConsoleDriver { +impl Write for VirtioConsoleDriver { fn write(&mut self, buf: &[u8]) -> Result { self.send_vq.send_packet(buf); diff --git a/src/drivers/console/pci.rs b/src/drivers/console/pci.rs index c0422d77b3..9e8d37a478 100644 --- a/src/drivers/console/pci.rs +++ b/src/drivers/console/pci.rs @@ -5,11 +5,11 @@ use volatile::VolatileRef; use crate::drivers::console::{ConsoleDevCfg, RxQueue, TxQueue, VirtioConsoleDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; -use crate::drivers::virtio::transport::pci::{self, PciCap, UniCapsColl}; +use crate::drivers::virtio::transport::pci::{self, PciCap, Transport, UniCapsColl}; use crate::pci::PciConfigRegion; // Backend-dependent interface for Virtio console driver -impl VirtioConsoleDriver { +impl VirtioConsoleDriver { fn map_cfg(cap: &PciCap) -> Option { let dev_cfg = pci::map_dev_cfg::(cap)?; let dev_cfg = VolatileRef::from_ref(dev_cfg); @@ -56,9 +56,7 @@ impl VirtioConsoleDriver { /// Initializes virtio console device /// /// Returns a driver instance of VirtioConsoleDriver. - pub(crate) fn init( - device: &PciDevice, - ) -> Result { + pub(crate) fn init(device: &PciDevice) -> Result { // enable bus master mode device.set_command(CommandRegister::BUS_MASTER_ENABLE); diff --git a/src/drivers/fs/mmio.rs b/src/drivers/fs/mmio.rs index 3ae8b2db2a..d6941d9165 100644 --- a/src/drivers/fs/mmio.rs +++ b/src/drivers/fs/mmio.rs @@ -7,15 +7,15 @@ use volatile::VolatileRef; use crate::drivers::InterruptLine; use crate::drivers::fs::{FsDevCfg, VirtioFsDriver}; use crate::drivers::virtio::error::VirtioError; -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg, Transport}; // Backend-dependent interface for Virtio fs driver -impl VirtioFsDriver { +impl VirtioFsDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result { + ) -> Result { let dev_cfg_raw: &'static Config = unsafe { &*registers .borrow_mut() @@ -53,7 +53,7 @@ impl VirtioFsDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result { + ) -> Result { let mut drv = VirtioFsDriver::new(dev_id, registers, irq)?; drv.init_dev().map_err(VirtioError::FsDriver)?; drv.com_cfg.print_information(); diff --git a/src/drivers/fs/mod.rs b/src/drivers/fs/mod.rs index cebad3e144..a8dd02a786 100644 --- a/src/drivers/fs/mod.rs +++ b/src/drivers/fs/mod.rs @@ -33,10 +33,7 @@ use crate::config::VIRTIO_MAX_QUEUE_SIZE; use crate::drivers::Driver; use crate::drivers::virtio::ControlRegisters; use crate::drivers::virtio::error::VirtioFsInitError; -#[cfg(not(feature = "pci"))] -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; -#[cfg(feature = "pci")] -use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::{ComCfg, IsrStatus, Transport}; use crate::drivers::virtio::virtqueue::error::VirtqError; use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ @@ -60,17 +57,17 @@ pub(crate) struct FsDevCfg { /// Struct allows to control devices virtqueues as also /// the device itself. #[allow(dead_code)] -pub(crate) struct VirtioFsDriver { +pub(crate) struct VirtioFsDriver { pub(super) dev_cfg: FsDevCfg, - pub(super) com_cfg: ComCfg, - pub(super) isr_stat: IsrStatus, - pub(super) notif_cfg: NotifCfg, - pub(super) vqueues: Vec, + pub(super) com_cfg: T::ComCfg, + pub(super) isr_stat: T::IsrStatus, + pub(super) notif_cfg: T::NotifCfg, + pub(super) vqueues: Vec>, pub(super) irq: InterruptLine, } // Backend-independent interface for Virtio network driver -impl VirtioFsDriver { +impl VirtioFsDriver { #[cfg(feature = "pci")] pub fn get_dev_id(&self) -> u16 { self.dev_cfg.dev_id @@ -161,21 +158,16 @@ impl VirtioFsDriver { pub fn handle_interrupt(&mut self) { let status = self.isr_stat.acknowledge(); - #[cfg(not(feature = "pci"))] - if status.contains(virtio::mmio::InterruptStatus::CONFIGURATION_CHANGE_NOTIFICATION) { - info!("Configuration changes are not possible! Aborting"); - todo!("Implement possibility to change config on the fly...") - } - - #[cfg(feature = "pci")] - if status.contains(virtio::pci::IsrStatus::DEVICE_CONFIGURATION_INTERRUPT) { + if status & ::CONFIGURATION_CHANGE + == ::CONFIGURATION_CHANGE + { info!("Configuration changes are not possible! Aborting"); todo!("Implement possibility to change config on the fly...") } } } -impl VirtioFsInterface for VirtioFsDriver { +impl VirtioFsInterface for VirtioFsDriver { fn send_command( &mut self, cmd: virtio_fs::Cmd, @@ -262,7 +254,7 @@ impl VirtioFsInterface for VirtioFsDriver { } } -impl Driver for VirtioFsDriver { +impl Driver for VirtioFsDriver { fn get_interrupt_number(&self) -> InterruptLine { self.irq } diff --git a/src/drivers/fs/pci.rs b/src/drivers/fs/pci.rs index 63843609c2..d08c26fa28 100644 --- a/src/drivers/fs/pci.rs +++ b/src/drivers/fs/pci.rs @@ -7,9 +7,9 @@ use crate::drivers::fs::{FsDevCfg, VirtioFsDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; -use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; +use crate::drivers::virtio::transport::pci::{PciCap, Transport, UniCapsColl}; -impl VirtioFsDriver { +impl VirtioFsDriver { fn map_cfg(cap: &PciCap) -> Option { let dev_cfg = pci::map_dev_cfg::(cap)?; @@ -54,7 +54,9 @@ impl VirtioFsDriver { } /// Initializes virtio filesystem device - pub fn init(device: &PciDevice) -> Result { + pub fn init( + device: &PciDevice, + ) -> Result, VirtioError> { let mut drv = match pci::map_caps(device) { Ok(caps) => match VirtioFsDriver::new(caps, device) { Ok(driver) => driver, diff --git a/src/drivers/net/virtio/mmio.rs b/src/drivers/net/virtio/mmio.rs index ea21245e3c..b945a882ab 100644 --- a/src/drivers/net/virtio/mmio.rs +++ b/src/drivers/net/virtio/mmio.rs @@ -3,12 +3,12 @@ use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; use volatile::VolatileRef; use crate::drivers::InterruptLine; -use crate::drivers::net::virtio::{Init, NetDevCfg, Uninit, VirtioNetDriver}; +use crate::drivers::net::virtio::{NetDevCfg, Uninit, VirtioNetDriver}; use crate::drivers::virtio::error::VirtioError; -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg, Transport}; // Backend-dependent interface for Virtio network driver -impl VirtioNetDriver { +impl VirtioNetDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, @@ -53,7 +53,7 @@ impl VirtioNetDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result, VirtioError> { + ) -> Result, VirtioError> { let drv = VirtioNetDriver::new(dev_id, registers, irq)?; let mut drv = drv.init_dev().map_err(VirtioError::NetDriver)?; drv.print_information(); @@ -61,7 +61,7 @@ impl VirtioNetDriver { } } -impl VirtioNetDriver { +impl VirtioNetDriver { pub fn print_information(&mut self) { self.com_cfg.print_information(); if self.dev_status() == virtio::net::S::LINK_UP { diff --git a/src/drivers/net/virtio/mod.rs b/src/drivers/net/virtio/mod.rs index 03fc66b399..899d0797b4 100644 --- a/src/drivers/net/virtio/mod.rs +++ b/src/drivers/net/virtio/mod.rs @@ -37,10 +37,7 @@ use crate::config::VIRTIO_MAX_QUEUE_SIZE; use crate::drivers::net::virtio::constants::BUFF_PER_PACKET; use crate::drivers::net::{NetworkDriver, mtu}; use crate::drivers::virtio::ControlRegisters; -#[cfg(not(feature = "pci"))] -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; -#[cfg(feature = "pci")] -use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::{ComCfg, IsrStatus, Transport}; use crate::drivers::virtio::virtqueue::packed::PackedVq; use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ @@ -103,13 +100,13 @@ fn determine_rx_buf_size(dev_cfg: &NetDevCfg) -> u32 { min_buf_size } -pub struct RxQueues { - vqs: Vec, +pub struct RxQueues { + vqs: Vec>, buf_size: u32, } -impl RxQueues { - pub fn new(vqs: Vec, dev_cfg: &NetDevCfg) -> Self { +impl RxQueues { + pub fn new(vqs: Vec>, dev_cfg: &NetDevCfg) -> Self { Self { vqs, buf_size: determine_rx_buf_size(dev_cfg), @@ -119,7 +116,7 @@ impl RxQueues { /// Adds a given queue to the underlying vector and populates the queue with RecvBuffers. /// /// Queues are all populated according to Virtio specification v1.1. - 5.1.6.3.1 - fn add(&mut self, mut vq: VirtQueue) { + fn add(&mut self, mut vq: VirtQueue) { let num_bufs = vq.size() / BUFF_PER_PACKET; fill_queue(&mut vq, num_bufs, self.buf_size); self.vqs.push(vq); @@ -162,7 +159,7 @@ fn buffer_token_from_hdr( .unwrap() } -fn fill_queue(vq: &mut VirtQueue, num_bufs: u16, buf_size: u32) { +fn fill_queue(vq: &mut VirtQueue, num_bufs: u16, buf_size: u32) { for _ in 0..num_bufs { let buff_tkn = buffer_token_from_hdr(Box::::new_uninit_in(DeviceAlloc), buf_size); @@ -178,13 +175,13 @@ fn fill_queue(vq: &mut VirtQueue, num_bufs: u16, buf_size: u32) { /// Structure which handles transmission of packets and delegation /// to the respective queue structures. -pub struct TxQueues { - vqs: Vec, +pub struct TxQueues { + vqs: Vec>, buf_size: u32, } -impl TxQueues { - pub fn new(vqs: Vec, dev_cfg: &NetDevCfg) -> Self { +impl TxQueues { + pub fn new(vqs: Vec>, dev_cfg: &NetDevCfg) -> Self { Self { vqs, buf_size: determine_mtu(dev_cfg).into(), @@ -218,7 +215,7 @@ impl TxQueues { released_buffers } - fn add(&mut self, vq: VirtQueue) { + fn add(&mut self, vq: VirtQueue) { // Currently we are doing nothing with the additional queues. They are inactive and might be used in the // future self.vqs.push(vq); @@ -226,11 +223,11 @@ impl TxQueues { } pub(crate) struct Uninit; -pub(crate) struct Init { +pub(crate) struct Init { pub(super) mtu: u16, - pub(super) ctrl_vq: Option, - pub(super) recv_vqs: RxQueues, - pub(super) send_vqs: TxQueues, + pub(super) ctrl_vq: Option>, + pub(super) recv_vqs: RxQueues, + pub(super) send_vqs: TxQueues, /// Capacity in number of buffer descriptors, not frames. pub(super) send_capacity: u32, } @@ -239,11 +236,11 @@ pub(crate) struct Init { /// /// Struct allows to control devices virtqueues as also /// the device itself. -pub(crate) struct VirtioNetDriver { +pub(crate) struct VirtioNetDriver> { pub(super) dev_cfg: NetDevCfg, - pub(super) com_cfg: ComCfg, - pub(super) isr_stat: IsrStatus, - pub(super) notif_cfg: NotifCfg, + pub(super) com_cfg: Tr::ComCfg, + pub(super) isr_stat: Tr::IsrStatus, + pub(super) notif_cfg: Tr::NotifCfg, pub(super) inner: T, @@ -255,19 +252,19 @@ pub(crate) struct VirtioNetDriver { pub(super) checksums: ChecksumCapabilities, } -pub struct TxToken<'a> { - send_vqs: &'a mut TxQueues, +pub struct TxToken<'a, T: Transport> { + send_vqs: &'a mut TxQueues, checksums: ChecksumCapabilities, send_capacity: &'a mut u32, } -impl Drop for TxToken<'_> { +impl Drop for TxToken<'_, T> { fn drop(&mut self) { *self.send_capacity += u32::from(BUFF_PER_PACKET); } } -impl smoltcp::phy::TxToken for TxToken<'_> { +impl smoltcp::phy::TxToken for TxToken<'_, T> { fn consume(self, len: usize, f: F) -> R where F: FnOnce(&mut [u8]) -> R, @@ -289,7 +286,7 @@ impl smoltcp::phy::TxToken for TxToken<'_> { // If a checksum calculation by the host is necessary, we have to inform the host within the header // see Virtio specification 5.1.6.2 if let Some((ip_header_len, csum_offset)) = - VirtioNetDriver::should_request_checksum(&token.checksums, &mut packet) + VirtioNetDriver::::should_request_checksum(&token.checksums, &mut packet) { header.flags = HdrF::NEEDS_CSUM; header.csum_start = @@ -311,13 +308,13 @@ impl smoltcp::phy::TxToken for TxToken<'_> { } } -pub struct RxToken<'a> { - recv_vqs: &'a mut RxQueues, +pub struct RxToken<'a, T: Transport> { + recv_vqs: &'a mut RxQueues, is_mrg_rxbuf_enabled: bool, checksums: ChecksumCapabilities, } -impl RxToken<'_> { +impl RxToken<'_, T> { /// If we advertised receive checksum offload to smoltcp, we need to validate the packet /// either by checking its virtio-net headers or checksum. Otherwise, it's smoltcp's responsibility /// to validate the frame and we can pass the frame directly. @@ -417,7 +414,7 @@ impl RxToken<'_> { } } -impl smoltcp::phy::RxToken for RxToken<'_> { +impl smoltcp::phy::RxToken for RxToken<'_, T> { fn consume(self, f: F) -> R where F: FnOnce(&[u8]) -> R, @@ -493,7 +490,7 @@ impl smoltcp::phy::RxToken for RxToken<'_> { } } -impl NetworkDriver for VirtioNetDriver { +impl NetworkDriver for VirtioNetDriver> { /// Returns the mac address of the device. /// If VIRTIO_NET_F_MAC is not set, the function panics currently! fn get_mac_address(&self) -> [u8; 6] { @@ -522,14 +519,9 @@ impl NetworkDriver for VirtioNetDriver { fn handle_interrupt(&mut self) { let status = self.isr_stat.acknowledge(); - #[cfg(not(feature = "pci"))] - if status.contains(virtio::mmio::InterruptStatus::CONFIGURATION_CHANGE_NOTIFICATION) { - info!("Configuration changes are not possible! Aborting"); - todo!("Implement possibility to change config on the fly...") - } - - #[cfg(feature = "pci")] - if status.contains(virtio::pci::IsrStatus::DEVICE_CONFIGURATION_INTERRUPT) { + if status & ::CONFIGURATION_CHANGE + == ::CONFIGURATION_CHANGE + { info!("Configuration changes are not possible! Aborting"); todo!("Implement possibility to change config on the fly...") } @@ -538,9 +530,15 @@ impl NetworkDriver for VirtioNetDriver { } } -impl smoltcp::phy::Device for VirtioNetDriver { - type TxToken<'a> = TxToken<'a>; - type RxToken<'a> = RxToken<'a>; +impl smoltcp::phy::Device for VirtioNetDriver { + type TxToken<'a> + = TxToken<'a, T> + where + T: 'a; + type RxToken<'a> + = RxToken<'a, T> + where + T: 'a; fn capabilities(&self) -> DeviceCapabilities { let mut device_capabilities = DeviceCapabilities::default(); @@ -597,7 +595,7 @@ impl smoltcp::phy::Device for VirtioNetDriver { } } -impl Driver for VirtioNetDriver { +impl Driver for VirtioNetDriver> { fn get_interrupt_number(&self) -> InterruptLine { self.irq } @@ -608,7 +606,7 @@ impl Driver for VirtioNetDriver { } // Backend-independent interface for Virtio network driver -impl VirtioNetDriver { +impl VirtioNetDriver> { #[cfg(feature = "pci")] pub fn get_dev_id(&self) -> u16 { self.dev_cfg.dev_id @@ -751,13 +749,13 @@ impl VirtioNetDriver { } } -impl VirtioNetDriver { +impl VirtioNetDriver { /// Initializes the device in adherence to specification. Returns Some(VirtioNetError) /// upon failure and None in case everything worked as expected. /// /// See Virtio specification v1.1. - 3.1.1. /// and v1.1. - 5.1.5 - pub fn init_dev(mut self) -> Result, VirtioNetError> { + pub fn init_dev(mut self) -> Result>, VirtioNetError> { // Reset self.com_cfg.reset_dev(); @@ -824,11 +822,11 @@ impl VirtioNetDriver { return Err(VirtioNetError::FailFeatureNeg(self.dev_cfg.dev_id)); } - let mut inner = Init { + let mut inner = Init:: { mtu: determine_mtu(&self.dev_cfg), ctrl_vq: None, - recv_vqs: RxQueues::new(Vec::new(), &self.dev_cfg), - send_vqs: TxQueues::new(Vec::new(), &self.dev_cfg), + recv_vqs: RxQueues::::new(Vec::new(), &self.dev_cfg), + send_vqs: TxQueues::::new(Vec::new(), &self.dev_cfg), send_capacity: 0, }; @@ -870,7 +868,7 @@ impl VirtioNetDriver { } /// Device Specific initialization according to Virtio specifictation v1.1. - 5.1.5 - fn dev_spec_init(&mut self, inner: &mut Init) -> Result<(), VirtioNetError> { + fn dev_spec_init(&mut self, inner: &mut Init) -> Result<(), VirtioNetError> { self.virtqueue_init(inner)?; info!("Network driver successfully initialized virtqueues."); @@ -908,7 +906,7 @@ impl VirtioNetDriver { } /// Initialize virtqueues via the queue interface and populates receiving queues - fn virtqueue_init(&mut self, inner: &mut Init) -> Result<(), VirtioNetError> { + fn virtqueue_init(&mut self, inner: &mut Init) -> Result<(), VirtioNetError> { // We are assuming here, that the device single source of truth is the // device specific configuration. Hence we do NOT check if // diff --git a/src/drivers/net/virtio/pci.rs b/src/drivers/net/virtio/pci.rs index 104ab84060..905c70eba6 100644 --- a/src/drivers/net/virtio/pci.rs +++ b/src/drivers/net/virtio/pci.rs @@ -2,16 +2,15 @@ use pci_types::CommandRegister; use smoltcp::phy::ChecksumCapabilities; use volatile::VolatileRef; -use super::{Init, Uninit}; +use super::Uninit; use crate::arch::pci::PciConfigRegion; use crate::drivers::net::virtio::{NetDevCfg, VirtioNetDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; -use crate::drivers::virtio::transport::pci; -use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; +use crate::drivers::virtio::transport::pci::{self, PciCap, Transport, UniCapsColl}; // Backend-dependent interface for Virtio network driver -impl VirtioNetDriver { +impl VirtioNetDriver { fn map_cfg(cap: &PciCap) -> Option { let dev_cfg = pci::map_dev_cfg::(cap)?; @@ -66,7 +65,7 @@ impl VirtioNetDriver { /// [VirtioNetDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html). pub(crate) fn init( device: &PciDevice, - ) -> Result, VirtioError> { + ) -> Result, VirtioError> { // enable bus master mode device.set_command(CommandRegister::BUS_MASTER_ENABLE); diff --git a/src/drivers/pci.rs b/src/drivers/pci.rs index 8b4cd34621..7fb88f12ac 100644 --- a/src/drivers/pci.rs +++ b/src/drivers/pci.rs @@ -33,6 +33,13 @@ use crate::drivers::net::virtio::VirtioNetDriver; #[cfg(feature = "virtio")] use crate::drivers::virtio::transport::pci as pci_virtio; #[cfg(feature = "virtio")] +#[cfg(any( + feature = "virtio-fs", + feature = "virtio-vsock", + feature = "virtio-console", + feature = "virtio-net" +))] +use crate::drivers::virtio::transport::pci::Transport; #[allow(unused_imports)] use crate::drivers::virtio::transport::pci::VirtioDriver; #[cfg(feature = "virtio-vsock")] @@ -331,16 +338,16 @@ pub(crate) fn print_information() { #[non_exhaustive] pub(crate) enum PciDriver { #[cfg(feature = "virtio-fs")] - VirtioFs(InterruptTicketMutex), + VirtioFs(InterruptTicketMutex>), #[cfg(feature = "virtio-console")] - VirtioConsole(InterruptTicketMutex), + VirtioConsole(InterruptTicketMutex>), #[cfg(feature = "virtio-vsock")] - VirtioVsock(InterruptTicketMutex), + VirtioVsock(InterruptTicketMutex>), } impl PciDriver { #[cfg(feature = "virtio-console")] - fn get_console_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_console_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioConsole(drv) => Some(drv), @@ -349,7 +356,7 @@ impl PciDriver { } #[cfg(feature = "virtio-vsock")] - fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex>> { #[allow(unreachable_patterns)] match self { Self::VirtioVsock(drv) => Some(drv), @@ -358,7 +365,7 @@ impl PciDriver { } #[cfg(feature = "virtio-fs")] - fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex> { + fn get_filesystem_driver(&self) -> Option<&InterruptTicketMutex>> { match self { Self::VirtioFs(drv) => Some(drv), #[allow(unreachable_patterns)] @@ -450,13 +457,14 @@ pub(crate) fn get_interrupt_handlers() -> HashMap; #[cfg(feature = "rtl8139")] pub(crate) type NetworkDevice = RTL8139Driver; #[cfg(feature = "virtio-console")] -pub(crate) fn get_console_driver() -> Option<&'static InterruptTicketMutex> { +pub(crate) fn get_console_driver() +-> Option<&'static InterruptTicketMutex>> { PCI_DRIVERS .get()? .iter() @@ -464,7 +472,8 @@ pub(crate) fn get_console_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { +pub(crate) fn get_vsock_driver() +-> Option<&'static InterruptTicketMutex>> { PCI_DRIVERS .get()? .iter() @@ -472,7 +481,8 @@ pub(crate) fn get_vsock_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { +pub(crate) fn get_filesystem_driver() +-> Option<&'static InterruptTicketMutex>> { PCI_DRIVERS .get()? .iter() diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 27f2147da4..14798a5c2a 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -13,8 +13,7 @@ use virtio::mmio::{ InterruptStatus, NotificationData, }; use virtio::{DeviceStatus, le32}; -use volatile::access::ReadOnly; -use volatile::{VolatilePtr, VolatileRef}; +use volatile::VolatileRef; use crate::drivers::InterruptLine; #[cfg(feature = "virtio-console")] @@ -42,12 +41,14 @@ impl VqCfgHandler<'_> { .queue_sel() .write(self.vq_index.into()); } +} +impl super::VqCfgHandler for VqCfgHandler<'_> { /// Sets the size of a given virtqueue. In case the provided size exceeds the maximum allowed /// size, the size is set to this maximum instead. Else size is set to the provided value. /// /// Returns the set size in form of a `u16`. - pub fn set_vq_size(&mut self, max_size: u16) -> u16 { + fn set_vq_size(&mut self, max_size: u16) -> u16 { self.select_queue(); let ptr = self.raw.as_mut_ptr(); @@ -57,7 +58,7 @@ impl VqCfgHandler<'_> { size } - pub fn set_ring_addr(&mut self, addr: PhysAddr) { + fn set_ring_addr(&mut self, addr: PhysAddr) { self.select_queue(); self.raw @@ -66,7 +67,7 @@ impl VqCfgHandler<'_> { .write(addr.as_u64().into()); } - pub fn set_drv_ctrl_addr(&mut self, addr: PhysAddr) { + fn set_drv_ctrl_addr(&mut self, addr: PhysAddr) { self.select_queue(); self.raw @@ -75,7 +76,7 @@ impl VqCfgHandler<'_> { .write(addr.as_u64().into()); } - pub fn set_dev_ctrl_addr(&mut self, addr: PhysAddr) { + fn set_dev_ctrl_addr(&mut self, addr: PhysAddr) { self.select_queue(); self.raw @@ -84,7 +85,7 @@ impl VqCfgHandler<'_> { .write(addr.as_u64().into()); } - pub fn enable_queue(&mut self) { + fn enable_queue(&mut self) { self.select_queue(); self.raw.as_mut_ptr().queue_ready().write(true); @@ -107,12 +108,35 @@ impl ComCfg { ComCfg { com_cfg: raw } } - pub fn control_registers(&mut self) -> impl ControlRegisters<'_> { + pub fn get_max_queue_size(&mut self, sel: u16) -> u16 { + let ptr = self.com_cfg.as_mut_ptr(); + ptr.queue_sel().write(sel.into()); + ptr.queue_num_max().read().to_ne() + } + + pub fn print_information(&mut self) { + let ptr = self.com_cfg.as_ptr(); + + infoheader!(" MMIO REGISTER LAYOUT INFORMATION "); + + infoentry!("Device version", "{:#X}", ptr.version().read()); + infoentry!("Device ID", "{:?}", ptr.device_id().read()); + infoentry!("Vendor ID", "{:#X}", ptr.vendor_id().read()); + let ptr = self.com_cfg.as_ptr(); + infoentry!("Interrupt status", "{:#X}", ptr.interrupt_status().read()); + infoentry!("Device status", "{:#X}", ptr.status().read()); + + infofooter!(); + } +} + +impl super::ComCfg for ComCfg { + fn control_registers(&mut self) -> impl ControlRegisters<'_> { self.com_cfg.as_mut_ptr() } #[allow(dead_code)] - pub fn device_config_space(&self) -> VolatilePtr<'_, DeviceRegisters, ReadOnly> { + fn device_config_space(&self) -> impl virtio::DeviceConfigSpace { self.com_cfg.as_ptr() } @@ -120,7 +144,7 @@ impl ComCfg { /// returns `Some(VqCfgHandler)`. /// /// INFO: The queue size is automatically bounded by constant `src::config:VIRTIO_MAX_QUEUE_SIZE`. - pub fn select_vq(&mut self, index: u16) -> Option> { + fn select_vq(&mut self, index: u16) -> Option> { if self.get_max_queue_size(index) == 0 { return None; } @@ -131,14 +155,8 @@ impl ComCfg { }) } - pub fn get_max_queue_size(&mut self, sel: u16) -> u16 { - let ptr = self.com_cfg.as_mut_ptr(); - ptr.queue_sel().write(sel.into()); - ptr.queue_num_max().read().to_ne() - } - /// Resets the device status field to zero. - pub fn reset_dev(&mut self) { + fn reset_dev(&mut self) { self.com_cfg .as_mut_ptr() .status() @@ -149,7 +167,7 @@ impl ComCfg { /// A driver MUST NOT initialize and use the device any further after this. /// A driver MAY use the device again after a proper reset of the device. #[allow(dead_code)] - pub fn set_failed(&mut self) { + fn set_failed(&mut self) { self.com_cfg .as_mut_ptr() .status() @@ -158,7 +176,7 @@ impl ComCfg { /// Sets the ACKNOWLEDGE bit in the device status field. This indicates, the /// OS has notived the device - pub fn ack_dev(&mut self) { + fn ack_dev(&mut self) { self.com_cfg .as_mut_ptr() .status() @@ -167,7 +185,7 @@ impl ComCfg { /// Sets the DRIVER bit in the device status field. This indicates, the OS /// know how to run this device. - pub fn set_drv(&mut self) { + fn set_drv(&mut self) { self.com_cfg .as_mut_ptr() .status() @@ -177,7 +195,7 @@ impl ComCfg { /// Sets the FEATURES_OK bit in the device status field. /// /// Drivers MUST NOT accept new features after this step. - pub fn features_ok(&mut self) { + fn features_ok(&mut self) { self.com_cfg .as_mut_ptr() .status() @@ -185,12 +203,12 @@ impl ComCfg { } /// In order to correctly check feature negotiaten, this function - /// MUST be called after [self.features_ok()](ComCfg::features_ok()) in order to check + /// MUST be called after [self.features_ok()](super::ComCfg::features_ok()) in order to check /// if features have been accepted by the device after negotiation. /// /// Re-reads 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. - pub fn check_features(&self) -> bool { + fn check_features(&self) -> bool { self.com_cfg .as_ptr() .status() @@ -201,27 +219,12 @@ impl ComCfg { /// Sets the DRIVER_OK bit in the device status field. /// /// After this call, the device is "live"! - pub fn drv_ok(&mut self) { + fn drv_ok(&mut self) { self.com_cfg .as_mut_ptr() .status() .update(|status| status | DeviceStatus::DRIVER_OK); } - - pub fn print_information(&mut self) { - let ptr = self.com_cfg.as_ptr(); - - infoheader!(" MMIO REGISTER LAYOUT INFORMATION "); - - infoentry!("Device version", "{:#X}", ptr.version().read()); - infoentry!("Device ID", "{:?}", ptr.device_id().read()); - infoentry!("Vendor ID", "{:#X}", ptr.vendor_id().read()); - let ptr = self.com_cfg.as_ptr(); - infoentry!("Interrupt status", "{:#X}", ptr.interrupt_status().read()); - infoentry!("Device status", "{:#X}", ptr.status().read()); - - infofooter!(); - } } /// Notification Structure to handle virtqueue notification settings. @@ -240,8 +243,10 @@ impl NotifCfg { NotifCfg { queue_notify: raw } } +} - pub fn notification_location(&self, _vq_cfg_handler: &mut VqCfgHandler<'_>) -> *mut le32 { +impl super::NotifCfg for NotifCfg { + fn notification_location(&self, _vq_cfg_handler: &mut VqCfgHandler<'_>) -> *mut le32 { self.queue_notify } } @@ -258,10 +263,12 @@ pub struct NotifCtrl { // FIXME: make `notif_addr` implement `Send` instead unsafe impl Send for NotifCtrl {} -impl NotifCtrl { +impl super::NotifCtrl for NotifCtrl { + type NotificationData = NotificationData; + /// Returns a new controller. By default MSI-X capabilities and VIRTIO_F_NOTIFICATION_DATA /// are disabled. - pub fn new(notif_addr: *mut le32) -> Self { + fn new(notif_addr: *mut le32) -> Self { NotifCtrl { f_notif_data: false, notif_addr, @@ -269,11 +276,11 @@ impl NotifCtrl { } /// Enables VIRTIO_F_NOTIFICATION_DATA. This changes which data is provided to the device. ONLY a good idea if Feature has been negotiated. - pub fn enable_notif_data(&mut self) { + fn enable_notif_data(&mut self) { self.f_notif_data = true; } - pub fn notify_dev(&self, data: NotificationData) { + fn notify_dev(&self, data: NotificationData) { let notification_data = if self.f_notif_data { data.into_bits() } else { @@ -286,6 +293,28 @@ impl NotifCtrl { } } +impl super::NotificationData for NotificationData { + fn new() -> Self { + NotificationData::new() + } + + fn with_next_idx(self, value: u16) -> Self { + self.with_next_idx(value) + } + + fn with_next_off(self, value: u16) -> Self { + self.with_next_off(value) + } + + fn with_next_wrap(self, value: u8) -> Self { + self.with_next_wrap(value) + } + + fn with_vqn(self, value: u16) -> Self { + self.with_vqn(value) + } +} + /// Wraps a [`DeviceRegisters`] in order to preserve /// the original structure and allow interaction with the device via /// the structure. @@ -303,8 +332,14 @@ impl IsrStatus { unsafe { mem::transmute::, VolatileRef<'static, _>>(registers) }; Self { raw } } +} + +impl super::IsrStatus for IsrStatus { + type Status = InterruptStatus; + const CONFIGURATION_CHANGE: InterruptStatus = + InterruptStatus::CONFIGURATION_CHANGE_NOTIFICATION; - pub fn acknowledge(&mut self) -> InterruptStatus { + fn acknowledge(&mut self) -> InterruptStatus { let ptr = self.raw.as_mut_ptr(); let status = ptr.interrupt_status().read(); ptr.interrupt_ack().write(status); @@ -314,13 +349,13 @@ impl IsrStatus { pub(crate) enum VirtioDriver { #[cfg(feature = "virtio-console")] - Console(alloc::boxed::Box), + Console(alloc::boxed::Box>), #[cfg(feature = "virtio-fs")] - Fs(alloc::boxed::Box), + Fs(alloc::boxed::Box>), #[cfg(feature = "virtio-net")] - Net(alloc::boxed::Box), + Net(alloc::boxed::Box>), #[cfg(feature = "virtio-vsock")] - Vsock(alloc::boxed::Box), + Vsock(alloc::boxed::Box>), } #[allow(unused_variables)] @@ -417,3 +452,13 @@ pub(crate) fn init_device( } } } + +pub struct Transport {} + +impl super::Transport for Transport { + type ComCfg = ComCfg; + type NotifCfg = NotifCfg; + type IsrStatus = IsrStatus; + type VqCfgHandler<'a> = VqCfgHandler<'a>; + type NotifCtrl = NotifCtrl; +} diff --git a/src/drivers/virtio/transport/mod.rs b/src/drivers/virtio/transport/mod.rs index 81fb06af41..3d14569078 100644 --- a/src/drivers/virtio/transport/mod.rs +++ b/src/drivers/virtio/transport/mod.rs @@ -1,4 +1,67 @@ +use core::ops::BitAnd; + +use memory_addresses::PhysAddr; +use virtio::{DeviceConfigSpace, le32}; + #[cfg(not(feature = "pci"))] pub mod mmio; #[cfg(feature = "pci")] pub mod pci; + +pub trait Transport: Sized { + type ComCfg: ComCfg; + type NotifCfg: NotifCfg; + type IsrStatus: IsrStatus; + type VqCfgHandler<'a>: VqCfgHandler; + type NotifCtrl: NotifCtrl + Send; +} + +pub trait ComCfg { + fn reset_dev(&mut self); + fn ack_dev(&mut self); + fn set_drv(&mut self); + fn control_registers(&mut self) -> impl super::ControlRegisters<'_>; + fn features_ok(&mut self); + fn check_features(&self) -> bool; + fn select_vq(&mut self, index: u16) -> Option>; + fn drv_ok(&mut self); + #[allow(dead_code)] + fn set_failed(&mut self); + #[allow(dead_code)] + fn device_config_space(&self) -> impl DeviceConfigSpace; +} + +pub trait NotifCfg { + fn notification_location(&self, vq_cfg_handler: &mut T::VqCfgHandler<'_>) -> *mut le32; +} + +pub trait IsrStatus { + type Status: BitAnd + PartialEq + Copy; + const CONFIGURATION_CHANGE: Self::Status; + + fn acknowledge(&mut self) -> Self::Status; +} + +pub trait VqCfgHandler { + fn enable_queue(&mut self); + fn set_dev_ctrl_addr(&mut self, addr: PhysAddr); + fn set_drv_ctrl_addr(&mut self, addr: PhysAddr); + fn set_ring_addr(&mut self, addr: PhysAddr); + fn set_vq_size(&mut self, max_size: u16) -> u16; +} + +pub trait NotifCtrl { + type NotificationData: NotificationData; + + fn new(notif_addr: *mut le32) -> Self; + fn notify_dev(&self, data: Self::NotificationData); + fn enable_notif_data(&mut self); +} + +pub trait NotificationData { + fn new() -> Self; + fn with_next_idx(self, value: u16) -> Self; + fn with_next_off(self, value: u16) -> Self; + fn with_next_wrap(self, value: u8) -> Self; + fn with_vqn(self, value: u16) -> Self; +} diff --git a/src/drivers/virtio/transport/pci.rs b/src/drivers/virtio/transport/pci.rs index babe017063..fe9a64de0e 100644 --- a/src/drivers/virtio/transport/pci.rs +++ b/src/drivers/virtio/transport/pci.rs @@ -15,8 +15,7 @@ use virtio::pci::{ IsrStatus as IsrStatusRaw, NotificationData, }; use virtio::{DeviceStatus, le16, le32}; -use volatile::access::ReadOnly; -use volatile::{VolatilePtr, VolatileRef}; +use volatile::VolatileRef; use crate::arch::pci::PciConfigRegion; #[cfg(feature = "virtio-console")] @@ -212,12 +211,14 @@ impl VqCfgHandler<'_> { .queue_select() .write(self.vq_index.into()); } +} +impl super::VqCfgHandler for VqCfgHandler<'_> { /// Sets the size of a given virtqueue. In case the provided size exceeds the maximum allowed /// size, the size is set to this maximum instead. Else size is set to the provided value. /// /// Returns the set size in form of a `u16`. - pub fn set_vq_size(&mut self, max_size: u16) -> u16 { + fn set_vq_size(&mut self, max_size: u16) -> u16 { self.select_queue(); let queue_size = self.raw.as_mut_ptr().queue_size(); @@ -231,7 +232,7 @@ impl VqCfgHandler<'_> { } } - pub fn set_ring_addr(&mut self, addr: PhysAddr) { + fn set_ring_addr(&mut self, addr: PhysAddr) { self.select_queue(); self.raw .as_mut_ptr() @@ -239,7 +240,7 @@ impl VqCfgHandler<'_> { .write(addr.as_u64().into()); } - pub fn set_drv_ctrl_addr(&mut self, addr: PhysAddr) { + fn set_drv_ctrl_addr(&mut self, addr: PhysAddr) { self.select_queue(); self.raw .as_mut_ptr() @@ -247,7 +248,7 @@ impl VqCfgHandler<'_> { .write(addr.as_u64().into()); } - pub fn set_dev_ctrl_addr(&mut self, addr: PhysAddr) { + fn set_dev_ctrl_addr(&mut self, addr: PhysAddr) { self.select_queue(); self.raw .as_mut_ptr() @@ -255,20 +256,22 @@ impl VqCfgHandler<'_> { .write(addr.as_u64().into()); } - pub fn notif_off(&mut self) -> u16 { + fn enable_queue(&mut self) { self.select_queue(); - self.raw.as_mut_ptr().queue_notify_off().read().to_ne() + self.raw.as_mut_ptr().queue_enable().write(1.into()); } +} - pub fn enable_queue(&mut self) { +impl VqCfgHandler<'_> { + fn notif_off(&mut self) -> u16 { self.select_queue(); - self.raw.as_mut_ptr().queue_enable().write(1.into()); + self.raw.as_mut_ptr().queue_notify_off().read().to_ne() } } // Public Interface of ComCfg -impl ComCfg { - pub fn control_registers(&mut self) -> impl ControlRegisters<'_> { +impl super::ComCfg for ComCfg { + fn control_registers(&mut self) -> impl ControlRegisters<'_> { self.com_cfg.as_mut_ptr() } @@ -276,7 +279,7 @@ impl ComCfg { /// returns `Some(VqCfgHandler)`. /// /// INFO: The queue size is automatically bounded by constant `src::config:VIRTIO_MAX_QUEUE_SIZE`. - pub fn select_vq(&mut self, index: u16) -> Option> { + fn select_vq(&mut self, index: u16) -> Option> { self.com_cfg.as_mut_ptr().queue_select().write(index.into()); if self.com_cfg.as_mut_ptr().queue_size().read().to_ne() == 0 { @@ -290,12 +293,12 @@ impl ComCfg { } #[allow(dead_code)] - pub fn device_config_space(&self) -> VolatilePtr<'_, CommonCfg, ReadOnly> { + fn device_config_space(&self) -> impl virtio::DeviceConfigSpace { self.com_cfg.as_ptr() } /// Resets the device status field to zero. - pub fn reset_dev(&mut self) { + fn reset_dev(&mut self) { self.com_cfg .as_mut_ptr() .device_status() @@ -306,7 +309,7 @@ impl ComCfg { /// A driver MUST NOT initialize and use the device any further after this. /// A driver MAY use the device again after a proper reset of the device. #[allow(dead_code)] - pub fn set_failed(&mut self) { + fn set_failed(&mut self) { self.com_cfg .as_mut_ptr() .device_status() @@ -315,7 +318,7 @@ impl ComCfg { /// Sets the ACKNOWLEDGE bit in the device status field. This indicates, the /// OS has notived the device - pub fn ack_dev(&mut self) { + fn ack_dev(&mut self) { self.com_cfg .as_mut_ptr() .device_status() @@ -324,7 +327,7 @@ impl ComCfg { /// Sets the DRIVER bit in the device status field. This indicates, the OS /// know how to run this device. - pub fn set_drv(&mut self) { + fn set_drv(&mut self) { self.com_cfg .as_mut_ptr() .device_status() @@ -334,7 +337,7 @@ impl ComCfg { /// Sets the FEATURES_OK bit in the device status field. /// /// Drivers MUST NOT accept new features after this step. - pub fn features_ok(&mut self) { + fn features_ok(&mut self) { self.com_cfg .as_mut_ptr() .device_status() @@ -342,12 +345,12 @@ impl ComCfg { } /// In order to correctly check feature negotiaten, this function - /// MUST be called after [self.features_ok()](ComCfg::features_ok()) in order to check + /// MUST be called after [self.features_ok()](super::ComCfg::features_ok()) in order to check /// if features have been accepted by the device after negotiation. /// /// Re-reads 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. - pub fn check_features(&self) -> bool { + fn check_features(&self) -> bool { let status = self.com_cfg.as_ptr().device_status().read(); status.contains(DeviceStatus::FEATURES_OK) } @@ -355,7 +358,7 @@ impl ComCfg { /// Sets the DRIVER_OK bit in the device status field. /// /// After this call, the device is "live"! - pub fn drv_ok(&mut self) { + fn drv_ok(&mut self) { self.com_cfg .as_mut_ptr() .device_status() @@ -403,8 +406,10 @@ impl NotifCfg { length: cap.len(), }) } +} - pub fn notification_location(&self, vq_cfg_handler: &mut VqCfgHandler<'_>) -> *mut le32 { +impl super::NotifCfg for NotifCfg { + fn notification_location(&self, vq_cfg_handler: &mut VqCfgHandler<'_>) -> *mut le32 { let addend = u32::from(vq_cfg_handler.notif_off()) * self.notify_off_multiplier; // TODO: This should be @@ -431,10 +436,12 @@ pub struct NotifCtrl { // FIXME: make `notif_addr` implement `Send` instead unsafe impl Send for NotifCtrl {} -impl NotifCtrl { +impl super::NotifCtrl for NotifCtrl { + type NotificationData = NotificationData; + /// Returns a new controller. By default MSI-X capabilities and VIRTIO_F_NOTIFICATION_DATA /// are disabled. - pub fn new(notif_addr: *mut le32) -> Self { + fn new(notif_addr: *mut le32) -> Self { NotifCtrl { f_notif_data: false, notif_addr, @@ -442,11 +449,11 @@ impl NotifCtrl { } /// Enables VIRTIO_F_NOTIFICATION_DATA. This changes which data is provided to the device. ONLY a good idea if Feature has been negotiated. - pub fn enable_notif_data(&mut self) { + fn enable_notif_data(&mut self) { self.f_notif_data = true; } - pub fn notify_dev(&self, data: NotificationData) { + fn notify_dev(&self, data: NotificationData) { // See Virtio specification v.1.1. - 4.1.5.2 // Depending in the feature negotiation, we write either only the // virtqueue index or the index and the next position inside the queue. @@ -465,6 +472,28 @@ impl NotifCtrl { } } +impl super::NotificationData for NotificationData { + fn new() -> Self { + NotificationData::new() + } + + fn with_next_idx(self, value: u16) -> Self { + self.with_next_idx(value) + } + + fn with_next_off(self, value: u16) -> Self { + self.with_next_off(value) + } + + fn with_next_wrap(self, value: u8) -> Self { + self.with_next_wrap(value) + } + + fn with_vqn(self, value: u16) -> Self { + self.with_vqn(value) + } +} + /// Wraps a [IsrStatusRaw] in order to preserve /// the original structure and allow interaction with the device via /// the structure. @@ -481,8 +510,13 @@ impl IsrStatus { fn new(raw: VolatileRef<'static, IsrStatusRaw>) -> Self { IsrStatus { isr_stat: raw } } +} + +impl super::IsrStatus for IsrStatus { + type Status = IsrStatusRaw; + const CONFIGURATION_CHANGE: IsrStatusRaw = IsrStatusRaw::DEVICE_CONFIGURATION_INTERRUPT; - pub fn acknowledge(&mut self) -> IsrStatusRaw { + fn acknowledge(&mut self) -> IsrStatusRaw { self.isr_stat.as_ptr().read() } } @@ -642,7 +676,7 @@ pub(crate) fn init_device( match id { #[cfg(feature = "virtio-console")] - virtio::Id::Console => match VirtioConsoleDriver::init(device) { + virtio::Id::Console => match VirtioConsoleDriver::::init(device) { Ok(virt_console_drv) => { info!("Virtio console driver initialized."); @@ -663,7 +697,7 @@ pub(crate) fn init_device( virtio::Id::Fs => { // TODO: check subclass // TODO: proper error handling on driver creation fail - match VirtioFsDriver::init(device) { + match VirtioFsDriver::::init(device) { Ok(virt_fs_drv) => { info!("Virtio filesystem driver initialized."); let irq = device.get_irq().unwrap(); @@ -683,7 +717,7 @@ pub(crate) fn init_device( not(feature = "rtl8139"), feature = "virtio-net", ))] - virtio::Id::Net => match VirtioNetDriver::init(device) { + virtio::Id::Net => match VirtioNetDriver::::init(device) { Ok(virt_net_drv) => { info!("Virtio network driver initialized."); @@ -701,7 +735,7 @@ pub(crate) fn init_device( } }, #[cfg(feature = "virtio-vsock")] - virtio::Id::Vsock => match VirtioVsockDriver::init(device) { + virtio::Id::Vsock => match VirtioVsockDriver::::init(device) { Ok(virt_sock_drv) => { info!("Virtio sock driver initialized."); @@ -734,15 +768,25 @@ pub(crate) fn init_device( pub(crate) enum VirtioDriver { #[cfg(feature = "virtio-console")] - Console(alloc::boxed::Box), + Console(alloc::boxed::Box>), #[cfg(feature = "virtio-fs")] - Fs(alloc::boxed::Box), + Fs(alloc::boxed::Box>), #[cfg(all( not(all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci"))), not(feature = "rtl8139"), feature = "virtio-net", ))] - Net(alloc::boxed::Box), + Net(alloc::boxed::Box>), #[cfg(feature = "virtio-vsock")] - Vsock(alloc::boxed::Box), + Vsock(alloc::boxed::Box>), +} + +pub struct Transport {} + +impl super::Transport for Transport { + type ComCfg = ComCfg; + type IsrStatus = IsrStatus; + type NotifCfg = NotifCfg; + type NotifCtrl = NotifCtrl; + type VqCfgHandler<'a> = VqCfgHandler<'a>; } diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index 592882e301..3099e4109b 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -22,6 +22,7 @@ use smallvec::SmallVec; use virtio::{le32, le64, pvirtq, virtq}; use self::error::VirtqError; +use crate::drivers::virtio::transport::Transport; use crate::drivers::virtio::virtqueue::packed::PackedVq; use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::mm::device_alloc::DeviceAlloc; @@ -226,9 +227,9 @@ trait VirtqPrivate { } #[enum_dispatch(Virtq)] -pub(crate) enum VirtQueue { - Split(SplitVq), - Packed(PackedVq), +pub(crate) enum VirtQueue { + Split(SplitVq), + Packed(PackedVq), } trait VirtqDescriptor { diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index c73773de32..c2e402deba 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -14,22 +14,17 @@ use core::ops; use core::sync::atomic::{Ordering, fence}; use align_address::Align; -#[cfg(not(feature = "pci"))] -use virtio::mmio::NotificationData; -#[cfg(feature = "pci")] -use virtio::pci::NotificationData; use virtio::pvirtq::{EventSuppressDesc, EventSuppressFlags}; use virtio::virtq::DescF; use virtio::{RingEventFlags, pvirtq}; -#[cfg(not(feature = "pci"))] -use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; -#[cfg(feature = "pci")] -use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::index_alloc::IndexAlloc; use super::{AvailBufferToken, BufferType, TransferToken, UsedBufferToken, Virtq, VirtqPrivate}; use crate::arch::mm::paging::{BasePageSize, PageSize}; +use crate::drivers::virtio::transport::{ + ComCfg, NotifCfg, NotifCtrl, NotificationData, Transport, VqCfgHandler, +}; use crate::mm::device_alloc::DeviceAlloc; trait RingIndexRange { @@ -92,7 +87,7 @@ impl DescriptorRing { let poll_index = write_index; - DescriptorRing { + Self { ring, tkn_ref_ring, write_index, @@ -113,7 +108,7 @@ impl DescriptorRing { .ok_or(VirtqError::NoNewUsed) } - fn push_batch( + fn push_batch( &mut self, tkn_lst: impl IntoIterator>, ) -> Result { @@ -126,7 +121,7 @@ impl DescriptorRing { return Err(VirtqError::BufferNotSpecified); }; - let mut ctrl = self.push_without_making_available(&first_tkn)?; + let mut ctrl = self.push_without_making_available::(&first_tkn)?; let first_ctrl_settings = (ctrl.start, ctrl.buff_id, ctrl.first_flags); let first_buffer = first_tkn; @@ -148,11 +143,14 @@ impl DescriptorRing { Ok(self.write_index) } - fn push(&mut self, tkn: TransferToken) -> Result { - self.push_batch([tkn]) + fn push( + &mut self, + tkn: TransferToken, + ) -> Result { + self.push_batch::([tkn]) } - fn push_without_making_available( + fn push_without_making_available( &mut self, tkn: &TransferToken, ) -> Result, VirtqError> { @@ -170,10 +168,10 @@ impl DescriptorRing { // The buffer uses indirect descriptors if the ctrl_desc field is Some. if let Some(ctrl_desc) = tkn.ctrl_desc.as_ref() { - let desc = PackedVq::indirect_desc(ctrl_desc.as_ref()); + let desc = PackedVq::::indirect_desc(ctrl_desc.as_ref()); ctrl.write_desc(desc); } else { - for incomplete_desc in PackedVq::descriptor_iter(&tkn.buff_tkn)? { + for incomplete_desc in PackedVq::::descriptor_iter(&tkn.buff_tkn)? { ctrl.write_desc(incomplete_desc); } } @@ -484,7 +482,7 @@ impl DevNotif { /// Packed virtqueue which provides the functionilaty as described in the /// virtio specification v1.1. - 2.7 -pub struct PackedVq { +pub struct PackedVq { /// Ring which allows easy access to the raw ring structure of the /// specification descr_ring: DescriptorRing, @@ -493,7 +491,7 @@ pub struct PackedVq { /// Allows to check, if the device wants a notification dev_event: DevNotif, /// Actually notify device about avail buffers - notif_ctrl: NotifCtrl, + notif_ctrl: T::NotifCtrl, /// The size of the queue, equals the number of descriptors which can /// be used size: u16, @@ -505,7 +503,7 @@ pub struct PackedVq { // Public interface of PackedVq // This interface is also public in order to allow people to use the PackedVq directly! -impl Virtq for PackedVq { +impl Virtq for PackedVq { fn enable_notifs(&mut self) { self.drv_event.enable_notif(); } @@ -530,7 +528,7 @@ impl Virtq for PackedVq { Self::transfer_token_from_buffer_token(buffer_tkn, buffer_type) }); - let next_idx = self.descr_ring.push_batch(transfer_tkns)?; + let next_idx = self.descr_ring.push_batch::(transfer_tkns)?; if notif { self.drv_event.enable_specific(next_idx); @@ -543,7 +541,7 @@ impl Virtq for PackedVq { .is_some_and(|idx| range.wrapping_contains(&idx)); if self.dev_event.is_notif() || notif_specific { - let notification_data = NotificationData::new() + let notification_data = ::NotificationData::new() .with_vqn(self.index) .with_next_off(next_idx.desc_event_off()) .with_next_wrap(next_idx.desc_event_wrap()); @@ -565,7 +563,7 @@ impl Virtq for PackedVq { Self::transfer_token_from_buffer_token(buffer_tkn, buffer_type) }); - let next_idx = self.descr_ring.push_batch(transfer_tkns)?; + let next_idx = self.descr_ring.push_batch::(transfer_tkns)?; if notif { self.drv_event.enable_specific(next_idx); @@ -578,7 +576,7 @@ impl Virtq for PackedVq { .is_some_and(|idx| range.wrapping_contains(&idx)); if self.dev_event.is_notif() | notif_specific { - let notification_data = NotificationData::new() + let notification_data = ::NotificationData::new() .with_vqn(self.index) .with_next_off(next_idx.desc_event_off()) .with_next_wrap(next_idx.desc_event_wrap()); @@ -595,7 +593,7 @@ impl Virtq for PackedVq { buffer_type: BufferType, ) -> Result<(), VirtqError> { let transfer_tkn = Self::transfer_token_from_buffer_token(buffer_tkn, buffer_type); - let next_idx = self.descr_ring.push(transfer_tkn)?; + let next_idx = self.descr_ring.push::(transfer_tkn)?; if notif { self.drv_event.enable_specific(next_idx); @@ -609,7 +607,7 @@ impl Virtq for PackedVq { == Some(self.last_next.get().into_bits()); if self.dev_event.is_notif() || notif_specific { - let notification_data = NotificationData::new() + let notification_data = ::NotificationData::new() .with_vqn(self.index) .with_next_off(next_idx.desc_event_off()) .with_next_wrap(next_idx.desc_event_wrap()); @@ -633,7 +631,7 @@ impl Virtq for PackedVq { } } -impl VirtqPrivate for PackedVq { +impl VirtqPrivate for PackedVq { type Descriptor = pvirtq::Desc; fn create_indirect_ctrl( @@ -645,11 +643,11 @@ impl VirtqPrivate for PackedVq { } } -impl PackedVq { +impl PackedVq { #[allow(dead_code)] pub(crate) fn new( - com_cfg: &mut ComCfg, - notif_cfg: &NotifCfg, + com_cfg: &mut T::ComCfg, + notif_cfg: &T::NotifCfg, max_size: u16, index: u16, features: virtio::F, @@ -709,7 +707,7 @@ impl PackedVq { raw: dev_event, }; - let mut notif_ctrl = NotifCtrl::new(notif_cfg.notification_location(&mut vq_handler)); + let mut notif_ctrl = T::NotifCtrl::new(notif_cfg.notification_location(&mut vq_handler)); if features.contains(virtio::F::NOTIFICATION_DATA) { notif_ctrl.enable_notif_data(); diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index cc584053bb..5a49715b44 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -13,19 +13,14 @@ use core::cell::UnsafeCell; use core::mem::{self, MaybeUninit}; use mem_barrier::BarrierType; -#[cfg(not(feature = "pci"))] -use virtio::mmio::NotificationData; -#[cfg(feature = "pci")] -use virtio::pci::NotificationData; use virtio::{le16, virtq}; -#[cfg(not(feature = "pci"))] -use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; -#[cfg(feature = "pci")] -use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::index_alloc::IndexAlloc; use super::{AvailBufferToken, BufferType, TransferToken, UsedBufferToken, Virtq, VirtqPrivate}; +use crate::drivers::virtio::transport::{ + ComCfg, NotifCfg, NotifCtrl, NotificationData, Transport, VqCfgHandler, +}; use crate::mm::device_alloc::DeviceAlloc; struct DescrRing { @@ -54,15 +49,15 @@ impl DescrRing { unsafe { &*self.used_ring_cell.get() } } - fn push(&mut self, tkn: TransferToken) -> Result { + fn push(&mut self, tkn: TransferToken) -> Result { let mut index; if let Some(ctrl_desc) = tkn.ctrl_desc.as_ref() { - let descriptor = SplitVq::indirect_desc(ctrl_desc.as_ref()); + let descriptor = SplitVq::::indirect_desc(ctrl_desc.as_ref()); index = self.indexes.allocate().ok_or(VirtqError::NoDescrAvail)?; self.descr_table_mut()[index] = MaybeUninit::new(descriptor); } else { - let mut rev_all_desc_iter = SplitVq::descriptor_iter(&tkn.buff_tkn)?.rev(); + let mut rev_all_desc_iter = SplitVq::::descriptor_iter(&tkn.buff_tkn)?.rev(); // We need to handle the last descriptor (the first for the reversed iterator) specially to not set the next flag. { @@ -151,15 +146,15 @@ impl DescrRing { } /// Virtio's split virtqueue structure -pub struct SplitVq { +pub struct SplitVq { ring: DescrRing, size: u16, index: u16, - notif_ctrl: NotifCtrl, + notif_ctrl: T::NotifCtrl, } -impl Virtq for SplitVq { +impl Virtq for SplitVq { fn enable_notifs(&mut self) { self.ring.drv_enable_notif(); } @@ -195,7 +190,7 @@ impl Virtq for SplitVq { buffer_type: BufferType, ) -> Result<(), VirtqError> { let transfer_tkn = Self::transfer_token_from_buffer_token(buffer_tkn, buffer_type); - let next_idx = self.ring.push(transfer_tkn)?; + let next_idx = self.ring.push::(transfer_tkn)?; if notif { // TODO: Check whether the splitvirtquue has notifications for specific descriptors @@ -204,7 +199,7 @@ impl Virtq for SplitVq { } if self.ring.dev_is_notif() { - let notification_data = NotificationData::new() + let notification_data = ::NotificationData::new() .with_vqn(self.index) .with_next_idx(next_idx); self.notif_ctrl.notify_dev(notification_data); @@ -225,7 +220,7 @@ impl Virtq for SplitVq { } } -impl VirtqPrivate for SplitVq { +impl VirtqPrivate for SplitVq { type Descriptor = virtq::Desc; fn create_indirect_ctrl( buffer_tkn: &AvailBufferToken, @@ -241,10 +236,10 @@ impl VirtqPrivate for SplitVq { } } -impl SplitVq { +impl SplitVq { pub(crate) fn new( - com_cfg: &mut ComCfg, - notif_cfg: &NotifCfg, + com_cfg: &mut T::ComCfg, + notif_cfg: &T::NotifCfg, max_size: u16, index: u16, features: virtio::F, @@ -309,7 +304,7 @@ impl SplitVq { order_platform, }; - let mut notif_ctrl = NotifCtrl::new(notif_cfg.notification_location(&mut vq_handler)); + let mut notif_ctrl = T::NotifCtrl::new(notif_cfg.notification_location(&mut vq_handler)); if features.contains(virtio::F::NOTIFICATION_DATA) { notif_ctrl.enable_notif_data(); diff --git a/src/drivers/vsock/mmio.rs b/src/drivers/vsock/mmio.rs index 071d1735c7..83ef312b17 100644 --- a/src/drivers/vsock/mmio.rs +++ b/src/drivers/vsock/mmio.rs @@ -1,19 +1,19 @@ -use virtio::vsock::Config; use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; +use virtio::vsock::Config; use volatile::VolatileRef; use crate::drivers::InterruptLine; -use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; use crate::drivers::virtio::error::VirtioError; -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg, Transport}; +use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; // Backend-dependent interface for Virtio vsock driver -impl VirtioVsockDriver { +impl VirtioVsockDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result { + ) -> Result { let dev_cfg_raw: &'static Config = unsafe { &*registers .borrow_mut() @@ -53,7 +53,7 @@ impl VirtioVsockDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, - ) -> Result { + ) -> Result { let mut drv = VirtioVsockDriver::new(dev_id, registers, irq)?; drv.init_dev().map_err(VirtioError::VsockDriver)?; drv.com_cfg.print_information(); diff --git a/src/drivers/vsock/mod.rs b/src/drivers/vsock/mod.rs index 77588be9d1..77340c3157 100644 --- a/src/drivers/vsock/mod.rs +++ b/src/drivers/vsock/mod.rs @@ -23,17 +23,14 @@ use crate::config::VIRTIO_MAX_QUEUE_SIZE; use crate::drivers::Driver; use crate::drivers::virtio::ControlRegisters; use crate::drivers::virtio::error::VirtioVsockError; -#[cfg(not(feature = "pci"))] -use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; -#[cfg(feature = "pci")] -use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::virtio::transport::{ComCfg, IsrStatus, Transport}; use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, Virtq, }; use crate::mm::device_alloc::DeviceAlloc; -fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { +fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { for _ in 0..num_packets { let buff_tkn = match AvailBufferToken::new( SmallVec::new(), @@ -62,12 +59,12 @@ fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { } } -pub(crate) struct RxQueue { - vq: Option, +pub(crate) struct RxQueue { + vq: Option>, packet_size: u32, } -impl RxQueue { +impl RxQueue { pub fn new() -> Self { Self { vq: None, @@ -76,7 +73,7 @@ impl RxQueue { } } - pub fn add(&mut self, mut vq: VirtQueue) { + pub fn add(&mut self, mut vq: VirtQueue) { const BUFF_PER_PACKET: u16 = 2; let num_packets = vq.size() / BUFF_PER_PACKET; info!("num_packets {num_packets}"); @@ -127,14 +124,14 @@ impl RxQueue { } } -pub(crate) struct TxQueue { - vq: Option, +pub(crate) struct TxQueue { + vq: Option>, /// Indicates, whether the Driver/Device are using multiple /// queues for communication. packet_length: u32, } -impl TxQueue { +impl TxQueue { pub fn new() -> Self { Self { vq: None, @@ -142,7 +139,7 @@ impl TxQueue { } } - pub fn add(&mut self, vq: VirtQueue) { + pub fn add(&mut self, vq: VirtQueue) { self.vq = Some(vq); } @@ -206,12 +203,12 @@ impl TxQueue { } } -pub(crate) struct EventQueue { - vq: Option, +pub(crate) struct EventQueue { + vq: Option>, packet_size: u32, } -impl EventQueue { +impl EventQueue { pub fn new() -> Self { Self { vq: None, @@ -222,7 +219,7 @@ impl EventQueue { /// Adds a given queue to the underlying vector and populates the queue with RecvBuffers. /// /// Queues are all populated according to Virtio specification v1.1. - 5.1.6.3.1 - fn add(&mut self, mut vq: VirtQueue) { + fn add(&mut self, mut vq: VirtQueue) { const BUFF_PER_PACKET: u16 = 2; let num_packets = vq.size() / BUFF_PER_PACKET; fill_queue(&mut vq, num_packets, self.packet_size); @@ -255,19 +252,19 @@ pub(crate) struct VsockDevCfg { pub features: virtio::vsock::F, } -pub(crate) struct VirtioVsockDriver { +pub(crate) struct VirtioVsockDriver { pub(super) dev_cfg: VsockDevCfg, - pub(super) com_cfg: ComCfg, - pub(super) isr_stat: IsrStatus, - pub(super) notif_cfg: NotifCfg, + pub(super) com_cfg: T::ComCfg, + pub(super) isr_stat: T::IsrStatus, + pub(super) notif_cfg: T::NotifCfg, pub(super) irq: InterruptLine, - pub(super) event_vq: EventQueue, - pub(super) recv_vq: RxQueue, - pub(super) send_vq: TxQueue, + pub(super) event_vq: EventQueue, + pub(super) recv_vq: RxQueue, + pub(super) send_vq: TxQueue, } -impl Driver for VirtioVsockDriver { +impl Driver for VirtioVsockDriver { fn get_interrupt_number(&self) -> InterruptLine { self.irq } @@ -277,7 +274,7 @@ impl Driver for VirtioVsockDriver { } } -impl VirtioVsockDriver { +impl VirtioVsockDriver { #[cfg(feature = "pci")] pub fn get_dev_id(&self) -> u16 { self.dev_cfg.dev_id @@ -308,14 +305,9 @@ impl VirtioVsockDriver { pub fn handle_interrupt(&mut self) { let status = self.isr_stat.acknowledge(); - #[cfg(not(feature = "pci"))] - if status.contains(virtio::mmio::InterruptStatus::CONFIGURATION_CHANGE_NOTIFICATION) { - info!("Configuration changes are not possible! Aborting"); - todo!("Implement possibility to change config on the fly...") - } - - #[cfg(feature = "pci")] - if status.contains(virtio::pci::IsrStatus::DEVICE_CONFIGURATION_INTERRUPT) { + if status & ::CONFIGURATION_CHANGE + == ::CONFIGURATION_CHANGE + { info!("Configuration changes are not possible! Aborting"); todo!("Implement possibility to change config on the fly...") } diff --git a/src/drivers/vsock/pci.rs b/src/drivers/vsock/pci.rs index 6b3c64c9ed..dedb7ddc7d 100644 --- a/src/drivers/vsock/pci.rs +++ b/src/drivers/vsock/pci.rs @@ -4,10 +4,10 @@ use crate::arch::pci::PciConfigRegion; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; -use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; +use crate::drivers::virtio::transport::pci::{PciCap, Transport, UniCapsColl}; use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; -impl VirtioVsockDriver { +impl VirtioVsockDriver { fn map_cfg(cap: &PciCap) -> Option { let dev_cfg = pci::map_dev_cfg::(cap)?; @@ -58,7 +58,7 @@ impl VirtioVsockDriver { /// Returns a driver instance of VirtioVsockDriver. pub(crate) fn init( device: &PciDevice, - ) -> Result { + ) -> Result, VirtioError> { let mut drv = match pci::map_caps(device) { Ok(caps) => match VirtioVsockDriver::new(caps, device) { Ok(driver) => driver,