diff --git a/Cargo.lock b/Cargo.lock index f878f1a93b..2983facc19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -182,6 +182,17 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +[[package]] +name = "bitfield-struct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2ce686adbebce0ee484a502c440b4657739adbad65eadf06d64f5816ee9765" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.66", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -1522,6 +1533,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "virtio-spec" version = "0.0.0" dependencies = [ + "bitfield-struct", "bitflags 2.5.0", "endian-num", "num_enum", diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 1bad406a68..90e33ace42 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -4,11 +4,10 @@ #![allow(dead_code)] use core::mem; -use core::sync::atomic::{fence, Ordering}; use virtio_spec::mmio::{ DeviceRegisterVolatileFieldAccess, DeviceRegisterVolatileWideFieldAccess, DeviceRegisters, - InterruptStatus, + InterruptStatus, NotificationData, }; use virtio_spec::{le32, DeviceStatus}; use volatile::VolatileRef; @@ -301,26 +300,21 @@ impl NotifCtrl { self.f_notif_data = true; } - pub fn notify_dev(&self, notif_data: &[u8]) { - fence(Ordering::Acquire); + pub fn notify_dev(&self, vqn: u16, next_off: u16, next_wrap: u8) { + let notification_data = NotificationData::new() + .with_vqn(vqn) + .with_next_off(next_off) + .with_next_wrap(next_wrap); - if self.f_notif_data { - let ptr = self.notif_addr as *mut [u8; 4]; - - unsafe { - ptr.write_volatile(notif_data[0..4].try_into().unwrap()); - } + let notification_data = if self.f_notif_data { + notification_data.into_bits() } else { - let mut data: [u8; 4] = [0, 0, 0, 0]; - data[0..2].copy_from_slice(¬if_data[0..2]); - let ptr = self.notif_addr as *mut [u8; 4]; + u32::from(notification_data.vqn()).into() + }; - unsafe { - ptr.write_volatile(data[0..4].try_into().unwrap()); - } + unsafe { + self.notif_addr.write_volatile(notification_data); } - - fence(Ordering::Release); } } diff --git a/src/drivers/virtio/transport/pci.rs b/src/drivers/virtio/transport/pci.rs index f58215994d..54070e9a51 100644 --- a/src/drivers/virtio/transport/pci.rs +++ b/src/drivers/virtio/transport/pci.rs @@ -5,15 +5,14 @@ use alloc::vec::Vec; use core::ptr::NonNull; -use core::sync::atomic::{fence, Ordering}; use core::{mem, ptr}; use pci_types::capability::PciCapability; use virtio_spec::pci::{ CapCfgType, CapData, CommonCfg, CommonCfgVolatileFieldAccess, CommonCfgVolatileWideFieldAccess, - IsrStatus as IsrStatusRaw, + IsrStatus as IsrStatusRaw, NotificationData, }; -use virtio_spec::{le32, DeviceStatus}; +use virtio_spec::{le16, le32, DeviceStatus}; use volatile::VolatileRef; #[cfg(all(not(feature = "rtl8139"), any(feature = "tcp", feature = "udp")))] @@ -589,28 +588,28 @@ impl NotifCtrl { self.f_notif_data = true; } - pub fn notify_dev(&self, notif_data: &[u8]) { + pub fn notify_dev(&self, vqn: u16, next_off: u16, next_wrap: u8) { // 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. - fence(Ordering::Acquire); + let notification_data = NotificationData::new() + .with_vqn(vqn) + .with_next_off(next_off) + .with_next_wrap(next_wrap); if self.f_notif_data { - let ptr = self.notif_addr as *mut [u8; 4]; - unsafe { - ptr.write_volatile(notif_data[0..4].try_into().unwrap()); + self.notif_addr + .write_volatile(notification_data.into_bits()); } } else { - let ptr = self.notif_addr as *mut [u8; 2]; - unsafe { - ptr.write_volatile(notif_data[0..2].try_into().unwrap()); + self.notif_addr + .cast::() + .write_volatile(notification_data.vqn().into()); } } - - fence(Ordering::Release); } } diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index f2e0dd0882..5eedb75a36 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -971,22 +971,8 @@ impl Virtq for PackedVq { } if self.dev_event.is_notif() | self.dev_event.is_notif_specfic(next_off, next_wrap) { - let index = self.index.0.to_le_bytes(); - let mut index = index.iter(); - let det_notif_data: u16 = next_off & !(1 << 15); - let flags = (det_notif_data | (u16::from(next_wrap) << 15)).to_le_bytes(); - let mut flags = flags.iter(); - let mut notif_data: [u8; 4] = [0, 0, 0, 0]; - - for (i, byte) in notif_data.iter_mut().enumerate() { - if i < 2 { - *byte = *index.next().unwrap(); - } else { - *byte = *flags.next().unwrap(); - } - } - - self.notif_ctrl.notify_dev(¬if_data) + self.notif_ctrl + .notify_dev(self.index.0, next_off, next_wrap); } } @@ -1013,22 +999,8 @@ impl Virtq for PackedVq { } if self.dev_event.is_notif() { - let index = self.index.0.to_le_bytes(); - let mut index = index.iter(); - let det_notif_data: u16 = next_off & !(1 << 15); - let flags = (det_notif_data | (u16::from(next_wrap) << 15)).to_le_bytes(); - let mut flags = flags.iter(); - let mut notif_data: [u8; 4] = [0, 0, 0, 0]; - - for (i, byte) in notif_data.iter_mut().enumerate() { - if i < 2 { - *byte = *index.next().unwrap(); - } else { - *byte = *flags.next().unwrap(); - } - } - - self.notif_ctrl.notify_dev(¬if_data) + self.notif_ctrl + .notify_dev(self.index.0, next_off, next_wrap); } } @@ -1042,22 +1014,8 @@ impl Virtq for PackedVq { } if self.dev_event.is_notif() { - let index = self.index.0.to_le_bytes(); - let mut index = index.iter(); - let det_notif_data: u16 = next_off & !(1 << 15); - let flags = (det_notif_data | (u16::from(next_wrap) << 15)).to_le_bytes(); - let mut flags = flags.iter(); - let mut notif_data: [u8; 4] = [0, 0, 0, 0]; - - for (i, byte) in notif_data.iter_mut().enumerate() { - if i < 2 { - *byte = *index.next().unwrap(); - } else { - *byte = *flags.next().unwrap(); - } - } - - self.notif_ctrl.notify_dev(¬if_data) + self.notif_ctrl + .notify_dev(self.index.0, next_off, next_wrap); } } diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index a379b8612d..5cafa70c49 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -378,22 +378,8 @@ impl Virtq for SplitVq { } if self.ring.borrow().dev_is_notif() { - let index = self.index.0.to_le_bytes(); - let mut index = index.iter(); - let det_notif_data: u16 = next_off & !(1 << 15); - let flags = (det_notif_data | (u16::from(next_wrap) << 15)).to_le_bytes(); - let mut flags = flags.iter(); - let mut notif_data: [u8; 4] = [0, 0, 0, 0]; - - for (i, byte) in notif_data.iter_mut().enumerate() { - if i < 2 { - *byte = *index.next().unwrap(); - } else { - *byte = *flags.next().unwrap(); - } - } - - self.notif_ctrl.notify_dev(¬if_data) + self.notif_ctrl + .notify_dev(self.index.0, next_off, next_wrap); } } diff --git a/virtio-spec/Cargo.toml b/virtio-spec/Cargo.toml index 41fafe51c2..15153a821a 100644 --- a/virtio-spec/Cargo.toml +++ b/virtio-spec/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["virtio", "driver", "volatile"] categories = ["no-std", "no-std::no-alloc"] [dependencies] +bitfield-struct = "0.7" bitflags = "2" endian-num = { version = "0.1", features = ["bitflags", "linux-types"] } num_enum = { version = "0.7", default-features = false } diff --git a/virtio-spec/src/mmio.rs b/virtio-spec/src/mmio.rs index bd7b1b4181..6d08347cc2 100644 --- a/virtio-spec/src/mmio.rs +++ b/virtio-spec/src/mmio.rs @@ -6,6 +6,8 @@ use endian_num::{le16, le32}; use volatile::access::{ReadOnly, ReadWrite, RestrictAccess, WriteOnly}; use volatile::VolatilePtr; +#[doc(inline)] +pub use super::pci::NotificationData; use crate::volatile::{OveralignedVolatilePtr, WideVolatilePtr}; use crate::{DeviceStatus, Id}; diff --git a/virtio-spec/src/pci.rs b/virtio-spec/src/pci.rs index c8bc70908d..a2513e869d 100644 --- a/virtio-spec/src/pci.rs +++ b/virtio-spec/src/pci.rs @@ -2,6 +2,7 @@ use core::mem; +use bitfield_struct::bitfield; use endian_num::{le64, Le}; use num_enum::{FromPrimitive, IntoPrimitive}; use pci_types::capability::PciCapabilityAddress; @@ -438,3 +439,34 @@ virtio_bitflags! { const DEVICE_CONFIGURATION_INTERRUPT = 1 << 1; } } + +/// Notification Data. +#[bitfield(u32, repr = le32, from = le32::from_ne, into = le32::to_ne)] +pub struct NotificationData { + /// VQ number to be notified. + pub vqn: u16, + + /// Offset + /// within the ring where the next available ring entry + /// will be written. + /// When [`VIRTIO_F_RING_PACKED`] has not been negotiated this refers to the + /// 15 least significant bits of the available index. + /// When `VIRTIO_F_RING_PACKED` has been negotiated this refers to the offset + /// (in units of descriptor entries) + /// within the descriptor ring where the next available + /// descriptor will be written. + /// + /// [`VIRTIO_F_RING_PACKED`]: F::RING_PACKED + #[bits(15)] + pub next_off: u16, + + /// Wrap Counter. + /// With [`VIRTIO_F_RING_PACKED`] this is the wrap counter + /// referring to the next available descriptor. + /// Without `VIRTIO_F_RING_PACKED` this is the most significant bit + /// (bit 15) of the available index. + /// + /// [`VIRTIO_F_RING_PACKED`]: F::RING_PACKED + #[bits(1)] + pub next_wrap: u8, +}