diff --git a/Cargo.toml b/Cargo.toml index 345ccfb8b1..e443389108 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -71,7 +71,7 @@ shell = ["simple-shell"] [dependencies] hermit-macro = { path = "hermit-macro" } -virtio-spec = { path = "virtio-spec" } +virtio-spec = { path = "virtio-spec", features = ["zerocopy"] } ahash = { version = "0.8", default-features = false } align-address = "0.3" anstyle = { version = "1", default-features = false } diff --git a/src/drivers/fs/virtio_fs.rs b/src/drivers/fs/virtio_fs.rs index ea81db6615..d55f096110 100644 --- a/src/drivers/fs/virtio_fs.rs +++ b/src/drivers/fs/virtio_fs.rs @@ -3,7 +3,6 @@ use alloc::string::{String, ToString}; use alloc::vec::Vec; use pci_types::InterruptLine; -use virtio_spec::features::VirtioFsF; use crate::config::VIRTIO_MAX_QUEUE_SIZE; #[cfg(feature = "pci")] @@ -24,7 +23,7 @@ use crate::fs::fuse::{self, FuseInterface}; pub(crate) struct FsDevCfg { pub raw: &'static FsDevCfgRaw, pub dev_id: u16, - pub features: VirtioFsF, + pub features: virtio_spec::fs::F, } /// Virtio file system driver struct. @@ -55,8 +54,11 @@ impl VirtioFsDriver { /// Negotiates a subset of features, understood and wanted by both the OS /// and the device. - fn negotiate_features(&mut self, driver_features: VirtioFsF) -> Result<(), VirtioFsError> { - let device_features = VirtioFsF::from(self.com_cfg.dev_features()); + fn negotiate_features( + &mut self, + driver_features: virtio_spec::fs::F, + ) -> Result<(), VirtioFsError> { + let device_features = virtio_spec::fs::F::from(self.com_cfg.dev_features()); if device_features.contains(driver_features) { // If device supports subset of features write feature set to common config @@ -85,7 +87,7 @@ impl VirtioFsDriver { // Indicate device, that driver is able to handle it self.com_cfg.set_drv(); - let features = VirtioFsF::VERSION_1; + let features = virtio_spec::fs::F::VERSION_1; self.negotiate_features(features)?; // Indicates the device, that the current feature set is final for the driver @@ -161,8 +163,6 @@ impl FuseInterface for VirtioFsDriver { /// Error module of virtios filesystem driver. pub mod error { - use virtio_spec::features::VirtioFsF; - /// Network filesystem error enum. #[derive(Debug, Copy, Clone)] pub enum VirtioFsError { @@ -177,7 +177,7 @@ pub mod error { FailFeatureNeg(u16), /// The first field contains the feature bits wanted by the driver. /// but which are incompatible with the device feature set, second field. - IncompatibleFeatureSets(VirtioFsF, VirtioFsF), + IncompatibleFeatureSets(virtio_spec::fs::F, virtio_spec::fs::F), Unknown, } } diff --git a/src/drivers/fs/virtio_pci.rs b/src/drivers/fs/virtio_pci.rs index e5a4646d78..7f4af03d7d 100644 --- a/src/drivers/fs/virtio_pci.rs +++ b/src/drivers/fs/virtio_pci.rs @@ -1,7 +1,5 @@ use alloc::vec::Vec; -use virtio_spec::features::VirtioFsF; - use crate::arch::pci::PciConfigRegion; use crate::drivers::fs::virtio_fs::{FsDevCfg, VirtioFsDriver}; use crate::drivers::pci::PciDevice; @@ -57,7 +55,7 @@ impl VirtioFsDriver { Some(FsDevCfg { raw: dev_cfg, dev_id: cap.dev_id(), - features: VirtioFsF::empty(), + features: virtio_spec::fs::F::empty(), }) } diff --git a/src/drivers/net/virtio_mmio.rs b/src/drivers/net/virtio_mmio.rs index d78fad4cad..f99e33a7dd 100644 --- a/src/drivers/net/virtio_mmio.rs +++ b/src/drivers/net/virtio_mmio.rs @@ -10,7 +10,6 @@ use core::str::FromStr; use core::sync::atomic::{fence, Ordering}; use smoltcp::phy::ChecksumCapabilities; -use virtio_spec::features::VirtioNetF; use crate::drivers::net::virtio_net::constants::Status; use crate::drivers::net::virtio_net::{CtrlQueue, NetDevCfg, RxQueues, TxQueues, VirtioNetDriver}; @@ -119,7 +118,7 @@ impl VirtioNetDriver { let dev_cfg = NetDevCfg { raw: dev_cfg_raw, dev_id, - features: VirtioNetF::empty(), + features: virtio_spec::net::F::empty(), }; let isr_stat = IsrStatus::new(registers); let notif_cfg = NotifCfg::new(registers); diff --git a/src/drivers/net/virtio_net.rs b/src/drivers/net/virtio_net.rs index 2e91390e7e..53f94d7583 100644 --- a/src/drivers/net/virtio_net.rs +++ b/src/drivers/net/virtio_net.rs @@ -12,10 +12,9 @@ use align_address::Align; use pci_types::InterruptLine; use smoltcp::phy::{Checksum, ChecksumCapabilities}; use smoltcp::wire::{EthernetFrame, Ipv4Packet, Ipv6Packet, ETHERNET_HEADER_LEN}; -use virtio_spec::features::VirtioNetF; -use zerocopy::AsBytes; +use virtio_spec::net::{Hdr, HdrF}; -use self::constants::{NetHdrFlag, NetHdrGSO, Status, MAX_NUM_VQ}; +use self::constants::{Status, MAX_NUM_VQ}; use self::error::VirtioNetError; #[cfg(not(target_arch = "riscv64"))] use crate::arch::kernel::core_local::increment_irq_counter; @@ -40,38 +39,7 @@ use crate::executor::device::{RxToken, TxToken}; pub(crate) struct NetDevCfg { pub raw: &'static NetDevCfgRaw, pub dev_id: u16, - pub features: VirtioNetF, -} - -#[derive(AsBytes, Debug)] -#[repr(C)] -pub struct VirtioNetHdr { - flags: NetHdrFlag, - gso_type: NetHdrGSO, - /// Ethernet + IP + tcp/udp hdrs - hdr_len: u16, - /// Bytes to append to hdr_len per frame - gso_size: u16, - /// Position to start checksumming from - csum_start: u16, - /// Offset after that to place checksum - csum_offset: u16, - /// Number of buffers this Packet consists of - num_buffers: u16, -} - -impl Default for VirtioNetHdr { - fn default() -> Self { - Self { - flags: NetHdrFlag::VIRTIO_NET_HDR_F_NONE, - gso_type: NetHdrGSO::VIRTIO_NET_HDR_GSO_NONE, - hdr_len: 0, - gso_size: 0, - csum_start: 0, - csum_offset: 0, - num_buffers: 0, - } - } + pub features: virtio_spec::net::F, } pub struct CtrlQueue(Option>); @@ -181,11 +149,11 @@ impl RxQueues { fn add(&mut self, vq: Rc, dev_cfg: &NetDevCfg) { let num_buff: u16 = vq.size().into(); - let rx_size = if dev_cfg.features.contains(VirtioNetF::MRG_RXBUF) { - (1514 + mem::size_of::()) + let rx_size = if dev_cfg.features.contains(virtio_spec::net::F::MRG_RXBUF) { + (1514 + mem::size_of::()) .align_up(core::mem::size_of::>()) } else { - dev_cfg.raw.get_mtu() as usize + mem::size_of::() + dev_cfg.raw.get_mtu() as usize + mem::size_of::() }; // See Virtio specification v1.1 - 5.1.6.3.1 @@ -322,15 +290,15 @@ impl TxQueues { // Unwrapping is safe, as one virtq will be definitely in the vector. let vq = self.vqs.first().unwrap(); - if dev_cfg.features.contains(VirtioNetF::GUEST_TSO4) - | dev_cfg.features.contains(VirtioNetF::GUEST_TSO6) - | dev_cfg.features.contains(VirtioNetF::GUEST_UFO) + if dev_cfg.features.contains(virtio_spec::net::F::GUEST_TSO4) + | dev_cfg.features.contains(virtio_spec::net::F::GUEST_TSO6) + | dev_cfg.features.contains(virtio_spec::net::F::GUEST_UFO) { // Virtio specification v1.1. - 5.1.6.2 point 5. // Header and data are added as ONE output descriptor to the transmitvq. // Hence we are interpreting this, as the fact, that send packets must be inside a single descriptor. // As usize is currently safe as the minimal usize is defined as 16bit in rust. - let buff_def = Bytes::new(mem::size_of::() + 65550).unwrap(); + let buff_def = Bytes::new(mem::size_of::() + 65550).unwrap(); let spec = BuffSpec::Single(buff_def); let num_buff: u16 = vq.size().into(); @@ -340,7 +308,7 @@ impl TxQueues { vq.clone() .prep_buffer(Some(spec.clone()), None) .unwrap() - .write_seq(Some(&VirtioNetHdr::default()), None::<&VirtioNetHdr>) + .write_seq(Some(&Hdr::default()), None::<&Hdr>) .unwrap(), ) } @@ -350,8 +318,7 @@ impl TxQueues { // Hence we are interpreting this, as the fact, that send packets must be inside a single descriptor. // As usize is currently safe as the minimal usize is defined as 16bit in rust. let buff_def = - Bytes::new(mem::size_of::() + dev_cfg.raw.get_mtu() as usize) - .unwrap(); + Bytes::new(mem::size_of::() + dev_cfg.raw.get_mtu() as usize).unwrap(); let spec = BuffSpec::Single(buff_def); let num_buff: u16 = vq.size().into(); @@ -361,7 +328,7 @@ impl TxQueues { vq.clone() .prep_buffer(Some(spec.clone()), None) .unwrap() - .write_seq(Some(&VirtioNetHdr::default()), None::<&VirtioNetHdr>) + .write_seq(Some(&Hdr::default()), None::<&Hdr>) .unwrap(), ) } @@ -452,7 +419,7 @@ 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] { - if self.dev_cfg.features.contains(VirtioNetF::MAC) { + if self.dev_cfg.features.contains(virtio_spec::net::F::MAC) { self.dev_cfg.raw.get_mac() } else { unreachable!("Currently VIRTIO_NET_F_MAC must be negotiated!") @@ -480,21 +447,19 @@ impl NetworkDriver for VirtioNetDriver { where F: FnOnce(&mut [u8]) -> R, { - if let Some((mut buff_tkn, _vq_index)) = self - .send_vqs - .get_tkn(len + core::mem::size_of::()) + if let Some((mut buff_tkn, _vq_index)) = + self.send_vqs.get_tkn(len + core::mem::size_of::()) { let (send_ptrs, _) = buff_tkn.raw_ptrs(); // Currently we have single Buffers in the TxQueue of size: MTU + ETHERNET_HEADER_LEN + VIRTIO_NET_HDR // see TxQueue.add() let (buff_ptr, _) = send_ptrs.unwrap()[0]; - // Do not show smoltcp the memory region for VirtioNetHdr. - let header = unsafe { &mut *(buff_ptr as *mut VirtioNetHdr) }; + // Do not show smoltcp the memory region for Hdr. + let header = unsafe { &mut *(buff_ptr as *mut Hdr) }; *header = Default::default(); - let buff_ptr = unsafe { - buff_ptr.offset(isize::try_from(core::mem::size_of::()).unwrap()) - }; + let buff_ptr = + unsafe { buff_ptr.offset(isize::try_from(core::mem::size_of::()).unwrap()) }; let buf_slice: &'static mut [u8] = unsafe { core::slice::from_raw_parts_mut(buff_ptr, len) }; @@ -503,7 +468,7 @@ impl NetworkDriver for VirtioNetDriver { // If a checksum isn't necessary, we have inform the host within the header // see Virtio specification 5.1.6.2 if !self.checksums.tcp.tx() || !self.checksums.udp.tx() { - header.flags = NetHdrFlag::VIRTIO_NET_HDR_F_NEEDS_CSUM; + header.flags = HdrF::NEEDS_CSUM; let ethernet_frame: smoltcp::wire::EthernetFrame<&[u8]> = EthernetFrame::new_unchecked(buf_slice); let packet_header_len: u16; @@ -524,12 +489,14 @@ impl NetworkDriver for VirtioNetDriver { protocol = None; } } - header.csum_start = u16::try_from(ETHERNET_HEADER_LEN).unwrap() + packet_header_len; + header.csum_start = + (u16::try_from(ETHERNET_HEADER_LEN).unwrap() + packet_header_len).into(); header.csum_offset = match protocol { Some(smoltcp::wire::IpProtocol::Tcp) => 16, Some(smoltcp::wire::IpProtocol::Udp) => 6, _ => 0, - }; + } + .into(); } buff_tkn @@ -560,7 +527,7 @@ impl NetworkDriver for VirtioNetDriver { if recv_data.len() == 1 { let mut vec_data: Vec = Vec::with_capacity(self.mtu.into()); let num_buffers = { - const HEADER_SIZE: usize = mem::size_of::(); + const HEADER_SIZE: usize = mem::size_of::(); let packet = recv_data.pop().unwrap(); // drop packets with invalid packet size @@ -574,14 +541,14 @@ impl NetworkDriver for VirtioNetDriver { } let header = unsafe { - core::mem::transmute::<[u8; HEADER_SIZE], VirtioNetHdr>( + core::mem::transmute::<[u8; HEADER_SIZE], Hdr>( packet[..HEADER_SIZE].try_into().unwrap(), ) }; trace!("Header: {:?}", header); let num_buffers = header.num_buffers; - vec_data.extend_from_slice(&packet[mem::size_of::()..]); + vec_data.extend_from_slice(&packet[mem::size_of::()..]); transfer .reset() .provide() @@ -590,7 +557,7 @@ impl NetworkDriver for VirtioNetDriver { num_buffers }; - for _ in 1..num_buffers { + for _ in 1..num_buffers.get() { let transfer = match RxQueues::post_processing(self.recv_vqs.get_next().unwrap()) { Ok(trf) => trf, @@ -615,7 +582,7 @@ impl NetworkDriver for VirtioNetDriver { error!("Empty transfer, or with wrong buffer layout. Reusing and returning error to user-space network driver..."); transfer .reset() - .write_seq(None::<&VirtioNetHdr>, Some(&VirtioNetHdr::default())) + .write_seq(None::<&Hdr>, Some(&Hdr::default())) .unwrap() .provide() .dispatch_await(self.recv_vqs.poll_sender.clone(), false); @@ -670,7 +637,7 @@ impl VirtioNetDriver { /// has been negotiated. Otherwise assumes an active device. #[cfg(not(feature = "pci"))] pub fn dev_status(&self) -> u16 { - if self.dev_cfg.features.contains(VirtioNetF::STATUS) { + if self.dev_cfg.features.contains(virtio_spec::net::F::STATUS) { self.dev_cfg.raw.get_status() } else { u16::from(Status::VIRTIO_NET_S_LINK_UP) @@ -681,7 +648,7 @@ impl VirtioNetDriver { /// If feature VIRTIO_NET_F_STATUS has not been negotiated, then we assume the link is up! #[cfg(feature = "pci")] pub fn is_link_up(&self) -> bool { - if self.dev_cfg.features.contains(VirtioNetF::STATUS) { + if self.dev_cfg.features.contains(virtio_spec::net::F::STATUS) { self.dev_cfg.raw.get_status() & u16::from(Status::VIRTIO_NET_S_LINK_UP) == u16::from(Status::VIRTIO_NET_S_LINK_UP) } else { @@ -691,7 +658,7 @@ impl VirtioNetDriver { #[allow(dead_code)] pub fn is_announce(&self) -> bool { - if self.dev_cfg.features.contains(VirtioNetF::STATUS) { + if self.dev_cfg.features.contains(virtio_spec::net::F::STATUS) { self.dev_cfg.raw.get_status() & u16::from(Status::VIRTIO_NET_S_ANNOUNCE) == u16::from(Status::VIRTIO_NET_S_ANNOUNCE) } else { @@ -706,7 +673,7 @@ impl VirtioNetDriver { /// Returns 1 (i.e. minimum number of pairs) if VIRTIO_NET_F_MQ is not set. #[allow(dead_code)] pub fn get_max_vq_pairs(&self) -> u16 { - if self.dev_cfg.features.contains(VirtioNetF::MQ) { + if self.dev_cfg.features.contains(virtio_spec::net::F::MQ) { self.dev_cfg.raw.get_max_virtqueue_pairs() } else { 1 @@ -740,31 +707,31 @@ impl VirtioNetDriver { // Indicate device, that driver is able to handle it self.com_cfg.set_drv(); - let minimal_features = VirtioNetF::VERSION_1 | VirtioNetF::MAC; + let minimal_features = virtio_spec::net::F::VERSION_1 | virtio_spec::net::F::MAC; // If wanted, push new features into feats here: let mut features = minimal_features // Indirect descriptors can be used - | VirtioNetF::INDIRECT_DESC + | virtio_spec::net::F::INDIRECT_DESC // Packed Vq can be used - | VirtioNetF::RING_PACKED + | virtio_spec::net::F::RING_PACKED // Host should avoid the creation of checksums - | VirtioNetF::CSUM + | virtio_spec::net::F::CSUM // Guest avoids the creation of checksums - | VirtioNetF::GUEST_CSUM + | virtio_spec::net::F::GUEST_CSUM // MTU setting can be used - | VirtioNetF::MTU + | virtio_spec::net::F::MTU // Driver can merge receive buffers - | VirtioNetF::MRG_RXBUF + | virtio_spec::net::F::MRG_RXBUF // the link status can be announced - | VirtioNetF::STATUS; + | virtio_spec::net::F::STATUS; // Currently the driver does NOT support the features below. // In order to provide functionality for these, the driver // needs to take care of calculating checksum in // RxQueues.post_processing() - // | VirtioNetF::GUEST_TSO4 - // | VirtioNetF::GUEST_TSO6 + // | virtio_spec::net::F::GUEST_TSO4 + // | virtio_spec::net::F::GUEST_TSO6 // Negotiate features with device. Automatically reduces selected feats in order to meet device capabilities. // Aborts in case incompatible features are selected by the driver or the device does not support min_feat_set. @@ -845,21 +812,28 @@ impl VirtioNetDriver { // At this point the device is "live" self.com_cfg.drv_ok(); - if self.dev_cfg.features.contains(VirtioNetF::CSUM) - && self.dev_cfg.features.contains(VirtioNetF::GUEST_CSUM) + if self.dev_cfg.features.contains(virtio_spec::net::F::CSUM) + && self + .dev_cfg + .features + .contains(virtio_spec::net::F::GUEST_CSUM) { self.checksums.udp = Checksum::None; self.checksums.tcp = Checksum::None; - } else if self.dev_cfg.features.contains(VirtioNetF::CSUM) { + } else if self.dev_cfg.features.contains(virtio_spec::net::F::CSUM) { self.checksums.udp = Checksum::Rx; self.checksums.tcp = Checksum::Rx; - } else if self.dev_cfg.features.contains(VirtioNetF::GUEST_CSUM) { + } else if self + .dev_cfg + .features + .contains(virtio_spec::net::F::GUEST_CSUM) + { self.checksums.udp = Checksum::Tx; self.checksums.tcp = Checksum::Tx; } debug!("{:?}", self.checksums); - if self.dev_cfg.features.contains(VirtioNetF::MTU) { + if self.dev_cfg.features.contains(virtio_spec::net::F::MTU) { self.mtu = self.dev_cfg.raw.get_mtu(); } @@ -868,8 +842,11 @@ impl VirtioNetDriver { /// Negotiates a subset of features, understood and wanted by both the OS /// and the device. - fn negotiate_features(&mut self, driver_features: VirtioNetF) -> Result<(), VirtioNetError> { - let device_features = VirtioNetF::from(self.com_cfg.dev_features()); + fn negotiate_features( + &mut self, + driver_features: virtio_spec::net::F, + ) -> Result<(), VirtioNetError> { + let device_features = virtio_spec::net::F::from(self.com_cfg.dev_features()); // Checks if the selected feature set is compatible with requirements for // features according to Virtio spec. v1.1 - 5.1.3.1. @@ -900,8 +877,12 @@ impl VirtioNetDriver { } // Add a control if feature is negotiated - if self.dev_cfg.features.contains(VirtioNetF::CTRL_VQ) { - if self.dev_cfg.features.contains(VirtioNetF::RING_PACKED) { + if self.dev_cfg.features.contains(virtio_spec::net::F::CTRL_VQ) { + if self + .dev_cfg + .features + .contains(virtio_spec::net::F::RING_PACKED) + { self.ctrl_vq = CtrlQueue(Some(Rc::new( PackedVq::new( &mut self.com_cfg, @@ -941,7 +922,7 @@ impl VirtioNetDriver { // - the plus 1 is due to the possibility of an existing control queue // - the num_queues is found in the ComCfg struct of the device and defines the maximal number // of supported queues. - if self.dev_cfg.features.contains(VirtioNetF::MQ) { + if self.dev_cfg.features.contains(virtio_spec::net::F::MQ) { if self.dev_cfg.raw.get_max_virtqueue_pairs() * 2 >= MAX_NUM_VQ { self.num_vqs = MAX_NUM_VQ; } else { @@ -964,7 +945,11 @@ impl VirtioNetDriver { assert_eq!(self.num_vqs % 2, 0); for i in 0..(self.num_vqs / 2) { - if self.dev_cfg.features.contains(VirtioNetF::RING_PACKED) { + if self + .dev_cfg + .features + .contains(virtio_spec::net::F::RING_PACKED) + { let vq = PackedVq::new( &mut self.com_cfg, &self.notif_cfg, @@ -1024,70 +1009,9 @@ impl VirtioNetDriver { } pub mod constants { - use zerocopy::AsBytes; - // Configuration constants pub const MAX_NUM_VQ: u16 = 2; - /// Enum containing Virtios netword header flags - /// - /// See Virtio specification v1.1. - 5.1.6 - #[allow(dead_code, non_camel_case_types)] - #[derive(AsBytes, Copy, Clone, Debug)] - #[repr(u8)] - pub enum NetHdrFlag { - /// No further information - VIRTIO_NET_HDR_F_NONE = 0, - /// use csum_start, csum_offset - VIRTIO_NET_HDR_F_NEEDS_CSUM = 1, - /// csum is valid - VIRTIO_NET_HDR_F_DATA_VALID = 2, - /// reports number of coalesced TCP segments - VIRTIO_NET_HDR_F_RSC_INFO = 4, - } - - impl From for u8 { - fn from(val: NetHdrFlag) -> Self { - match val { - NetHdrFlag::VIRTIO_NET_HDR_F_NONE => 0, - NetHdrFlag::VIRTIO_NET_HDR_F_NEEDS_CSUM => 1, - NetHdrFlag::VIRTIO_NET_HDR_F_DATA_VALID => 2, - NetHdrFlag::VIRTIO_NET_HDR_F_RSC_INFO => 4, - } - } - } - - /// Enum containing Virtios netword GSO types - /// - /// See Virtio specification v1.1. - 5.1.6 - #[allow(dead_code, non_camel_case_types)] - #[derive(AsBytes, Copy, Clone, Debug)] - #[repr(u8)] - pub enum NetHdrGSO { - /// not a GSO frame - VIRTIO_NET_HDR_GSO_NONE = 0, - /// GSO frame, IPv4 TCP (TSO) - VIRTIO_NET_HDR_GSO_TCPV4 = 1, - /// GSO frame, IPv4 UDP (UFO) - VIRTIO_NET_HDR_GSO_UDP = 3, - /// GSO frame, IPv6 TCP - VIRTIO_NET_HDR_GSO_TCPV6 = 4, - /// TCP has ECN set - VIRTIO_NET_HDR_GSO_ECN = 0x80, - } - - impl From for u8 { - fn from(val: NetHdrGSO) -> Self { - match val { - NetHdrGSO::VIRTIO_NET_HDR_GSO_NONE => 0, - NetHdrGSO::VIRTIO_NET_HDR_GSO_TCPV4 => 1, - NetHdrGSO::VIRTIO_NET_HDR_GSO_UDP => 3, - NetHdrGSO::VIRTIO_NET_HDR_GSO_TCPV6 => 4, - NetHdrGSO::VIRTIO_NET_HDR_GSO_ECN => 0x80, - } - } - } - /// Enum contains virtio's network device status /// indiacted in the status field of the device's /// configuration structure. @@ -1116,39 +1040,43 @@ pub mod constants { /// Upon an error returns the incompatible set of features by the /// [`VirtioNetError::FeatureRequirementsNotMet`] error value, which /// wraps the u64 indicating the feature set. -pub fn check_features(features: VirtioNetF) -> Result<(), VirtioNetError> { +pub fn check_features(features: virtio_spec::net::F) -> Result<(), VirtioNetError> { for feature in features.iter() { match feature { - VirtioNetF::GUEST_TSO4 | VirtioNetF::GUEST_TSO6 | VirtioNetF::GUEST_UFO => { - if !features.contains(VirtioNetF::GUEST_CSUM) { + virtio_spec::net::F::GUEST_TSO4 + | virtio_spec::net::F::GUEST_TSO6 + | virtio_spec::net::F::GUEST_UFO => { + if !features.contains(virtio_spec::net::F::GUEST_CSUM) { return Err(VirtioNetError::FeatureRequirementsNotMet(features)); } } - VirtioNetF::GUEST_ECN => { - if !(features.contains(VirtioNetF::GUEST_TSO4) - || features.contains(VirtioNetF::GUEST_TSO6)) + virtio_spec::net::F::GUEST_ECN => { + if !(features.contains(virtio_spec::net::F::GUEST_TSO4) + || features.contains(virtio_spec::net::F::GUEST_TSO6)) { return Err(VirtioNetError::FeatureRequirementsNotMet(features)); } } - VirtioNetF::HOST_TSO4 | VirtioNetF::HOST_TSO6 | VirtioNetF::HOST_UFO => { - if !features.contains(VirtioNetF::CSUM) { + virtio_spec::net::F::HOST_TSO4 + | virtio_spec::net::F::HOST_TSO6 + | virtio_spec::net::F::HOST_UFO => { + if !features.contains(virtio_spec::net::F::CSUM) { return Err(VirtioNetError::FeatureRequirementsNotMet(features)); } } - VirtioNetF::HOST_ECN | VirtioNetF::RSC_EXT => { - if !(features.contains(VirtioNetF::HOST_TSO4) - || features.contains(VirtioNetF::HOST_TSO6)) + virtio_spec::net::F::HOST_ECN | virtio_spec::net::F::RSC_EXT => { + if !(features.contains(virtio_spec::net::F::HOST_TSO4) + || features.contains(virtio_spec::net::F::HOST_TSO6)) { return Err(VirtioNetError::FeatureRequirementsNotMet(features)); } } - VirtioNetF::CTRL_RX - | VirtioNetF::CTRL_VLAN - | VirtioNetF::GUEST_ANNOUNCE - | VirtioNetF::MQ - | VirtioNetF::CTRL_MAC_ADDR => { - if !features.contains(VirtioNetF::CTRL_VQ) { + virtio_spec::net::F::CTRL_RX + | virtio_spec::net::F::CTRL_VLAN + | virtio_spec::net::F::GUEST_ANNOUNCE + | virtio_spec::net::F::MQ + | virtio_spec::net::F::CTRL_MAC_ADDR => { + if !features.contains(virtio_spec::net::F::CTRL_VQ) { return Err(VirtioNetError::FeatureRequirementsNotMet(features)); } } @@ -1162,8 +1090,6 @@ pub fn check_features(features: VirtioNetF) -> Result<(), VirtioNetError> { /// Error module of virtios network driver. Containing the (VirtioNetError)[VirtioNetError] /// enum. pub mod error { - use virtio_spec::features::VirtioNetF; - /// Network drivers error enum. #[derive(Debug, Copy, Clone)] pub enum VirtioNetError { @@ -1178,9 +1104,9 @@ pub mod error { FailFeatureNeg(u16), /// Set of features does not adhere to the requirements of features /// indicated by the specification - FeatureRequirementsNotMet(VirtioNetF), + FeatureRequirementsNotMet(virtio_spec::net::F), /// The first field contains the feature bits wanted by the driver. /// but which are incompatible with the device feature set, second field. - IncompatibleFeatureSets(VirtioNetF, VirtioNetF), + IncompatibleFeatureSets(virtio_spec::net::F, virtio_spec::net::F), } } diff --git a/src/drivers/net/virtio_pci.rs b/src/drivers/net/virtio_pci.rs index ce7b8ea41f..a8eb73462d 100644 --- a/src/drivers/net/virtio_pci.rs +++ b/src/drivers/net/virtio_pci.rs @@ -6,7 +6,6 @@ use alloc::vec::Vec; use core::str::FromStr; use smoltcp::phy::ChecksumCapabilities; -use virtio_spec::features::VirtioNetF; use crate::arch::pci::PciConfigRegion; use crate::drivers::net::virtio_net::{CtrlQueue, NetDevCfg, RxQueues, TxQueues, VirtioNetDriver}; @@ -80,7 +79,7 @@ impl VirtioNetDriver { Some(NetDevCfg { raw: dev_cfg, dev_id: cap.dev_id(), - features: VirtioNetF::empty(), + features: virtio_spec::net::F::empty(), }) } diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 7149c98fbb..6bcd4b6ebf 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -7,7 +7,6 @@ use core::ptr; use core::ptr::{read_volatile, write_volatile}; use core::sync::atomic::{fence, Ordering}; -use virtio_spec::features::VirtioF; use virtio_spec::DeviceStatus; #[cfg(any(feature = "tcp", feature = "udp"))] @@ -234,12 +233,12 @@ impl ComCfg { } /// Returns the features offered by the device. - pub fn dev_features(&mut self) -> VirtioF { + pub fn dev_features(&mut self) -> virtio_spec::F { self.com_cfg.dev_features() } /// Write selected features into driver_select field. - pub fn set_drv_features(&mut self, features: VirtioF) { + pub fn set_drv_features(&mut self, features: virtio_spec::F) { self.com_cfg.set_drv_features(features); } @@ -540,7 +539,7 @@ impl MmioRegisterLayout { } } - pub fn dev_features(&mut self) -> VirtioF { + pub fn dev_features(&mut self) -> virtio_spec::F { // Indicate device to show high 32 bits in device_feature field. // See Virtio specification v1.1. - 4.1.4.3 unsafe { @@ -556,12 +555,12 @@ impl MmioRegisterLayout { // read low 32 bits of device features device_features |= u64::from(read_volatile(&self.device_features)); - VirtioF::from_bits_retain(device_features.into()) + virtio_spec::F::from_bits_retain(device_features.into()) } } /// Write selected features into driver_select field. - pub fn set_drv_features(&mut self, features: VirtioF) { + pub fn set_drv_features(&mut self, features: virtio_spec::F) { let features = features.bits() as u64; let high: u32 = (features >> 32) as u32; let low: u32 = features as u32; diff --git a/src/drivers/virtio/transport/pci.rs b/src/drivers/virtio/transport/pci.rs index 48bfed040c..e814ea8f2b 100644 --- a/src/drivers/virtio/transport/pci.rs +++ b/src/drivers/virtio/transport/pci.rs @@ -8,8 +8,7 @@ use core::ptr::NonNull; use core::sync::atomic::{fence, Ordering}; use core::{mem, ptr}; -use virtio_spec::features::VirtioF; -use virtio_spec::pci::{CommonCfg, CommonCfgVolatileFieldAccess}; +use virtio_spec::pci::{CommonCfg, CommonCfgVolatileFieldAccess, CommonCfgVolatileWideFieldAccess}; use virtio_spec::DeviceStatus; use volatile::VolatileRef; @@ -597,7 +596,7 @@ impl ComCfg { } /// Returns the features offered by the device. - pub fn dev_features(&mut self) -> VirtioF { + pub fn dev_features(&mut self) -> virtio_spec::F { let com_cfg = self.com_cfg.as_mut_ptr(); let device_feature_select = com_cfg.device_feature_select(); let device_feature = com_cfg.device_feature(); @@ -619,11 +618,11 @@ impl ComCfg { // read low 32 bits of device features device_features |= u64::from(device_feature.read().get()); - VirtioF::from_bits_retain(device_features.into()) + virtio_spec::F::from_bits_retain(device_features.into()) } /// Write selected features into driver_select field. - pub fn set_drv_features(&mut self, features: VirtioF) { + pub fn set_drv_features(&mut self, features: virtio_spec::F) { let features = features.bits() as u64; let com_cfg = self.com_cfg.as_mut_ptr(); let driver_feature_select = com_cfg.driver_feature_select(); diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index 2ecd8ec7ff..70fd3f2a2a 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -22,7 +22,6 @@ use core::ptr; use align_address::Align; use async_channel::TryRecvError; -use virtio_spec::features::VirtioF; use zerocopy::AsBytes; use self::error::{BufferError, VirtqError}; @@ -172,7 +171,7 @@ pub trait Virtq: VirtqPrivate { notif_cfg: &NotifCfg, size: VqSize, index: VqIndex, - features: VirtioF, + features: virtio_spec::F, ) -> Result where Self: Sized; @@ -2984,8 +2983,6 @@ impl From for u16 { /// This module unifies errors provided to useres of a virtqueue, independent of the underlying /// virtqueue implementation, realized via the different enum variants. pub mod error { - use virtio_spec::features::VirtioF; - use crate::fd; #[derive(Debug)] @@ -3038,7 +3035,7 @@ pub mod error { /// referring to). BufferToLarge, QueueSizeNotAllowed(u16), - FeatureNotSupported(VirtioF), + FeatureNotSupported(virtio_spec::F), AllocationError, } diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index 7847b306ad..ae52c879f3 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -10,7 +10,6 @@ use core::ptr; use core::sync::atomic::{fence, Ordering}; use align_address::Align; -use virtio_spec::features::VirtioF; use zerocopy::little_endian; #[cfg(not(feature = "pci"))] @@ -1072,7 +1071,7 @@ impl Virtq for PackedVq { notif_cfg: &NotifCfg, size: VqSize, index: VqIndex, - features: VirtioF, + features: virtio_spec::F, ) -> Result { // Currently we do not have support for in order use. // This steems from the fact, that the packedVq ReadCtrl currently is not @@ -1081,9 +1080,9 @@ impl Virtq for PackedVq { // TransferTokens are inserted into the queue. Furthermore the Queue should // carry a feature u64 in order to check which features are used currently // and adjust its ReadCtrl accordingly. - if features.contains(VirtioF::IN_ORDER) { + if features.contains(virtio_spec::F::IN_ORDER) { info!("PackedVq has no support for VIRTIO_F_IN_ORDER. Aborting..."); - return Err(VirtqError::FeatureNotSupported(VirtioF::IN_ORDER)); + return Err(VirtqError::FeatureNotSupported(virtio_spec::F::IN_ORDER)); } // Get a handler to the queues configuration area. @@ -1139,11 +1138,11 @@ impl Virtq for PackedVq { + usize::try_from(notif_cfg.multiplier()).unwrap(), )); - if features.contains(VirtioF::NOTIFICATION_DATA) { + if features.contains(virtio_spec::F::NOTIFICATION_DATA) { notif_ctrl.enable_notif_data(); } - if features.contains(VirtioF::EVENT_IDX) { + if features.contains(virtio_spec::F::EVENT_IDX) { drv_event.borrow_mut().f_notif_idx = true; } diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index 8d4174ddcd..9709755027 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -10,7 +10,6 @@ use core::cell::{RefCell, UnsafeCell}; use core::mem::{size_of, MaybeUninit}; use core::ptr::{self, NonNull}; -use virtio_spec::features::VirtioF; use virtio_spec::num::{le16, le32, le64}; use volatile::access::ReadOnly; use volatile::{map_field, VolatilePtr, VolatileRef}; @@ -406,7 +405,7 @@ impl Virtq for SplitVq { notif_cfg: &NotifCfg, size: VqSize, index: VqIndex, - _features: VirtioF, + _features: virtio_spec::F, ) -> Result { // Get a handler to the queues configuration area. let mut vq_handler = match com_cfg.select_vq(index.into()) { diff --git a/virtio-spec/src/features.rs b/virtio-spec/src/features.rs index 499cf5002e..435c01a008 100644 --- a/virtio-spec/src/features.rs +++ b/virtio-spec/src/features.rs @@ -3,7 +3,7 @@ virtio_bitflags! { /// Device-independent Feature Bits #[doc(alias = "VIRTIO_F")] - pub struct VirtioF: u128 { + pub struct F: u128 { /// Negotiating this feature indicates /// that the driver can use descriptors with the VIRTQ_DESC_F_INDIRECT /// flag set, as described in _Basic Facilities of a Virtio @@ -142,77 +142,77 @@ macro_rules! feature_bits { const $Flag = $value; )* - /// Device-independent Bit. See [`VirtioF::INDIRECT_DESC`]. - const INDIRECT_DESC = VirtioF::INDIRECT_DESC.bits(); + /// Device-independent Bit. See [`virtio_spec::F::INDIRECT_DESC`](crate::F::INDIRECT_DESC). + const INDIRECT_DESC = $crate::F::INDIRECT_DESC.bits(); - /// Device-independent Bit. See [`VirtioF::EVENT_IDX`]. - const EVENT_IDX = VirtioF::EVENT_IDX.bits(); + /// Device-independent Bit. See [`virtio_spec::F::EVENT_IDX`](crate::F::EVENT_IDX). + const EVENT_IDX = $crate::F::EVENT_IDX.bits(); - /// Device-independent Bit. See [`VirtioF::VERSION_1`]. - const VERSION_1 = VirtioF::VERSION_1.bits(); + /// Device-independent Bit. See [`virtio_spec::F::VERSION_1`](crate::F::VERSION_1). + const VERSION_1 = $crate::F::VERSION_1.bits(); - /// Device-independent Bit. See [`VirtioF::ACCESS_PLATFORM`]. - const ACCESS_PLATFORM = VirtioF::ACCESS_PLATFORM.bits(); + /// Device-independent Bit. See [`virtio_spec::F::ACCESS_PLATFORM`](crate::F::ACCESS_PLATFORM). + const ACCESS_PLATFORM = $crate::F::ACCESS_PLATFORM.bits(); - /// Device-independent Bit. See [`VirtioF::RING_PACKED`]. - const RING_PACKED = VirtioF::RING_PACKED.bits(); + /// Device-independent Bit. See [`virtio_spec::F::RING_PACKED`](crate::F::RING_PACKED). + const RING_PACKED = $crate::F::RING_PACKED.bits(); - /// Device-independent Bit. See [`VirtioF::IN_ORDER`]. - const IN_ORDER = VirtioF::IN_ORDER.bits(); + /// Device-independent Bit. See [`virtio_spec::F::IN_ORDER`](crate::F::IN_ORDER). + const IN_ORDER = $crate::F::IN_ORDER.bits(); - /// Device-independent Bit. See [`VirtioF::ORDER_PLATFORM`]. - const ORDER_PLATFORM = VirtioF::ORDER_PLATFORM.bits(); + /// Device-independent Bit. See [`virtio_spec::F::ORDER_PLATFORM`](crate::F::ORDER_PLATFORM). + const ORDER_PLATFORM = $crate::F::ORDER_PLATFORM.bits(); - /// Device-independent Bit. See [`VirtioF::SR_IOV`]. - const SR_IOV = VirtioF::SR_IOV.bits(); + /// Device-independent Bit. See [`virtio_spec::F::SR_IOV`](crate::F::SR_IOV). + const SR_IOV = $crate::F::SR_IOV.bits(); - /// Device-independent Bit. See [`VirtioF::NOTIFICATION_DATA`]. - const NOTIFICATION_DATA = VirtioF::NOTIFICATION_DATA.bits(); + /// Device-independent Bit. See [`virtio_spec::F::NOTIFICATION_DATA`](crate::F::NOTIFICATION_DATA). + const NOTIFICATION_DATA = $crate::F::NOTIFICATION_DATA.bits(); - /// Device-independent Bit. See [`VirtioF::NOTIF_CONFIG_DATA`]. - const NOTIF_CONFIG_DATA = VirtioF::NOTIF_CONFIG_DATA.bits(); + /// Device-independent Bit. See [`virtio_spec::F::NOTIF_CONFIG_DATA`](crate::F::NOTIF_CONFIG_DATA). + const NOTIF_CONFIG_DATA = $crate::F::NOTIF_CONFIG_DATA.bits(); - /// Device-independent Bit. See [`VirtioF::RING_RESET`]. - const RING_RESET = VirtioF::RING_RESET.bits(); + /// Device-independent Bit. See [`virtio_spec::F::RING_RESET`](crate::F::RING_RESET). + const RING_RESET = $crate::F::RING_RESET.bits(); } } - impl From for $BitFlags { - fn from(value: VirtioF) -> Self { + impl From<$crate::F> for $BitFlags { + fn from(value: $crate::F) -> Self { Self::from_bits_retain(value.bits()) } } - impl AsRef<$BitFlags> for VirtioF { + impl AsRef<$BitFlags> for $crate::F { fn as_ref(&self) -> &$BitFlags { unsafe { &*(self as *const Self as *const $BitFlags) } } } - impl AsMut<$BitFlags> for VirtioF { + impl AsMut<$BitFlags> for $crate::F { fn as_mut(&mut self) -> &mut $BitFlags { unsafe { &mut *(self as *mut Self as *mut $BitFlags) } } } - impl From<$BitFlags> for VirtioF { + impl From<$BitFlags> for $crate::F { /// Returns the device-independent feature bits while retaining device-specific feature bits. fn from(value: $BitFlags) -> Self { - VirtioF::from_bits_retain(value.bits()) + $crate::F::from_bits_retain(value.bits()) } } - impl AsRef for $BitFlags { + impl AsRef<$crate::F> for $BitFlags { /// Returns a shared reference to the device-independent features while retaining device-specific feature bits. - fn as_ref(&self) -> &VirtioF { - unsafe { &*(self as *const Self as *const VirtioF) } + fn as_ref(&self) -> &$crate::F { + unsafe { &*(self as *const Self as *const $crate::F) } } } - impl AsMut for $BitFlags { + impl AsMut<$crate::F> for $BitFlags { /// Returns a mutable reference to the device-independent features while retaining device-specific feature bits. - fn as_mut(&mut self) -> &mut VirtioF { - unsafe { &mut *(self as *mut Self as *mut VirtioF) } + fn as_mut(&mut self) -> &mut $crate::F { + unsafe { &mut *(self as *mut Self as *mut $crate::F) } } } @@ -223,152 +223,156 @@ macro_rules! feature_bits { () => {}; } -feature_bits! { - /// Network Device Feature Bits - #[doc(alias = "VIRTIO_NET_F")] - pub struct VirtioNetF: u128 { - /// Device handles packets with partial checksum. This - /// “checksum offload” is a common feature on modern network cards. - #[doc(alias = "VIRTIO_NET_F_CSUM")] - const CSUM = 1 << 0; - - /// Driver handles packets with partial checksum. - #[doc(alias = "VIRTIO_NET_F_GUEST_CSUM")] - const GUEST_CSUM = 1 << 1; - - /// Control channel offloads - /// reconfiguration support. - #[doc(alias = "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS")] - const CTRL_GUEST_OFFLOADS = 1 << 2; - - /// Device maximum MTU reporting is supported. If - /// offered by the device, device advises driver about the value of - /// its maximum MTU. If negotiated, the driver uses _mtu_ as - /// the maximum MTU value. - #[doc(alias = "VIRTIO_NET_F_MTU")] - const MTU = 1 << 3; - - /// Device has given MAC address. - #[doc(alias = "VIRTIO_NET_F_MAC")] - const MAC = 1 << 5; - - /// Driver can receive TSOv4. - #[doc(alias = "VIRTIO_NET_F_GUEST_TSO4")] - const GUEST_TSO4 = 1 << 7; - - /// Driver can receive TSOv6. - #[doc(alias = "VIRTIO_NET_F_GUEST_TSO6")] - const GUEST_TSO6 = 1 << 8; - - /// Driver can receive TSO with ECN. - #[doc(alias = "VIRTIO_NET_F_GUEST_ECN")] - const GUEST_ECN = 1 << 9; - - /// Driver can receive UFO. - #[doc(alias = "VIRTIO_NET_F_GUEST_UFO")] - const GUEST_UFO = 1 << 10; - - /// Device can receive TSOv4. - #[doc(alias = "VIRTIO_NET_F_HOST_TSO4")] - const HOST_TSO4 = 1 << 11; - - /// Device can receive TSOv6. - #[doc(alias = "VIRTIO_NET_F_HOST_TSO6")] - const HOST_TSO6 = 1 << 12; - - /// Device can receive TSO with ECN. - #[doc(alias = "VIRTIO_NET_F_HOST_ECN")] - const HOST_ECN = 1 << 13; - - /// Device can receive UFO. - #[doc(alias = "VIRTIO_NET_F_HOST_UFO")] - const HOST_UFO = 1 << 14; - - /// Driver can merge receive buffers. - #[doc(alias = "VIRTIO_NET_F_MRG_RXBUF")] - const MRG_RXBUF = 1 << 15; - - /// Configuration status field is - /// available. - #[doc(alias = "VIRTIO_NET_F_STATUS")] - const STATUS = 1 << 16; - - /// Control channel is available. - #[doc(alias = "VIRTIO_NET_F_CTRL_VQ")] - const CTRL_VQ = 1 << 17; - - /// Control channel RX mode support. - #[doc(alias = "VIRTIO_NET_F_CTRL_RX")] - const CTRL_RX = 1 << 18; - - /// Control channel VLAN filtering. - #[doc(alias = "VIRTIO_NET_F_CTRL_VLAN")] - const CTRL_VLAN = 1 << 19; - - /// Driver can send gratuitous - /// packets. - #[doc(alias = "VIRTIO_NET_F_GUEST_ANNOUNCE")] - const GUEST_ANNOUNCE = 1 << 21; - - /// Device supports multiqueue with automatic - /// receive steering. - #[doc(alias = "VIRTIO_NET_F_MQ")] - const MQ = 1 << 22; - - /// Set MAC address through control - /// channel. - #[doc(alias = "VIRTIO_NET_F_CTRL_MAC_ADDR")] - const CTRL_MAC_ADDR = 1 << 23; - - /// Device can receive USO packets. Unlike UFO - /// (fragmenting the packet) the USO splits large UDP packet - /// to several segments when each of these smaller packets has UDP header. - #[doc(alias = "VIRTIO_NET_F_HOST_USO")] - const HOST_USO = 1 << 56; - - /// Device can report per-packet hash - /// value and a type of calculated hash. - #[doc(alias = "VIRTIO_NET_F_HASH_REPORT")] - const HASH_REPORT = 1 << 57; - - /// Driver can provide the exact _hdr_len_ - /// value. Device benefits from knowing the exact header length. - #[doc(alias = "VIRTIO_NET_F_GUEST_HDRLEN")] - const GUEST_HDRLEN = 1 << 59; - - /// Device supports RSS (receive-side scaling) - /// with Toeplitz hash calculation and configurable hash - /// parameters for receive steering. - #[doc(alias = "VIRTIO_NET_F_RSS")] - const RSS = 1 << 60; - - /// Device can process duplicated ACKs - /// and report number of coalesced segments and duplicated ACKs. - #[doc(alias = "VIRTIO_NET_F_RSC_EXT")] - const RSC_EXT = 1 << 61; - - /// Device may act as a standby for a primary - /// device with the same MAC address. - #[doc(alias = "VIRTIO_NET_F_STANDBY")] - const STANDBY = 1 << 62; - - /// Device reports speed and duplex. - #[doc(alias = "VIRTIO_NET_F_SPEED_DUPLEX")] - const SPEED_DUPLEX = 1 << 63; - - const _ = !0; +pub mod net { + feature_bits! { + /// Network Device Feature Bits + #[doc(alias = "VIRTIO_NET_F")] + pub struct F: u128 { + /// Device handles packets with partial checksum. This + /// “checksum offload” is a common feature on modern network cards. + #[doc(alias = "VIRTIO_NET_F_CSUM")] + const CSUM = 1 << 0; + + /// Driver handles packets with partial checksum. + #[doc(alias = "VIRTIO_NET_F_GUEST_CSUM")] + const GUEST_CSUM = 1 << 1; + + /// Control channel offloads + /// reconfiguration support. + #[doc(alias = "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS")] + const CTRL_GUEST_OFFLOADS = 1 << 2; + + /// Device maximum MTU reporting is supported. If + /// offered by the device, device advises driver about the value of + /// its maximum MTU. If negotiated, the driver uses _mtu_ as + /// the maximum MTU value. + #[doc(alias = "VIRTIO_NET_F_MTU")] + const MTU = 1 << 3; + + /// Device has given MAC address. + #[doc(alias = "VIRTIO_NET_F_MAC")] + const MAC = 1 << 5; + + /// Driver can receive TSOv4. + #[doc(alias = "VIRTIO_NET_F_GUEST_TSO4")] + const GUEST_TSO4 = 1 << 7; + + /// Driver can receive TSOv6. + #[doc(alias = "VIRTIO_NET_F_GUEST_TSO6")] + const GUEST_TSO6 = 1 << 8; + + /// Driver can receive TSO with ECN. + #[doc(alias = "VIRTIO_NET_F_GUEST_ECN")] + const GUEST_ECN = 1 << 9; + + /// Driver can receive UFO. + #[doc(alias = "VIRTIO_NET_F_GUEST_UFO")] + const GUEST_UFO = 1 << 10; + + /// Device can receive TSOv4. + #[doc(alias = "VIRTIO_NET_F_HOST_TSO4")] + const HOST_TSO4 = 1 << 11; + + /// Device can receive TSOv6. + #[doc(alias = "VIRTIO_NET_F_HOST_TSO6")] + const HOST_TSO6 = 1 << 12; + + /// Device can receive TSO with ECN. + #[doc(alias = "VIRTIO_NET_F_HOST_ECN")] + const HOST_ECN = 1 << 13; + + /// Device can receive UFO. + #[doc(alias = "VIRTIO_NET_F_HOST_UFO")] + const HOST_UFO = 1 << 14; + + /// Driver can merge receive buffers. + #[doc(alias = "VIRTIO_NET_F_MRG_RXBUF")] + const MRG_RXBUF = 1 << 15; + + /// Configuration status field is + /// available. + #[doc(alias = "VIRTIO_NET_F_STATUS")] + const STATUS = 1 << 16; + + /// Control channel is available. + #[doc(alias = "VIRTIO_NET_F_CTRL_VQ")] + const CTRL_VQ = 1 << 17; + + /// Control channel RX mode support. + #[doc(alias = "VIRTIO_NET_F_CTRL_RX")] + const CTRL_RX = 1 << 18; + + /// Control channel VLAN filtering. + #[doc(alias = "VIRTIO_NET_F_CTRL_VLAN")] + const CTRL_VLAN = 1 << 19; + + /// Driver can send gratuitous + /// packets. + #[doc(alias = "VIRTIO_NET_F_GUEST_ANNOUNCE")] + const GUEST_ANNOUNCE = 1 << 21; + + /// Device supports multiqueue with automatic + /// receive steering. + #[doc(alias = "VIRTIO_NET_F_MQ")] + const MQ = 1 << 22; + + /// Set MAC address through control + /// channel. + #[doc(alias = "VIRTIO_NET_F_CTRL_MAC_ADDR")] + const CTRL_MAC_ADDR = 1 << 23; + + /// Device can receive USO packets. Unlike UFO + /// (fragmenting the packet) the USO splits large UDP packet + /// to several segments when each of these smaller packets has UDP header. + #[doc(alias = "VIRTIO_NET_F_HOST_USO")] + const HOST_USO = 1 << 56; + + /// Device can report per-packet hash + /// value and a type of calculated hash. + #[doc(alias = "VIRTIO_NET_F_HASH_REPORT")] + const HASH_REPORT = 1 << 57; + + /// Driver can provide the exact _hdr_len_ + /// value. Device benefits from knowing the exact header length. + #[doc(alias = "VIRTIO_NET_F_GUEST_HDRLEN")] + const GUEST_HDRLEN = 1 << 59; + + /// Device supports RSS (receive-side scaling) + /// with Toeplitz hash calculation and configurable hash + /// parameters for receive steering. + #[doc(alias = "VIRTIO_NET_F_RSS")] + const RSS = 1 << 60; + + /// Device can process duplicated ACKs + /// and report number of coalesced segments and duplicated ACKs. + #[doc(alias = "VIRTIO_NET_F_RSC_EXT")] + const RSC_EXT = 1 << 61; + + /// Device may act as a standby for a primary + /// device with the same MAC address. + #[doc(alias = "VIRTIO_NET_F_STANDBY")] + const STANDBY = 1 << 62; + + /// Device reports speed and duplex. + #[doc(alias = "VIRTIO_NET_F_SPEED_DUPLEX")] + const SPEED_DUPLEX = 1 << 63; + + const _ = !0; + } } } -feature_bits! { - /// File System Device Feature Bits - #[doc(alias = "VIRTIO_FS_F")] - pub struct VirtioFsF: u128 { - /// Device has support for FUSE notify - /// messages. The notification queue is virtqueue 1. - #[doc(alias = "VIRTIO_FS_F_NOTIFICATION")] - const NOTIFICATION = 1 << 0; - - const _ = !0; +pub mod fs { + feature_bits! { + /// File System Device Feature Bits + #[doc(alias = "VIRTIO_FS_F")] + pub struct F: u128 { + /// Device has support for FUSE notify + /// messages. The notification queue is virtqueue 1. + #[doc(alias = "VIRTIO_FS_F_NOTIFICATION")] + const NOTIFICATION = 1 << 0; + + const _ = !0; + } } } diff --git a/virtio-spec/src/lib.rs b/virtio-spec/src/lib.rs index 83239f81b3..20a98be351 100644 --- a/virtio-spec/src/lib.rs +++ b/virtio-spec/src/lib.rs @@ -25,7 +25,7 @@ macro_rules! virtio_bitflags { zerocopy_derive::AsBytes ) )] - #[derive(Clone, Copy, PartialEq, Eq, Hash)] + #[derive(Default, Clone, Copy, PartialEq, Eq, Hash)] #[repr(transparent)] $(#[$outer])* $vis struct $BitFlags($T); @@ -66,10 +66,22 @@ macro_rules! virtio_bitflags { () => {}; } -pub mod features; +#[macro_use] +mod volatile; +mod features; +pub mod net; pub mod num; pub mod pci; +pub use features::F; +pub use volatile::WideVolatilePtr; + +pub mod fs { + //! File System Device + + pub use super::features::fs::F; +} + virtio_bitflags! { /// Device Status Field /// diff --git a/virtio-spec/src/net.rs b/virtio-spec/src/net.rs new file mode 100644 index 0000000000..ea94fc0eac --- /dev/null +++ b/virtio-spec/src/net.rs @@ -0,0 +1,88 @@ +//! Network Device + +pub use super::features::net::F; +use crate::num::{le16, le32}; + +virtio_bitflags! { + /// Network Device Header Flags + #[doc(alias = "VIRTIO_NET_HDR_F")] + pub struct HdrF: u8 { + #[doc(alias = "VIRTIO_NET_HDR_F_NEEDS_CSUM")] + const NEEDS_CSUM = 1; + + #[doc(alias = "VIRTIO_NET_HDR_F_DATA_VALID")] + const DATA_VALID = 2; + + #[doc(alias = "VIRTIO_NET_HDR_F_RSC_INFO")] + const RSC_INFO = 4; + } +} + +virtio_bitflags! { + /// Network Device Header GSO Type + #[doc(alias = "VIRTIO_NET_HDR_GSO")] + pub struct HdrGso: u8 { + #[doc(alias = "VIRTIO_NET_HDR_GSO_NONE")] + const NONE = 0; + + #[doc(alias = "VIRTIO_NET_HDR_GSO_TCPV4")] + const TCPV4 = 1; + + #[doc(alias = "VIRTIO_NET_HDR_GSO_UDP")] + const UDP = 3; + + #[doc(alias = "VIRTIO_NET_HDR_GSO_TCPV6")] + const TCPV6 = 4; + + #[doc(alias = "VIRTIO_NET_HDR_GSO_UDP_L4")] + const UDP_L4 = 5; + + #[doc(alias = "VIRTIO_NET_HDR_GSO_ECN")] + const ECN = 0x80; + } +} + +/// Network Device Header +#[doc(alias = "virtio_net_hdr")] +#[cfg_attr( + feature = "zerocopy", + derive( + zerocopy_derive::FromZeroes, + zerocopy_derive::FromBytes, + zerocopy_derive::AsBytes + ) +)] +#[derive(Default, Clone, Copy, Debug)] +#[repr(C)] +pub struct Hdr { + pub flags: HdrF, + pub gso_type: HdrGso, + pub hdr_len: le16, + pub gso_size: le16, + pub csum_start: le16, + pub csum_offset: le16, + pub num_buffers: le16, +} + +/// Network Device Header Hash Report +/// +/// Only if VIRTIO_NET_F_HASH_REPORT negotiated +#[doc(alias = "virtio_net_hdr")] +#[cfg_attr( + feature = "zerocopy", + derive( + zerocopy_derive::FromZeroes, + zerocopy_derive::FromBytes, + zerocopy_derive::AsBytes + ) +)] +#[derive(Default, Clone, Copy, Debug)] +#[repr(C)] +pub struct HdrHashReport { + /// Only if VIRTIO_NET_F_HASH_REPORT negotiated + pub hash_value: le32, + /// Only if VIRTIO_NET_F_HASH_REPORT negotiated + pub hash_report: le16, + /// Only if VIRTIO_NET_F_HASH_REPORT negotiated + pub padding_reserved: le16, +} diff --git a/virtio-spec/src/num.rs b/virtio-spec/src/num.rs index f2c0dd0475..c5f758dabc 100644 --- a/virtio-spec/src/num.rs +++ b/virtio-spec/src/num.rs @@ -1,12 +1,14 @@ //! Byte order-aware numeric primitives. +use core::mem; + macro_rules! le_impl { ($SelfT:ident, $ActualT:ty, $to:ident, $from:ident, $bits:expr, $order:expr) => { #[doc = concat!("A ", stringify!($bits), "-bit unsigned integer stored in ", $order, " byte order.")] #[allow(non_camel_case_types)] #[must_use] #[cfg_attr(feature = "zerocopy", derive(zerocopy_derive::FromZeroes, zerocopy_derive::FromBytes, zerocopy_derive::AsBytes))] - #[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] + #[derive(Default, Hash, PartialEq, Eq, Clone, Copy, Debug)] #[repr(transparent)] pub struct $SelfT($ActualT); @@ -40,6 +42,30 @@ macro_rules! le_impl { }; } +impl be64 { + /// Create an integer from its representation as a [`be32`] array in big endian. + pub const fn from_be_parts(parts: [be32; 2]) -> Self { + unsafe { mem::transmute(parts) } + } + + /// Return the memory representation of this integer as a [`be32`] array in big-endian (network) byte order. + pub const fn to_be_parts(self) -> [be32; 2] { + unsafe { mem::transmute(self) } + } +} + +impl le64 { + /// Create an integer from its representation as a [`le32`] array in little endian. + pub const fn from_le_parts(parts: [le32; 2]) -> Self { + unsafe { mem::transmute(parts) } + } + + /// Return the memory representation of this integer as a [`le32`] array in little-endian byte order. + pub const fn to_le_parts(self) -> [le32; 2] { + unsafe { mem::transmute(self) } + } +} + le_impl!(be16, u16, to_be, from_be, 16, "big-endian"); le_impl!(be32, u32, to_be, from_be, 32, "big-endian"); le_impl!(be64, u64, to_be, from_be, 64, "big-endian"); diff --git a/virtio-spec/src/pci.rs b/virtio-spec/src/pci.rs index 2cbb2918d8..443c3142ff 100644 --- a/virtio-spec/src/pci.rs +++ b/virtio-spec/src/pci.rs @@ -1,10 +1,10 @@ //! Definitions for Virtio over PCI bus. -use volatile::access::ReadOnly; -use volatile::VolatileFieldAccess; +use volatile::access::{ReadOnly, ReadWrite, RestrictAccess}; +use volatile::{VolatileFieldAccess, VolatilePtr}; use crate::num::*; -use crate::DeviceStatus; +use crate::{DeviceStatus, WideVolatilePtr}; /// Common configuration structure /// @@ -15,7 +15,6 @@ use crate::DeviceStatus; derive(zerocopy_derive::FromZeroes, zerocopy_derive::FromBytes) )] #[derive(VolatileFieldAccess)] -#[allow(non_camel_case_types)] #[repr(C)] pub struct CommonCfg { /// The driver uses this to select which feature bits `device_feature` shows. @@ -81,13 +80,22 @@ pub struct CommonCfg { queue_notify_off: le16, /// The driver writes the physical address of Descriptor Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. - queue_desc: le64, + queue_desc_low: le32, + + /// The driver writes the physical address of Descriptor Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. + queue_desc_high: le32, /// The driver writes the physical address of Driver Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. - queue_driver: le64, + queue_driver_low: le32, + + /// The driver writes the physical address of Driver Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. + queue_driver_high: le32, + + /// The driver writes the physical address of Device Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. + queue_device_low: le32, /// The driver writes the physical address of Device Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. - queue_device: le64, + queue_device_high: le32, /// This field exists only if [`VIRTIO_F_NOTIF_CONFIG_DATA`] has been negotiated. /// The driver will use this value to put it in the 'virtqueue number' field @@ -104,7 +112,7 @@ pub struct CommonCfg { /// /// /// - /// [`VIRTIO_F_NOTIF_CONFIG_DATA`]: crate::features::VirtioF::NOTIF_CONFIG_DATA + /// [`VIRTIO_F_NOTIF_CONFIG_DATA`]: crate::F::NOTIF_CONFIG_DATA #[access(ReadOnly)] queue_notify_data: le16, @@ -112,6 +120,20 @@ pub struct CommonCfg { /// This field exists only if [`VIRTIO_F_RING_RESET`] has been /// negotiated. (see _Basic Facilities of a Virtio Device / Virtqueues / Virtqueue Reset_). /// - /// [`VIRTIO_F_RING_RESET`]: crate::features::VirtioF::RING_RESET + /// [`VIRTIO_F_RING_RESET`]: crate::F::RING_RESET queue_reset: le16, } + +impl_wide_field_access! { + /// Common configuration structure + pub trait CommonCfgVolatileWideFieldAccess<'a, A>: CommonCfg { + /// The driver writes the physical address of Device Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. + queue_desc: queue_desc_low, queue_desc_high; + + /// The driver writes the physical address of Device Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. + queue_driver: queue_driver_low, queue_driver_high; + + /// The driver writes the physical address of Device Area here. See section _Basic Facilities of a Virtio Device / Virtqueues_. + queue_device: queue_device_low, queue_device_high; + } +} diff --git a/virtio-spec/src/volatile.rs b/virtio-spec/src/volatile.rs new file mode 100644 index 0000000000..1537de2239 --- /dev/null +++ b/virtio-spec/src/volatile.rs @@ -0,0 +1,107 @@ +//! Volatile Pointer Types. + +use volatile::access::{Readable, Writable}; +use volatile::VolatilePtr; + +use crate::num::{be32, be64, le32, le64}; + +/// A wide volatile pointer for 64-bit fields. +/// +/// In virtio, 64-bit fields are to be treated as two 32-bit fields, with low 32 bit part followed by the high 32 bit part. +/// This type mimics [`VolatilePtr`], and allows easy access to 64-bit fields. +pub struct WideVolatilePtr<'a, T, A> { + low: VolatilePtr<'a, T, A>, + high: VolatilePtr<'a, T, A>, +} + +impl<'a, T, A> WideVolatilePtr<'a, T, A> { + /// Creates a new wide volatile pointer from pointers to the low and to the high part. + pub fn from_low_high(low: VolatilePtr<'a, T, A>, high: VolatilePtr<'a, T, A>) -> Self { + Self { low, high } + } +} + +impl<'a, A> WideVolatilePtr<'a, le32, A> { + /// Performs a volatile read of the contained value. + /// + /// See [`VolatilePtr::read`]. + pub fn read(self) -> le64 + where + A: Readable, + { + let low = self.low.read(); + let high = self.high.read(); + le64::from_le_parts([low, high]) + } + + /// Performs a volatile write, setting the contained value to the given `value`. + /// + /// See [`VolatilePtr::write`]. + pub fn write(self, value: le64) + where + A: Writable, + { + let [low, high] = value.to_le_parts(); + self.low.write(low); + self.high.write(high); + } +} + +impl<'a, A> WideVolatilePtr<'a, be32, A> { + /// Performs a volatile read of the contained value. + /// + /// See [`VolatilePtr::read`]. + pub fn read(self) -> be64 + where + A: Readable, + { + let low = self.low.read(); + let high = self.high.read(); + be64::from_be_parts([low, high]) + } + + /// Performs a volatile write, setting the contained value to the given `value`. + /// + /// See [`VolatilePtr::write`]. + pub fn write(self, value: be64) + where + A: Writable, + { + let [low, high] = value.to_be_parts(); + self.low.write(low); + self.high.write(high); + } +} + +macro_rules! impl_wide_field_access { + ( + $(#[$outer:meta])* + $vis:vis trait $Trait:ident<'a, A>: $T:ty { + $( + $(#[$inner:meta])* + $field:ident: $field_low:ident, $field_high:ident; + )* + } + ) => { + $(#[$outer])* + $vis trait $Trait<'a, A> { + $( + $(#[$inner])* + fn $field(self) -> WideVolatilePtr<'a, le32, A::Restricted> + where + A: RestrictAccess; + )* + } + + impl<'a, A> $Trait<'a, A> for VolatilePtr<'a, $T, A> { + $( + fn $field(self) -> WideVolatilePtr<'a, le32, A::Restricted> + where + A: RestrictAccess, + { + WideVolatilePtr::from_low_high(self.$field_low(), self.$field_high()) + } + )* + } + }; +} diff --git a/xtask/src/clippy.rs b/xtask/src/clippy.rs index 34c5dc464e..ac147c12c2 100644 --- a/xtask/src/clippy.rs +++ b/xtask/src/clippy.rs @@ -22,7 +22,7 @@ impl Clippy { .run()?; cmd!(sh, "cargo clippy --target={triple}") .arg("--no-default-features") - .arg("--features=fs,tcp") + .arg("--features=tcp") .run()?; cmd!(sh, "cargo clippy --target={triple}") .arg("--no-default-features")