From 02860f29ddd7accfa0446bbc5c59e0e6fca8ad2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Wed, 21 Feb 2024 15:25:31 +0100 Subject: [PATCH 1/4] virtq: use a trait for the common queue interface Use a trait instead of a wrapper enum to represent the interface provided by both SplitVq and PackedVq. --- src/drivers/fs/virtio_fs.rs | 15 +- src/drivers/net/virtio_mmio.rs | 4 +- src/drivers/net/virtio_net.rs | 105 +++--- src/drivers/net/virtio_pci.rs | 9 +- src/drivers/virtio/virtqueue/mod.rs | 425 +++++++++++-------------- src/drivers/virtio/virtqueue/packed.rs | 248 ++++++--------- src/drivers/virtio/virtqueue/split.rs | 234 ++++++-------- 7 files changed, 449 insertions(+), 591 deletions(-) diff --git a/src/drivers/fs/virtio_fs.rs b/src/drivers/fs/virtio_fs.rs index f4502a4608..d5c401db7e 100644 --- a/src/drivers/fs/virtio_fs.rs +++ b/src/drivers/fs/virtio_fs.rs @@ -13,8 +13,9 @@ use crate::drivers::virtio::error::VirtioFsError; 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::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ - AsSliceU8, BuffSpec, BufferToken, Bytes, Virtq, VqIndex, VqSize, VqType, + AsSliceU8, BuffSpec, BufferToken, Bytes, Virtq, VqIndex, VqSize, }; use crate::fs::fuse::{self, FuseInterface}; @@ -37,7 +38,7 @@ pub(crate) struct VirtioFsDriver { pub(super) com_cfg: ComCfg, pub(super) isr_stat: IsrStatus, pub(super) notif_cfg: NotifCfg, - pub(super) vqueues: Vec>, + pub(super) vqueues: Vec>, pub(super) ready_queue: Vec, pub(super) irq: InterruptLine, } @@ -126,23 +127,21 @@ impl VirtioFsDriver { // create the queues and tell device about them for i in 0..vqnum as u16 { - let vq = Virtq::new( + let vq = SplitVq::new( &mut self.com_cfg, &self.notif_cfg, VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Split, VqIndex::from(i), self.dev_cfg.features.into(), - ); + ) + .unwrap(); self.vqueues.push(Rc::new(vq)); } let cmd_spec = Some(BuffSpec::Single(Bytes::new(64 * 1024 + 128).unwrap())); let rsp_spec = Some(BuffSpec::Single(Bytes::new(64 * 1024 + 128).unwrap())); - if let Ok(buff_tkn) = - self.vqueues[1].prep_buffer(Rc::clone(&self.vqueues[1]), cmd_spec, rsp_spec) - { + if let Ok(buff_tkn) = self.vqueues[1].clone().prep_buffer(cmd_spec, rsp_spec) { self.ready_queue.push(buff_tkn); // At this point the device is "live" self.com_cfg.drv_ok(); diff --git a/src/drivers/net/virtio_mmio.rs b/src/drivers/net/virtio_mmio.rs index a954042965..2ebc5b0073 100644 --- a/src/drivers/net/virtio_mmio.rs +++ b/src/drivers/net/virtio_mmio.rs @@ -139,12 +139,12 @@ impl VirtioNetDriver { notif_cfg, ctrl_vq: CtrlQueue::new(None), recv_vqs: RxQueues::new( - Vec::>::new(), + Vec::>::new(), Rc::new(RefCell::new(VecDeque::new())), false, ), send_vqs: TxQueues::new( - Vec::>::new(), + Vec::>::new(), Rc::new(RefCell::new(VecDeque::new())), Vec::new(), false, diff --git a/src/drivers/net/virtio_net.rs b/src/drivers/net/virtio_net.rs index ccd1bd47a1..a18e78ed62 100644 --- a/src/drivers/net/virtio_net.rs +++ b/src/drivers/net/virtio_net.rs @@ -30,8 +30,10 @@ use crate::drivers::net::NetworkDriver; 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::virtqueue::packed::PackedVq; +use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ - BuffSpec, BufferToken, Bytes, Transfer, Virtq, VqIndex, VqSize, VqType, + BuffSpec, BufferToken, Bytes, Transfer, Virtq, VqIndex, VqSize, }; use crate::executor::device::{RxToken, TxToken}; @@ -77,10 +79,10 @@ impl Default for VirtioNetHdr { } } -pub struct CtrlQueue(Option>); +pub struct CtrlQueue(Option>); impl CtrlQueue { - pub fn new(vq: Option>) -> Self { + pub fn new(vq: Option>) -> Self { CtrlQueue(vq) } } @@ -153,14 +155,14 @@ enum MqCmd { } pub struct RxQueues { - vqs: Vec>, + vqs: Vec>, poll_queue: Rc>>, is_multi: bool, } impl RxQueues { pub fn new( - vqs: Vec>, + vqs: Vec>, poll_queue: Rc>>, is_multi: bool, ) -> Self { @@ -188,10 +190,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, vq: Virtq, dev_cfg: &NetDevCfg) { - // Safe virtqueue - let rc_vq = Rc::new(vq); - let vq = &rc_vq; + fn add(&mut self, vq: Rc, dev_cfg: &NetDevCfg) { let num_buff: u16 = vq.size().into(); let rx_size = if dev_cfg @@ -208,7 +207,7 @@ impl RxQueues { // let spec = BuffSpec::Single(Bytes::new(rx_size).unwrap()); for _ in 0..num_buff { - let buff_tkn = match vq.prep_buffer(Rc::clone(vq), None, Some(spec.clone())) { + let buff_tkn = match vq.clone().prep_buffer(None, Some(spec.clone())) { Ok(tkn) => tkn, Err(_vq_err) => { error!("Setup of network queue failed, which should not happen!"); @@ -225,7 +224,7 @@ impl RxQueues { } // Safe virtqueue - self.vqs.push(rc_vq); + self.vqs.push(vq); if self.vqs.len() > 1 { self.is_multi = true; @@ -277,7 +276,7 @@ impl RxQueues { /// Structure which handles transmission of packets and delegation /// to the respective queue structures. pub struct TxQueues { - vqs: Vec>, + vqs: Vec>, poll_queue: Rc>>, ready_queue: Vec, /// Indicates, whether the Driver/Device are using multiple @@ -287,7 +286,7 @@ pub struct TxQueues { impl TxQueues { pub fn new( - vqs: Vec>, + vqs: Vec>, poll_queue: Rc>>, ready_queue: Vec, is_multi: bool, @@ -331,9 +330,9 @@ impl TxQueues { } } - fn add(&mut self, vq: Virtq, dev_cfg: &NetDevCfg) { + fn add(&mut self, vq: Rc, dev_cfg: &NetDevCfg) { // Safe virtqueue - self.vqs.push(Rc::new(vq)); + self.vqs.push(vq.clone()); if self.vqs.len() == 1 { // Unwrapping is safe, as one virtq will be definitely in the vector. let vq = self.vqs.first().unwrap(); @@ -359,7 +358,8 @@ impl TxQueues { for _ in 0..num_buff { self.ready_queue.push( - vq.prep_buffer(Rc::clone(vq), Some(spec.clone()), None) + vq.clone() + .prep_buffer(Some(spec.clone()), None) .unwrap() .write_seq(Some(&VirtioNetHdr::default()), None::<&VirtioNetHdr>) .unwrap(), @@ -379,7 +379,8 @@ impl TxQueues { for _ in 0..num_buff { self.ready_queue.push( - vq.prep_buffer(Rc::clone(vq), Some(spec.clone()), None) + vq.clone() + .prep_buffer(Some(spec.clone()), None) .unwrap() .write_seq(Some(&VirtioNetHdr::default()), None::<&VirtioNetHdr>) .unwrap(), @@ -436,7 +437,7 @@ impl TxQueues { // As usize is currently safe as the minimal usize is defined as 16bit in rust. let spec = BuffSpec::Single(Bytes::new(len).unwrap()); - match self.vqs[0].prep_buffer(Rc::clone(&self.vqs[0]), Some(spec), None) { + match self.vqs[0].clone().prep_buffer(Some(spec), None) { Ok(tkn) => Some((tkn, 0)), Err(_) => { // Here it is possible if multiple queues are enabled to get another buffertoken from them! @@ -974,23 +975,27 @@ impl VirtioNetDriver { .features .is_feature(Features::VIRTIO_F_RING_PACKED) { - self.ctrl_vq = CtrlQueue(Some(Rc::new(Virtq::new( - &mut self.com_cfg, - &self.notif_cfg, - VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Packed, - VqIndex::from(self.num_vqs), - self.dev_cfg.features.into(), - )))); + self.ctrl_vq = CtrlQueue(Some(Rc::new( + PackedVq::new( + &mut self.com_cfg, + &self.notif_cfg, + VqSize::from(VIRTIO_MAX_QUEUE_SIZE), + VqIndex::from(self.num_vqs), + self.dev_cfg.features.into(), + ) + .unwrap(), + ))); } else { - self.ctrl_vq = CtrlQueue(Some(Rc::new(Virtq::new( - &mut self.com_cfg, - &self.notif_cfg, - VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Split, - VqIndex::from(self.num_vqs), - self.dev_cfg.features.into(), - )))); + self.ctrl_vq = CtrlQueue(Some(Rc::new( + SplitVq::new( + &mut self.com_cfg, + &self.notif_cfg, + VqSize::from(VIRTIO_MAX_QUEUE_SIZE), + VqIndex::from(self.num_vqs), + self.dev_cfg.features.into(), + ) + .unwrap(), + ))); } self.ctrl_vq.0.as_ref().unwrap().enable_notifs(); @@ -1037,57 +1042,57 @@ impl VirtioNetDriver { .features .is_feature(Features::VIRTIO_F_RING_PACKED) { - let vq = Virtq::new( + let vq = PackedVq::new( &mut self.com_cfg, &self.notif_cfg, VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Packed, VqIndex::from(2 * i), self.dev_cfg.features.into(), - ); + ) + .unwrap(); // Interrupt for receiving packets is wanted vq.enable_notifs(); - self.recv_vqs.add(vq, &self.dev_cfg); + self.recv_vqs.add(Rc::from(vq), &self.dev_cfg); - let vq = Virtq::new( + let vq = PackedVq::new( &mut self.com_cfg, &self.notif_cfg, VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Packed, VqIndex::from(2 * i + 1), self.dev_cfg.features.into(), - ); + ) + .unwrap(); // Interrupt for comunicating that a sended packet left, is not needed vq.disable_notifs(); - self.send_vqs.add(vq, &self.dev_cfg); + self.send_vqs.add(Rc::from(vq), &self.dev_cfg); } else { - let vq = Virtq::new( + let vq = SplitVq::new( &mut self.com_cfg, &self.notif_cfg, VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Split, VqIndex::from(2 * i), self.dev_cfg.features.into(), - ); + ) + .unwrap(); // Interrupt for receiving packets is wanted vq.enable_notifs(); - self.recv_vqs.add(vq, &self.dev_cfg); + self.recv_vqs.add(Rc::from(vq), &self.dev_cfg); - let vq = Virtq::new( + let vq = SplitVq::new( &mut self.com_cfg, &self.notif_cfg, VqSize::from(VIRTIO_MAX_QUEUE_SIZE), - VqType::Split, VqIndex::from(2 * i + 1), self.dev_cfg.features.into(), - ); + ) + .unwrap(); // Interrupt for comunicating that a sended packet left, is not needed vq.disable_notifs(); - self.send_vqs.add(vq, &self.dev_cfg); + self.send_vqs.add(Rc::from(vq), &self.dev_cfg); } } diff --git a/src/drivers/net/virtio_pci.rs b/src/drivers/net/virtio_pci.rs index 49a31c6783..e2b66c48e0 100644 --- a/src/drivers/net/virtio_pci.rs +++ b/src/drivers/net/virtio_pci.rs @@ -17,7 +17,6 @@ use crate::drivers::pci::{PciCommand, 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::virtqueue::Virtq; /// Virtio's network device configuration structure. /// See specification v1.1. - 5.1.4 @@ -147,13 +146,9 @@ impl VirtioNetDriver { notif_cfg, ctrl_vq: CtrlQueue::new(None), - recv_vqs: RxQueues::new( - Vec::>::new(), - Rc::new(RefCell::new(VecDeque::new())), - false, - ), + recv_vqs: RxQueues::new(Vec::new(), Rc::new(RefCell::new(VecDeque::new())), false), send_vqs: TxQueues::new( - Vec::>::new(), + Vec::new(), Rc::new(RefCell::new(VecDeque::new())), Vec::new(), false, diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index 633f773bb5..d67eb2cfd2 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -1,7 +1,7 @@ //! This module contains Virtio's virtqueue. //! //! The virtqueue is available in two forms. -//! [SplitVq] and [PackedVq]. +//! [split::SplitVq] and [packed::PackedVq]. //! Both queues are wrapped inside an enum [Virtq] in //! order to provide an unified interface. //! @@ -25,8 +25,6 @@ use align_address::Align; use zerocopy::AsBytes; use self::error::{BufferError, VirtqError}; -use self::packed::PackedVq; -use self::split::SplitVq; #[cfg(not(feature = "pci"))] use super::transport::mmio::{ComCfg, NotifCfg}; #[cfg(feature = "pci")] @@ -92,12 +90,6 @@ impl From for u16 { } } -/// Enum that defines which virtqueue shall be created when used via the `Virtq::new()` function. -pub enum VqType { - Packed, - Split, -} - /// The General Descriptor struct for both Packed and SplitVq. #[repr(C, align(16))] struct Descriptor { @@ -107,96 +99,29 @@ struct Descriptor { flags: u16, } -/// The Virtq enum unifies access to the two different Virtqueue types -/// [PackedVq] and [SplitVq]. +// Public interface of Virtq + +/// The Virtq trait unifies access to the two different Virtqueue types +/// [packed::PackedVq] and [split::SplitVq]. /// -/// The enum provides a common interface for both types. Which in some case +/// The trait provides a common interface for both types. Which in some case /// might not provide the complete feature set of each queue. Drivers who /// do need these features should refrain from providing support for both /// Virtqueue types and use the structs directly instead. -pub enum Virtq { - Packed(PackedVq), - Split(SplitVq), -} - -// Private Interface of the Virtq -impl Virtq { +pub trait Virtq { /// Entry function which the TransferTokens can use, when they are dispatching /// themselves via their `Rc` reference /// /// The `notif` parameter indicates if the driver wants to have a notification for this specific /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the /// updated notification flags before finishing transfers! - fn dispatch(&self, tkn: TransferToken, notif: bool) { - match self { - Virtq::Packed(vq) => vq.dispatch(tkn, notif), - Virtq::Split(vq) => vq.dispatch(tkn, notif), - }; - } -} - -// Public Interface solely for page boundary checking and other convenience functions -impl Virtq { - /// Allows to check, if a given structure crosses a physical page boundary. - /// Returns true, if the structure does NOT cross a boundary or crosses only - /// contiguous physical page boundaries. - /// - /// Structures provided to the Queue must pass this test, otherwise the queue - /// currently panics. - pub fn check_bounds(data: &T) -> bool { - let slice = data.as_slice_u8(); - - let start_virt = ptr::from_ref(slice.first().unwrap()).addr(); - let end_virt = ptr::from_ref(slice.last().unwrap()).addr(); - let end_phy_calc = paging::virt_to_phys(VirtAddr::from(start_virt)) + (slice.len() - 1); - let end_phy = paging::virt_to_phys(VirtAddr::from(end_virt)); + fn dispatch(&self, tkn: TransferToken, notif: bool); - end_phy == end_phy_calc - } - - /// Allows to check, if a given slice crosses a physical page boundary. - /// Returns true, if the slice does NOT cross a boundary or crosses only - /// contiguous physical page boundaries. - /// Slice MUST come from a boxed value. Otherwise the slice might be moved and - /// the test of this function is not longer valid. - /// - /// This check is especially useful if one wants to check if slices - /// into which the queue will destructure a structure are valid for the queue. - /// - /// Slices provided to the Queue must pass this test, otherwise the queue - /// currently panics. - pub fn check_bounds_slice(slice: &[u8]) -> bool { - let start_virt = ptr::from_ref(slice.first().unwrap()).addr(); - let end_virt = ptr::from_ref(slice.last().unwrap()).addr(); - let end_phy_calc = paging::virt_to_phys(VirtAddr::from(start_virt)) + (slice.len() - 1); - let end_phy = paging::virt_to_phys(VirtAddr::from(end_virt)); - - end_phy == end_phy_calc - } - - /// Frees memory regions gained access to via `Transfer.ret_raw()`. - pub fn free_raw(ptr: *mut u8, len: usize) { - crate::mm::deallocate(VirtAddr::from(ptr as usize), len); - } -} - -// Public interface of Virtq -impl Virtq { /// Enables interrupts for this virtqueue upon receiving a transfer - pub fn enable_notifs(&self) { - match self { - Virtq::Packed(vq) => vq.enable_notifs(), - Virtq::Split(vq) => vq.enable_notifs(), - } - } + fn enable_notifs(&self); /// Disables interrupts for this virtqueue upon receiving a transfer - pub fn disable_notifs(&self) { - match self { - Virtq::Packed(vq) => vq.disable_notifs(), - Virtq::Split(vq) => vq.disable_notifs(), - } - } + fn disable_notifs(&self); /// Checks if new used descriptors have been written by the device. /// This activates the queue and polls the descriptor ring of the queue. @@ -204,166 +129,38 @@ impl Virtq { /// * `TransferTokens` which hold an `await_queue` will be placed into /// these queues. /// * All finished `TransferTokens` will have a state of `TransferState::Finished`. - pub fn poll(&self) { - match self { - Virtq::Packed(vq) => vq.poll(), - Virtq::Split(vq) => vq.poll(), - } - } + fn poll(&self); - /// Dispatches a batch of TransferTokens. The actual behaviour depends on the respective - /// virtqueue implementation. Please see the respective docs for details. - /// - /// **INFO:** - /// Due to the missing HashMap implementation in the kernel, this function currently uses a nested - /// for-loop. The first iteration is over the number if dispatched tokens. Inside this loop, the - /// function iterates over a list of all already "used" virtqueues. If the given token belongs to an - /// existing queue it is inserted into the corresponding list of tokens, if it belongs to no queue, - /// a new entry in the "used" virtqueues list is made. - /// This procedure can possibly be very slow. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! - pub fn dispatch_batch(tkns: Vec, notif: bool) { - let mut used_vqs: Vec<(Rc, Vec)> = Vec::new(); - - // Sort the TransferTokens depending in the queue their coming from. - // then call dispatch_batch of that queue - for tkn in tkns { - let index = tkn.get_vq().index(); - let mut used = false; - let mut index_used = 0usize; - - for (pos, (vq, _)) in used_vqs.iter_mut().enumerate() { - if index == vq.index() { - index_used = pos; - used = true; - break; - } - } + fn dispatch_batch(&self, tkns: Vec, notif: bool); - if used { - let (_, tkn_lst) = &mut used_vqs[index_used]; - tkn_lst.push(tkn); - } else { - let mut new_tkn_lst = Vec::new(); - let vq = tkn.get_vq(); - new_tkn_lst.push(tkn); - - used_vqs.push((vq, new_tkn_lst)) - } - } - - for (vq_ref, tkn_lst) in used_vqs { - match vq_ref.as_ref() { - Virtq::Packed(vq) => vq.dispatch_batch(tkn_lst, notif), - Virtq::Split(vq) => vq.dispatch_batch(tkn_lst, notif), - } - } - } - - /// Dispatches a batch of TransferTokens. The Transfers will be placed in to the `await_queue` - /// upon finish. - /// - /// **INFO:** - /// Due to the missing HashMap implementation in the kernel, this function currently uses a nested - /// for-loop. The first iteration is over the number if dispatched tokens. Inside this loop, the - /// function iterates over a list of all already "used" virtqueues. If the given token belongs to an - /// existing queue it is inserted into the corresponding list of tokens, if it belongs to no queue, - /// a new entry in the "used" virtqueues list is made. - /// This procedure can possibly be very slow. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! - pub fn dispatch_batch_await( + fn dispatch_batch_await( + &self, tkns: Vec, await_queue: Rc>>, notif: bool, - ) { - let mut used_vqs: Vec<(Rc, Vec)> = Vec::new(); - - // Sort the TransferTokens depending in the queue their coming from. - // then call dispatch_batch of that queue - for tkn in tkns { - let index = tkn.get_vq().index(); - let mut used = false; - let mut index_used = 0usize; - - for (pos, (vq, _)) in used_vqs.iter_mut().enumerate() { - if index == vq.index() { - index_used = pos; - used = true; - break; - } - } + ); - if used { - let (_, tkn_lst) = &mut used_vqs[index_used]; - tkn_lst.push(tkn); - } else { - let mut new_tkn_lst = Vec::new(); - let vq = tkn.get_vq(); - new_tkn_lst.push(tkn); - - used_vqs.push((vq, new_tkn_lst)) - } - } - - for (vq, tkn_lst) in used_vqs { - match vq.as_ref() { - Virtq::Packed(vq) => { - vq.dispatch_batch_await(tkn_lst, Rc::clone(&await_queue), notif) - } - Virtq::Split(vq) => { - vq.dispatch_batch_await(tkn_lst, Rc::clone(&await_queue), notif) - } - } - } - } - - /// Creates a new Virtq of the specified (VqType)[VqType], (VqSize)[VqSize] and the (VqIndex)[VqIndex]. + /// Creates a new Virtq of the specified (VqSize)[VqSize] and the (VqIndex)[VqIndex]. /// The index represents the "ID" of the virtqueue. /// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct. /// /// Be aware, that devices define a maximum number of queues and a maximal size they can handle. - pub fn new( + fn new( com_cfg: &mut ComCfg, notif_cfg: &NotifCfg, size: VqSize, - vq_type: VqType, index: VqIndex, feats: u64, - ) -> Self { - match vq_type { - VqType::Packed => match PackedVq::new(com_cfg, notif_cfg, size, index, feats) { - Ok(packed_vq) => Virtq::Packed(packed_vq), - Err(_vq_error) => panic!("Currently panics if queue fails to be created"), - }, - VqType::Split => match SplitVq::new(com_cfg, notif_cfg, size, index, feats) { - Ok(split_vq) => Virtq::Split(split_vq), - Err(_vq_error) => panic!("Currently panics if queue fails to be created"), - }, - } - } + ) -> Result + where + Self: Sized; /// Returns the size of a Virtqueue. This represents the overall size and not the capacity the /// queue currently has for new descriptors. - pub fn size(&self) -> VqSize { - match self { - Virtq::Packed(vq) => vq.size(), - Virtq::Split(vq) => vq.size(), - } - } + fn size(&self) -> VqSize; // Returns the index (ID) of a Virtqueue. - pub fn index(&self) -> VqIndex { - match self { - Virtq::Packed(vq) => vq.index(), - Virtq::Split(vq) => vq.index(), - } - } + fn index(&self) -> VqIndex; /// Provides the calley with a TransferToken. Fails upon multiple circumstances. /// @@ -371,7 +168,7 @@ impl Virtq { /// * Data behind the respective raw pointers will NOT be deallocated. Under no circumstances. /// * Calley is responsible for ensuring the raw pointers will remain valid from start till end of transfer. /// * start: call of `fn prep_transfer_from_raw()` - /// * end: closing of [Transfer] via `Transfer.close()`. + /// * end: return of the [Transfer] via [TransferToken::dispatch_blocking] or its push to the [TransferToken::await_queue]. /// * In case the underlying BufferToken is reused, the raw pointers MUST still be valid all the time /// BufferToken exists. /// * Transfer created from this TransferTokens will ONLY allow to return a copy of the data. @@ -427,17 +224,11 @@ impl Virtq { /// ``` /// Then he must split the structure after the send part and provide the respective part via the send argument and the respective other /// part via the recv argument. - pub fn prep_transfer_from_raw( - &self, - rc_self: Rc, - send: Option<(*mut T, BuffSpec<'_>)>, - recv: Option<(*mut K, BuffSpec<'_>)>, - ) -> Result { - match self { - Virtq::Packed(vq) => vq.prep_transfer_from_raw(rc_self, send, recv), - Virtq::Split(vq) => vq.prep_transfer_from_raw(rc_self, send, recv), - } - } + fn prep_transfer_from_raw( + self: Rc, + send: Option<(&[u8], BuffSpec<'_>)>, + recv: Option<(&mut [u8], BuffSpec<'_>)>, + ) -> Result; /// Provides the calley with empty buffers as specified via the `send` and `recv` function parameters, (see [BuffSpec]), in form of /// a [BufferToken]. @@ -480,17 +271,155 @@ impl Virtq { /// // ++++++++++++++++++++++++++ /// ``` /// As a result indirect descriptors result in a single descriptor consumption in the actual queue. - pub fn prep_buffer( - &self, - rc_self: Rc, + fn prep_buffer( + self: Rc, send: Option>, recv: Option>, - ) -> Result { - match self { - Virtq::Packed(vq) => vq.prep_buffer(rc_self, send, recv), - Virtq::Split(vq) => vq.prep_buffer(rc_self, send, recv), + ) -> Result; +} + +/// Allows to check, if a given structure crosses a physical page boundary. +/// Returns true, if the structure does NOT cross a boundary or crosses only +/// contiguous physical page boundaries. +/// +/// Structures provided to the Queue must pass this test, otherwise the queue +/// currently panics. +pub fn check_bounds(data: &T) -> bool { + let slice = data.as_slice_u8(); + + let start_virt = ptr::from_ref(slice.first().unwrap()).addr(); + let end_virt = ptr::from_ref(slice.last().unwrap()).addr(); + let end_phy_calc = paging::virt_to_phys(VirtAddr::from(start_virt)) + (slice.len() - 1); + let end_phy = paging::virt_to_phys(VirtAddr::from(end_virt)); + + end_phy == end_phy_calc +} + +/// Allows to check, if a given slice crosses a physical page boundary. +/// Returns true, if the slice does NOT cross a boundary or crosses only +/// contiguous physical page boundaries. +/// Slice MUST come from a boxed value. Otherwise the slice might be moved and +/// the test of this function is not longer valid. +/// +/// This check is especially useful if one wants to check if slices +/// into which the queue will destructure a structure are valid for the queue. +/// +/// Slices provided to the Queue must pass this test, otherwise the queue +/// currently panics. +pub fn check_bounds_slice(slice: &[u8]) -> bool { + let start_virt = ptr::from_ref(slice.first().unwrap()).addr(); + let end_virt = ptr::from_ref(slice.last().unwrap()).addr(); + let end_phy_calc = paging::virt_to_phys(VirtAddr::from(start_virt)) + (slice.len() - 1); + let end_phy = paging::virt_to_phys(VirtAddr::from(end_virt)); + + end_phy == end_phy_calc +} + +/// Frees memory regions gained access to via `Transfer.ret_raw()`. +pub fn free_raw(ptr: *mut u8, len: usize) { + crate::mm::deallocate(VirtAddr::from(ptr as usize), len); +} + +/// Dispatches a batch of TransferTokens. The actual behaviour depends on the respective +/// virtqueue implementation. Please see the respective docs for details. +/// +/// **INFO:** +/// Due to the missing HashMap implementation in the kernel, this function currently uses a nested +/// for-loop. The first iteration is over the number if dispatched tokens. Inside this loop, the +/// function iterates over a list of all already "used" virtqueues. If the given token belongs to an +/// existing queue it is inserted into the corresponding list of tokens, if it belongs to no queue, +/// a new entry in the "used" virtqueues list is made. +/// This procedure can possibly be very slow. +/// +/// The `notif` parameter indicates if the driver wants to have a notification for this specific +/// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the +/// updated notification flags before finishing transfers! +pub fn dispatch_batch(tkns: Vec, notif: bool) { + let mut used_vqs: Vec<(Rc, Vec)> = Vec::new(); + + // Sort the TransferTokens depending in the queue their coming from. + // then call dispatch_batch of that queue + for tkn in tkns { + let index = tkn.get_vq().index(); + let mut used = false; + let mut index_used = 0usize; + + for (pos, (vq, _)) in used_vqs.iter_mut().enumerate() { + if index == vq.index() { + index_used = pos; + used = true; + break; + } + } + + if used { + let (_, tkn_lst) = &mut used_vqs[index_used]; + tkn_lst.push(tkn); + } else { + let mut new_tkn_lst = Vec::new(); + let vq = tkn.get_vq(); + new_tkn_lst.push(tkn); + + used_vqs.push((vq, new_tkn_lst)) + } + } + + for (vq_ref, tkn_lst) in used_vqs { + vq_ref.dispatch_batch(tkn_lst, notif); + } +} + +/// Dispatches a batch of TransferTokens. The Transfers will be placed in to the `await_queue` +/// upon finish. +/// +/// **INFO:** +/// Due to the missing HashMap implementation in the kernel, this function currently uses a nested +/// for-loop. The first iteration is over the number if dispatched tokens. Inside this loop, the +/// function iterates over a list of all already "used" virtqueues. If the given token belongs to an +/// existing queue it is inserted into the corresponding list of tokens, if it belongs to no queue, +/// a new entry in the "used" virtqueues list is made. +/// This procedure can possibly be very slow. +/// +/// The `notif` parameter indicates if the driver wants to have a notification for this specific +/// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the +/// updated notification flags before finishing transfers! +pub fn dispatch_batch_await( + tkns: Vec, + await_queue: Rc>>, + notif: bool, +) { + let mut used_vqs: Vec<(Rc, Vec)> = Vec::new(); + + // Sort the TransferTokens depending in the queue their coming from. + // then call dispatch_batch of that queue + for tkn in tkns { + let index = tkn.get_vq().index(); + let mut used = false; + let mut index_used = 0usize; + + for (pos, (vq, _)) in used_vqs.iter_mut().enumerate() { + if index == vq.index() { + index_used = pos; + used = true; + break; + } + } + + if used { + let (_, tkn_lst) = &mut used_vqs[index_used]; + tkn_lst.push(tkn); + } else { + let mut new_tkn_lst = Vec::new(); + let vq = tkn.get_vq(); + new_tkn_lst.push(tkn); + + used_vqs.push((vq, new_tkn_lst)) } } + + for (vq, tkn_lst) in used_vqs { + vq.dispatch_batch_await(tkn_lst, Rc::clone(&await_queue), notif); + } } /// The trait needs to be implemented on structures which are to be used via the `prep_transfer()` function of virtqueues and for @@ -961,7 +890,7 @@ pub struct TransferToken { /// Public Interface for TransferToken impl TransferToken { /// Returns a reference to the holding virtqueue - pub fn get_vq(&self) -> Rc { + pub fn get_vq(&self) -> Rc { // Unwrapping is okay here, as TransferToken must hold a BufferToken Rc::clone(&self.buff_tkn.as_ref().unwrap().vq) } @@ -1046,7 +975,7 @@ pub struct BufferToken { //send_desc_lst: Option>, recv_buff: Option, //recv_desc_lst: Option>, - vq: Rc, + vq: Rc, /// Indicates whether the buff is returnable ret_send: bool, ret_recv: bool, @@ -2421,6 +2350,8 @@ pub mod error { /// descriptors (both the one placed in the queue, as also the ones the indirect descriptor is /// referring to). BufferToLarge, + QueueSizeNotAllowed(u16), + FeatNotSupported(u64), } impl core::fmt::Debug for VirtqError { @@ -2437,6 +2368,8 @@ pub mod error { VirtqError::OngoingTransfer(_) => write!(f, "Transfer is ongoging and can not be used currently!"), VirtqError::WriteToLarge(_) => write!(f, "Write is to large for BufferToken!"), VirtqError::BufferToLarge => write!(f, "Buffer to large for queue! u32::MAX exceeded."), + VirtqError::QueueSizeNotAllowed(_) => write!(f, "The requested queue size is not valid."), + VirtqError:: FeatNotSupported(_) => write!(f, "An unsupported feature was requested from the queue."), } } } diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index fbd3b262ab..2519b24473 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -12,7 +12,6 @@ use core::sync::atomic::{fence, Ordering}; use align_address::Align; -use self::error::VqPackedError; use super::super::features::Features; #[cfg(not(feature = "pci"))] use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; @@ -20,8 +19,8 @@ use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::{ - AsSliceU8, BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, - TransferState, TransferToken, Virtq, VqIndex, VqSize, + BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, TransferState, + TransferToken, Virtq, VqIndex, VqSize, }; use crate::arch::mm::paging::{BasePageSize, PageSize}; use crate::arch::mm::{paging, VirtAddr}; @@ -974,19 +973,19 @@ pub struct PackedVq { // This interface is also public in order to allow people to use the PackedVq directly! // This is currently unlikely, as the Tokens hold a Rc for refering to their origin // queue. This could be eased -impl PackedVq { +impl Virtq for PackedVq { /// Enables interrupts for this virtqueue upon receiving a transfer - pub fn enable_notifs(&self) { + fn enable_notifs(&self) { self.drv_event.borrow_mut().enable_notif(); } /// Disables interrupts for this virtqueue upon receiving a transfer - pub fn disable_notifs(&self) { + fn disable_notifs(&self) { self.drv_event.borrow_mut().disable_notif(); } /// See `Virtq.poll()` documentation - pub fn poll(&self) { + fn poll(&self) { self.descr_ring.borrow_mut().poll(); } @@ -997,7 +996,7 @@ impl PackedVq { /// The `notif` parameter indicates if the driver wants to have a notification for this specific /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the /// updated notification flags before finishing transfers! - pub fn dispatch_batch(&self, tkns: Vec, notif: bool) { + fn dispatch_batch(&self, tkns: Vec, notif: bool) { // Zero transfers are not allowed assert!(!tkns.is_empty()); @@ -1042,7 +1041,7 @@ impl PackedVq { /// a device notification if wanted by the device. /// /// Tokens to get a reference to the provided await_queue, where they will be placed upon finish. - pub fn dispatch_batch_await( + fn dispatch_batch_await( &self, mut tkns: Vec, await_queue: Rc>>, @@ -1090,7 +1089,7 @@ impl PackedVq { /// The `notif` parameter indicates if the driver wants to have a notification for this specific /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the /// updated notification flags before finishing transfers! - pub fn dispatch(&self, tkn: TransferToken, notif: bool) { + fn dispatch(&self, tkn: TransferToken, notif: bool) { let (next_off, next_wrap) = self.descr_ring.borrow_mut().push(tkn); if notif { @@ -1121,18 +1120,22 @@ impl PackedVq { } /// See `Virtq.index()` documentation - pub fn index(&self) -> VqIndex { + fn index(&self) -> VqIndex { self.index } - /// See `Virtq::new()` documentation - pub fn new( + /// Creates a new Virtq of the specified (VqSize)[VqSize] and the (VqIndex)[VqIndex]. + /// The index represents the "ID" of the virtqueue. + /// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct. + /// + /// Be aware, that devices define a maximum number of queues and a maximal size they can handle. + fn new( com_cfg: &mut ComCfg, notif_cfg: &NotifCfg, size: VqSize, index: VqIndex, feats: u64, - ) -> Result { + ) -> Result { // Currently we do not have support for in order use. // This steems from the fact, that the packedVq ReadCtrl currently is not // able to derive other finished transfer from a used-buffer notification. @@ -1142,7 +1145,7 @@ impl PackedVq { // and adjust its ReadCtrl accordingly. if feats & Features::VIRTIO_F_IN_ORDER == Features::VIRTIO_F_IN_ORDER { info!("PackedVq has no support for VIRTIO_F_IN_ORDER. Aborting..."); - return Err(VqPackedError::FeatNotSupported( + return Err(VirtqError::FeatNotSupported( feats & Features::VIRTIO_F_IN_ORDER, )); } @@ -1150,7 +1153,7 @@ impl PackedVq { // Get a handler to the queues configuration area. let mut vq_handler = match com_cfg.select_vq(index.into()) { Some(handler) => handler, - None => return Err(VqPackedError::QueueNotExisting(index.into())), + None => return Err(VirtqError::QueueNotExisting(index.into())), }; // Must catch zero size as it is not allowed for packed queues. @@ -1158,7 +1161,7 @@ impl PackedVq { // // See Virtio specification v1.1. - 4.1.4.3.2 let vq_size = if (size.0 == 0) | (size.0 > 32768) { - return Err(VqPackedError::SizeNotAllowed(size.0)); + return Err(VirtqError::QueueSizeNotAllowed(size.0)); } else { vq_handler.set_vq_size(size.0) }; @@ -1227,27 +1230,24 @@ impl PackedVq { } /// See `Virtq.prep_transfer_from_raw()` documentation. - pub fn prep_transfer_from_raw( - &self, - master: Rc, - send: Option<(*mut T, BuffSpec<'_>)>, - recv: Option<(*mut K, BuffSpec<'_>)>, + fn prep_transfer_from_raw( + self: Rc, + send: Option<(&[u8], BuffSpec<'_>)>, + recv: Option<(&mut [u8], BuffSpec<'_>)>, ) -> Result { match (send, recv) { (None, None) => Err(VirtqError::BufferNotSpecified), (Some((send_data, send_spec)), None) => { match send_spec { BuffSpec::Single(size) => { - let data_slice = unsafe { (*send_data).as_slice_u8() }; - // Buffer must have the right size - if data_slice.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(data_slice.len())); + if send_data.len() != size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); } let desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), send_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -1258,11 +1258,11 @@ impl PackedVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Single { desc_lst: vec![desc].into_boxed_slice(), - len: data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: None, - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1271,15 +1271,14 @@ impl PackedVq { }) } BuffSpec::Multiple(size_lst) => { - let data_slice = unsafe { (*send_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; match self @@ -1299,11 +1298,11 @@ impl PackedVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Multiple { desc_lst: desc_lst.into_boxed_slice(), - len: data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: None, - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1312,15 +1311,14 @@ impl PackedVq { }) } BuffSpec::Indirect(size_lst) => { - let data_slice = unsafe { (*send_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; desc_lst.push( @@ -1343,11 +1341,11 @@ impl PackedVq { send_buff: Some(Buffer::Indirect { desc_lst: desc_lst.into_boxed_slice(), ctrl_desc, - len: data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: None, - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1360,16 +1358,14 @@ impl PackedVq { (None, Some((recv_data, recv_spec))) => { match recv_spec { BuffSpec::Single(size) => { - let data_slice = unsafe { (*recv_data).as_slice_u8() }; - // Buffer must have the right size - if data_slice.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(data_slice.len())); + if recv_data.len() != size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); } let desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -1381,10 +1377,10 @@ impl PackedVq { send_buff: None, recv_buff: Some(Buffer::Single { desc_lst: vec![desc].into_boxed_slice(), - len: data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1393,15 +1389,14 @@ impl PackedVq { }) } BuffSpec::Multiple(size_lst) => { - let data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; match self @@ -1422,10 +1417,10 @@ impl PackedVq { send_buff: None, recv_buff: Some(Buffer::Multiple { desc_lst: desc_lst.into_boxed_slice(), - len: data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1434,15 +1429,14 @@ impl PackedVq { }) } BuffSpec::Indirect(size_lst) => { - let data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; desc_lst.push( @@ -1466,10 +1460,10 @@ impl PackedVq { recv_buff: Some(Buffer::Indirect { desc_lst: desc_lst.into_boxed_slice(), ctrl_desc, - len: data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1482,31 +1476,27 @@ impl PackedVq { (Some((send_data, send_spec)), Some((recv_data, recv_spec))) => { match (send_spec, recv_spec) { (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; - // Buffer must have the right size - if send_data_slice.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())); + if send_data.len() != send_size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); } let send_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), send_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), }; - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; - // Buffer must have the right size - if recv_data_slice.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())); + if recv_data.len() != recv_size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); } let recv_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -1517,15 +1507,15 @@ impl PackedVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Single { desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Single { desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1534,33 +1524,28 @@ impl PackedVq { }) } (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; - // Buffer must have the right size - if send_data_slice.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())); + if send_data.len() != send_size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); } let send_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), send_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), }; - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut index = 0usize; for byte in recv_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match recv_data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; match self @@ -1580,15 +1565,15 @@ impl PackedVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Single { desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Multiple { desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1597,18 +1582,15 @@ impl PackedVq { }) } (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; let mut send_desc_lst: Vec = Vec::with_capacity(send_size_lst.len()); let mut index = 0usize; for byte in send_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match send_data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; match self @@ -1623,18 +1605,15 @@ impl PackedVq { index += usize::from(*byte); } - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut index = 0usize; for byte in recv_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match recv_data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; match self @@ -1654,15 +1633,15 @@ impl PackedVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Multiple { desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Multiple { desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1671,18 +1650,15 @@ impl PackedVq { }) } (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; let mut send_desc_lst: Vec = Vec::with_capacity(send_size_lst.len()); let mut index = 0usize; for byte in send_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match send_data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; match self @@ -1697,16 +1673,14 @@ impl PackedVq { index += usize::from(*byte); } - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; - // Buffer must have the right size - if recv_data_slice.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())); + if recv_data.len() != recv_size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); } let recv_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -1717,15 +1691,15 @@ impl PackedVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Multiple { desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Single { desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1734,18 +1708,15 @@ impl PackedVq { }) } (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; let mut send_desc_lst: Vec = Vec::with_capacity(send_size_lst.len()); let mut index = 0usize; for byte in send_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match send_data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; send_desc_lst.push( @@ -1757,18 +1728,15 @@ impl PackedVq { index += usize::from(*byte); } - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut index = 0usize; for byte in recv_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match recv_data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; recv_desc_lst.push( @@ -1793,16 +1761,16 @@ impl PackedVq { recv_buff: Some(Buffer::Indirect { desc_lst: recv_desc_lst.into_boxed_slice(), ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), send_buff: Some(Buffer::Indirect { desc_lst: send_desc_lst.into_boxed_slice(), ctrl_desc, - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1820,9 +1788,8 @@ impl PackedVq { } /// See `Virtq.prep_buffer()` documentation. - pub fn prep_buffer( - &self, - master: Rc, + fn prep_buffer( + self: Rc, send: Option>, recv: Option>, ) -> Result { @@ -1844,7 +1811,7 @@ impl PackedVq { Ok(BufferToken { send_buff: Some(buffer), recv_buff: None, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: false, reusable: true, @@ -1874,7 +1841,7 @@ impl PackedVq { Ok(BufferToken { send_buff: Some(buffer), recv_buff: None, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: false, reusable: true, @@ -1909,7 +1876,7 @@ impl PackedVq { Ok(BufferToken { send_buff: Some(buffer), recv_buff: None, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: false, reusable: true, @@ -1932,7 +1899,7 @@ impl PackedVq { Ok(BufferToken { send_buff: None, recv_buff: Some(buffer), - vq: master, + vq: self.clone(), ret_send: false, ret_recv: true, reusable: true, @@ -1962,7 +1929,7 @@ impl PackedVq { Ok(BufferToken { send_buff: None, recv_buff: Some(buffer), - vq: master, + vq: self.clone(), ret_send: false, ret_recv: true, reusable: true, @@ -1997,7 +1964,7 @@ impl PackedVq { Ok(BufferToken { send_buff: None, recv_buff: Some(buffer), - vq: master, + vq: self.clone(), ret_send: false, ret_recv: true, reusable: true, @@ -2032,7 +1999,7 @@ impl PackedVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -2070,7 +2037,7 @@ impl PackedVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -2115,7 +2082,7 @@ impl PackedVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -2153,7 +2120,7 @@ impl PackedVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -2211,7 +2178,7 @@ impl PackedVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -2226,7 +2193,7 @@ impl PackedVq { } } - pub fn size(&self) -> VqSize { + fn size(&self) -> VqSize { self.size } } @@ -2326,12 +2293,3 @@ impl PackedVq { } } } - -pub mod error { - pub enum VqPackedError { - General, - SizeNotAllowed(u16), - QueueNotExisting(u16), - FeatNotSupported(u64), - } -} diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index 010723f850..20d276a0bc 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -17,8 +17,8 @@ use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::{ - AsSliceU8, BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, - TransferState, TransferToken, Virtq, VqIndex, VqSize, + BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, TransferState, + TransferToken, Virtq, VqIndex, VqSize, }; use crate::arch::memory_barrier; use crate::arch::mm::paging::{BasePageSize, PageSize}; @@ -247,19 +247,19 @@ pub struct SplitVq { notif_ctrl: NotifCtrl, } -impl SplitVq { +impl Virtq for SplitVq { /// Enables interrupts for this virtqueue upon receiving a transfer - pub fn enable_notifs(&self) { + fn enable_notifs(&self) { self.ring.borrow_mut().drv_enable_notif(); } /// Disables interrupts for this virtqueue upon receiving a transfer - pub fn disable_notifs(&self) { + fn disable_notifs(&self) { self.ring.borrow_mut().drv_disable_notif(); } /// See `Virtq.poll()` documentation - pub fn poll(&self) { + fn poll(&self) { self.ring.borrow_mut().poll() } @@ -270,7 +270,7 @@ impl SplitVq { /// The `notif` parameter indicates if the driver wants to have a notification for this specific /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the /// updated notification flags before finishing transfers! - pub fn dispatch_batch(&self, _tkns: Vec, _notif: bool) { + fn dispatch_batch(&self, _tkns: Vec, _notif: bool) { unimplemented!(); } @@ -286,7 +286,7 @@ impl SplitVq { /// a device notification if wanted by the device. /// /// Tokens to get a reference to the provided await_queue, where they will be placed upon finish. - pub fn dispatch_batch_await( + fn dispatch_batch_await( &self, _tkns: Vec, _await_queue: Rc>>, @@ -300,7 +300,7 @@ impl SplitVq { /// The `notif` parameter indicates if the driver wants to have a notification for this specific /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the /// updated notification flags before finishing transfers! - pub fn dispatch(&self, tkn: TransferToken, notif: bool) { + fn dispatch(&self, tkn: TransferToken, notif: bool) { let (next_off, next_wrap) = self.ring.borrow_mut().push(tkn); if notif { @@ -331,22 +331,26 @@ impl SplitVq { } /// See `Virtq.index()` documentation - pub fn index(&self) -> VqIndex { + fn index(&self) -> VqIndex { self.index } - /// See `Virtq::new()` documentation - pub fn new( + /// Creates a new Virtq of the specified (VqSize)[VqSize] and the (VqIndex)[VqIndex]. + /// The index represents the "ID" of the virtqueue. + /// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct. + /// + /// Be aware, that devices define a maximum number of queues and a maximal size they can handle. + fn new( com_cfg: &mut ComCfg, notif_cfg: &NotifCfg, size: VqSize, index: VqIndex, _feats: u64, - ) -> Result { + ) -> Result { // Get a handler to the queues configuration area. let mut vq_handler = match com_cfg.select_vq(index.into()) { Some(handler) => handler, - None => return Err(()), + None => return Err(VirtqError::QueueNotExisting(index.into())), }; let size = vq_handler.set_vq_size(size.0); @@ -443,27 +447,24 @@ impl SplitVq { } /// See `Virtq.prep_transfer_from_raw()` documentation. - pub fn prep_transfer_from_raw( - &self, - master: Rc, - send: Option<(*mut T, BuffSpec<'_>)>, - recv: Option<(*mut K, BuffSpec<'_>)>, + fn prep_transfer_from_raw( + self: Rc, + send: Option<(&[u8], BuffSpec<'_>)>, + recv: Option<(&mut [u8], BuffSpec<'_>)>, ) -> Result { match (send, recv) { (None, None) => Err(VirtqError::BufferNotSpecified), (Some((send_data, send_spec)), None) => { match send_spec { BuffSpec::Single(size) => { - let data_slice = unsafe { (*send_data).as_slice_u8() }; - // Buffer must have the right size - if data_slice.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(data_slice.len())); + if send_data.len() != size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); } let desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), send_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -474,11 +475,11 @@ impl SplitVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Single { desc_lst: vec![desc].into_boxed_slice(), - len: data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: None, - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -487,15 +488,14 @@ impl SplitVq { }) } BuffSpec::Multiple(size_lst) => { - let data_slice = unsafe { (*send_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; match self @@ -515,11 +515,11 @@ impl SplitVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Multiple { desc_lst: desc_lst.into_boxed_slice(), - len: data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: None, - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -528,15 +528,14 @@ impl SplitVq { }) } BuffSpec::Indirect(size_lst) => { - let data_slice = unsafe { (*send_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; desc_lst.push( @@ -559,11 +558,11 @@ impl SplitVq { send_buff: Some(Buffer::Indirect { desc_lst: desc_lst.into_boxed_slice(), ctrl_desc, - len: data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: None, - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -576,16 +575,14 @@ impl SplitVq { (None, Some((recv_data, recv_spec))) => { match recv_spec { BuffSpec::Single(size) => { - let data_slice = unsafe { (*recv_data).as_slice_u8() }; - // Buffer must have the right size - if data_slice.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(data_slice.len())); + if recv_data.len() != size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); } let desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -597,10 +594,10 @@ impl SplitVq { send_buff: None, recv_buff: Some(Buffer::Single { desc_lst: vec![desc].into_boxed_slice(), - len: data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -609,15 +606,14 @@ impl SplitVq { }) } BuffSpec::Multiple(size_lst) => { - let data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; match self @@ -638,10 +634,10 @@ impl SplitVq { send_buff: None, recv_buff: Some(Buffer::Multiple { desc_lst: desc_lst.into_boxed_slice(), - len: data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -650,15 +646,14 @@ impl SplitVq { }) } BuffSpec::Indirect(size_lst) => { - let data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); let mut index = 0usize; for byte in size_lst { let end_index = index + usize::from(*byte); - let next_slice = match data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(data_slice.len())), + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; desc_lst.push( @@ -682,10 +677,10 @@ impl SplitVq { recv_buff: Some(Buffer::Indirect { desc_lst: desc_lst.into_boxed_slice(), ctrl_desc, - len: data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -698,31 +693,27 @@ impl SplitVq { (Some((send_data, send_spec)), Some((recv_data, recv_spec))) => { match (send_spec, recv_spec) { (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; - // Buffer must have the right size - if send_data_slice.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())); + if send_data.len() != send_size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); } let send_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), send_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), }; - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; - // Buffer must have the right size - if recv_data_slice.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())); + if recv_data.len() != recv_size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); } let recv_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -733,15 +724,15 @@ impl SplitVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Single { desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Single { desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -750,33 +741,28 @@ impl SplitVq { }) } (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; - // Buffer must have the right size - if send_data_slice.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())); + if send_data.len() != send_size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); } let send_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), send_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), }; - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut index = 0usize; for byte in recv_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match recv_data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; match self @@ -796,15 +782,15 @@ impl SplitVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Single { desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Multiple { desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -813,18 +799,15 @@ impl SplitVq { }) } (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; let mut send_desc_lst: Vec = Vec::with_capacity(send_size_lst.len()); let mut index = 0usize; for byte in send_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match send_data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; match self @@ -839,18 +822,15 @@ impl SplitVq { index += usize::from(*byte); } - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut index = 0usize; for byte in recv_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match recv_data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; match self @@ -870,15 +850,15 @@ impl SplitVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Multiple { desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Multiple { desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -887,18 +867,15 @@ impl SplitVq { }) } (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; let mut send_desc_lst: Vec = Vec::with_capacity(send_size_lst.len()); let mut index = 0usize; for byte in send_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match send_data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; match self @@ -913,16 +890,14 @@ impl SplitVq { index += usize::from(*byte); } - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; - // Buffer must have the right size - if recv_data_slice.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())); + if recv_data.len() != recv_size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); } let recv_desc = match self .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data_slice) + .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) { Ok(desc) => desc, Err(vq_err) => return Err(vq_err), @@ -933,15 +908,15 @@ impl SplitVq { buff_tkn: Some(BufferToken { send_buff: Some(Buffer::Multiple { desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), recv_buff: Some(Buffer::Single { desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -950,18 +925,15 @@ impl SplitVq { }) } (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let send_data_slice = unsafe { (*send_data).as_slice_u8() }; let mut send_desc_lst: Vec = Vec::with_capacity(send_size_lst.len()); let mut index = 0usize; for byte in send_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match send_data_slice.get(index..end_index) { + let next_slice = match send_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(send_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), }; send_desc_lst.push( @@ -973,18 +945,15 @@ impl SplitVq { index += usize::from(*byte); } - let recv_data_slice = unsafe { (*recv_data).as_slice_u8() }; let mut recv_desc_lst: Vec = Vec::with_capacity(recv_size_lst.len()); let mut index = 0usize; for byte in recv_size_lst { let end_index = index + usize::from(*byte); - let next_slice = match recv_data_slice.get(index..end_index) { + let next_slice = match recv_data.get(index..end_index) { Some(slice) => slice, - None => { - return Err(VirtqError::BufferSizeWrong(recv_data_slice.len())) - } + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), }; recv_desc_lst.push( @@ -1009,16 +978,16 @@ impl SplitVq { recv_buff: Some(Buffer::Indirect { desc_lst: recv_desc_lst.into_boxed_slice(), ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_data_slice.len(), + len: recv_data.len(), next_write: 0, }), send_buff: Some(Buffer::Indirect { desc_lst: send_desc_lst.into_boxed_slice(), ctrl_desc, - len: send_data_slice.len(), + len: send_data.len(), next_write: 0, }), - vq: master, + vq: self, ret_send: false, ret_recv: false, reusable: false, @@ -1036,9 +1005,8 @@ impl SplitVq { } /// See `Virtq.prep_buffer()` documentation. - pub fn prep_buffer( - &self, - master: Rc, + fn prep_buffer( + self: Rc, send: Option>, recv: Option>, ) -> Result { @@ -1060,7 +1028,7 @@ impl SplitVq { Ok(BufferToken { send_buff: Some(buffer), recv_buff: None, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: false, reusable: true, @@ -1090,7 +1058,7 @@ impl SplitVq { Ok(BufferToken { send_buff: Some(buffer), recv_buff: None, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: false, reusable: true, @@ -1125,7 +1093,7 @@ impl SplitVq { Ok(BufferToken { send_buff: Some(buffer), recv_buff: None, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: false, reusable: true, @@ -1148,7 +1116,7 @@ impl SplitVq { Ok(BufferToken { send_buff: None, recv_buff: Some(buffer), - vq: master, + vq: self.clone(), ret_send: false, ret_recv: true, reusable: true, @@ -1178,7 +1146,7 @@ impl SplitVq { Ok(BufferToken { send_buff: None, recv_buff: Some(buffer), - vq: master, + vq: self.clone(), ret_send: false, ret_recv: true, reusable: true, @@ -1213,7 +1181,7 @@ impl SplitVq { Ok(BufferToken { send_buff: None, recv_buff: Some(buffer), - vq: master, + vq: self.clone(), ret_send: false, ret_recv: true, reusable: true, @@ -1248,7 +1216,7 @@ impl SplitVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -1286,7 +1254,7 @@ impl SplitVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -1331,7 +1299,7 @@ impl SplitVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -1369,7 +1337,7 @@ impl SplitVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -1427,7 +1395,7 @@ impl SplitVq { Ok(BufferToken { send_buff, recv_buff, - vq: master, + vq: self.clone(), ret_send: true, ret_recv: true, reusable: true, @@ -1442,7 +1410,7 @@ impl SplitVq { } } - pub fn size(&self) -> VqSize { + fn size(&self) -> VqSize { self.size } } From 63d6dad6a9aef9bf682bc083f78718a327922811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Wed, 21 Feb 2024 15:10:10 +0100 Subject: [PATCH 2/4] virtq: remove large unused data attached to error The BufferToken attached to VirtqError::WriteTooLarge was not used and increased the error size from 16 bytes to 184 bytes. The enum was large also earlier (176 bytes), but the last commit made it exceed clippy's threshold. --- src/drivers/virtio/virtqueue/mod.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index d67eb2cfd2..8c5a1eaaf0 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -1454,7 +1454,7 @@ impl BufferToken { match self.send_buff.as_mut() { Some(buff) => { if buff.len() < data.as_slice_u8().len() { - return Err(VirtqError::WriteToLarge(self)); + return Err(VirtqError::WriteTooLarge); } else { let data_slc = data.as_slice_u8(); let mut from = 0usize; @@ -1483,7 +1483,7 @@ impl BufferToken { let data_slc = data.as_slice_u8(); if buff.len() < data_slc.len() { - return Err(VirtqError::WriteToLarge(self)); + return Err(VirtqError::WriteTooLarge); } else { let mut from = 0usize; @@ -1537,7 +1537,7 @@ impl BufferToken { Err(_) => { // Need no match here, as result is the same, but for the future one could // pass on the actual BufferError wrapped inside a VirtqError, for better recovery - return Err(VirtqError::WriteToLarge(self)); + return Err(VirtqError::WriteTooLarge); } } } @@ -1553,7 +1553,7 @@ impl BufferToken { Err(_) => { // Need no match here, as result is the same, but for the future one could // pass on the actual BufferError wrapped inside a VirtqError, for better recovery - return Err(VirtqError::WriteToLarge(self)); + return Err(VirtqError::WriteTooLarge); } } } @@ -2292,7 +2292,7 @@ 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 super::{BufferToken, Transfer}; + use super::Transfer; #[derive(Debug)] // Internal Error Handling for Buffers @@ -2344,7 +2344,7 @@ pub mod error { NoBufferAvail, /// Indicates that a write to a Buffer happened and the data to be written into /// the buffer/descriptor was to large for the buffer. - WriteToLarge(BufferToken), + WriteTooLarge, /// Indicates that a Bytes::new() call failed or generally that a buffer is to large to /// be transferred as one. The Maximum size is u32::MAX. This also is the maximum for indirect /// descriptors (both the one placed in the queue, as also the ones the indirect descriptor is @@ -2366,7 +2366,7 @@ pub mod error { VirtqError::BufferSizeWrong(_) => write!(f, "Specified Buffer is to small for write!"), VirtqError::NoReuseBuffer => write!(f, "Buffer can not be reused!"), VirtqError::OngoingTransfer(_) => write!(f, "Transfer is ongoging and can not be used currently!"), - VirtqError::WriteToLarge(_) => write!(f, "Write is to large for BufferToken!"), + VirtqError::WriteTooLarge => write!(f, "Write is to large for BufferToken!"), VirtqError::BufferToLarge => write!(f, "Buffer to large for queue! u32::MAX exceeded."), VirtqError::QueueSizeNotAllowed(_) => write!(f, "The requested queue size is not valid."), VirtqError:: FeatNotSupported(_) => write!(f, "An unsupported feature was requested from the queue."), From ecbedf162fc466c692690c6808185f591034cc24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Wed, 21 Feb 2024 15:44:55 +0100 Subject: [PATCH 3/4] virtqueue: improve documentation Move method docs to trait definition and remove references to methods that were removed. --- src/drivers/virtio/virtqueue/mod.rs | 27 +++++++++++++++++--- src/drivers/virtio/virtqueue/packed.rs | 35 -------------------------- src/drivers/virtio/virtqueue/split.rs | 35 -------------------------- 3 files changed, 23 insertions(+), 74 deletions(-) diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index 8c5a1eaaf0..f2e07b738c 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -131,8 +131,27 @@ pub trait Virtq { /// * All finished `TransferTokens` will have a state of `TransferState::Finished`. fn poll(&self); + /// Dispatches a batch of transfer token. The buffers of the respective transfers are provided to the queue in + /// sequence. After the last buffer has been written, the queue marks the first buffer as available and triggers + /// a device notification if wanted by the device. + /// + /// The `notif` parameter indicates if the driver wants to have a notification for this specific + /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the + /// updated notification flags before finishing transfers! fn dispatch_batch(&self, tkns: Vec, notif: bool); + /// Dispatches a batch of TransferTokens. The Transfers will be placed in to the `await_queue` + /// upon finish. + /// + /// The `notif` parameter indicates if the driver wants to have a notification for this specific + /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the + /// updated notification flags before finishing transfers! + /// + /// Dispatches a batch of transfer token. The buffers of the respective transfers are provided to the queue in + /// sequence. After the last buffer has been written, the queue marks the first buffer as available and triggers + /// a device notification if wanted by the device. + /// + /// Tokens to get a reference to the provided await_queue, where they will be placed upon finish. fn dispatch_batch_await( &self, tkns: Vec, @@ -140,7 +159,7 @@ pub trait Virtq { notif: bool, ); - /// Creates a new Virtq of the specified (VqSize)[VqSize] and the (VqIndex)[VqIndex]. + /// Creates a new Virtq of the specified [VqSize] and the [VqIndex]. /// The index represents the "ID" of the virtqueue. /// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct. /// @@ -422,8 +441,8 @@ pub fn dispatch_batch_await( } } -/// The trait needs to be implemented on structures which are to be used via the `prep_transfer()` function of virtqueues and for -/// structures which are to be used to write data into buffers of a [BufferToken] via `BufferToken.write()` or +/// The trait needs to be implemented for +/// structures which are to be used to write data into buffers of a [BufferToken] via [BufferToken::write] or /// `BufferToken.write_seq()`. /// /// **INFO:* @@ -638,7 +657,7 @@ impl Transfer { /// The returned data is of type `Box<[Box<[u8]>]>`. This function therefore preserves /// the scattered structure of the buffer, /// - /// If one create this buffer via a `Virtq.prep_transfer()` or `Virtq.prep_transfer_from_raw()` + /// If one creates this buffer via a `Virtq.prep_transfer_from_raw()` /// call, a casting back to the original structure `T` is NOT possible. /// In these cases please use `Transfer.ret_cpy()` or use 'BuffSpec::Single' only! pub fn ret_scat_cpy( diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index 2519b24473..8a0d1d9191 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -974,28 +974,18 @@ pub struct PackedVq { // This is currently unlikely, as the Tokens hold a Rc for refering to their origin // queue. This could be eased impl Virtq for PackedVq { - /// Enables interrupts for this virtqueue upon receiving a transfer fn enable_notifs(&self) { self.drv_event.borrow_mut().enable_notif(); } - /// Disables interrupts for this virtqueue upon receiving a transfer fn disable_notifs(&self) { self.drv_event.borrow_mut().disable_notif(); } - /// See `Virtq.poll()` documentation fn poll(&self) { self.descr_ring.borrow_mut().poll(); } - /// Dispatches a batch of transfer token. The buffers of the respective transfers are provided to the queue in - /// sequence. After the last buffer has been written, the queue marks the first buffer as available and triggers - /// a device notification if wanted by the device. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! fn dispatch_batch(&self, tkns: Vec, notif: bool) { // Zero transfers are not allowed assert!(!tkns.is_empty()); @@ -1029,18 +1019,6 @@ impl Virtq for PackedVq { } } - /// Dispatches a batch of TransferTokens. The Transfers will be placed in to the `await_queue` - /// upon finish. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! - /// - /// Dispatches a batch of transfer token. The buffers of the respective transfers are provided to the queue in - /// sequence. After the last buffer has been written, the queue marks the first buffer as available and triggers - /// a device notification if wanted by the device. - /// - /// Tokens to get a reference to the provided await_queue, where they will be placed upon finish. fn dispatch_batch_await( &self, mut tkns: Vec, @@ -1084,11 +1062,6 @@ impl Virtq for PackedVq { } } - /// See `Virtq.prep_transfer()` documentation. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! fn dispatch(&self, tkn: TransferToken, notif: bool) { let (next_off, next_wrap) = self.descr_ring.borrow_mut().push(tkn); @@ -1119,16 +1092,10 @@ impl Virtq for PackedVq { } } - /// See `Virtq.index()` documentation fn index(&self) -> VqIndex { self.index } - /// Creates a new Virtq of the specified (VqSize)[VqSize] and the (VqIndex)[VqIndex]. - /// The index represents the "ID" of the virtqueue. - /// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct. - /// - /// Be aware, that devices define a maximum number of queues and a maximal size they can handle. fn new( com_cfg: &mut ComCfg, notif_cfg: &NotifCfg, @@ -1229,7 +1196,6 @@ impl Virtq for PackedVq { }) } - /// See `Virtq.prep_transfer_from_raw()` documentation. fn prep_transfer_from_raw( self: Rc, send: Option<(&[u8], BuffSpec<'_>)>, @@ -1787,7 +1753,6 @@ impl Virtq for PackedVq { } } - /// See `Virtq.prep_buffer()` documentation. fn prep_buffer( self: Rc, send: Option>, diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index 20d276a0bc..17c23fd32a 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -248,44 +248,22 @@ pub struct SplitVq { } impl Virtq for SplitVq { - /// Enables interrupts for this virtqueue upon receiving a transfer fn enable_notifs(&self) { self.ring.borrow_mut().drv_enable_notif(); } - /// Disables interrupts for this virtqueue upon receiving a transfer fn disable_notifs(&self) { self.ring.borrow_mut().drv_disable_notif(); } - /// See `Virtq.poll()` documentation fn poll(&self) { self.ring.borrow_mut().poll() } - /// Dispatches a batch of transfer token. The buffers of the respective transfers are provided to the queue in - /// sequence. After the last buffer has been written, the queue marks the first buffer as available and triggers - /// a device notification if wanted by the device. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! fn dispatch_batch(&self, _tkns: Vec, _notif: bool) { unimplemented!(); } - /// Dispatches a batch of TransferTokens. The Transfers will be placed in to the `await_queue` - /// upon finish. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! - /// - /// Dispatches a batch of transfer token. The buffers of the respective transfers are provided to the queue in - /// sequence. After the last buffer has been written, the queue marks the first buffer as available and triggers - /// a device notification if wanted by the device. - /// - /// Tokens to get a reference to the provided await_queue, where they will be placed upon finish. fn dispatch_batch_await( &self, _tkns: Vec, @@ -295,11 +273,6 @@ impl Virtq for SplitVq { unimplemented!() } - /// See `Virtq.prep_transfer()` documentation. - /// - /// The `notif` parameter indicates if the driver wants to have a notification for this specific - /// transfer. This is only for performance optimization. As it is NOT ensured, that the device sees the - /// updated notification flags before finishing transfers! fn dispatch(&self, tkn: TransferToken, notif: bool) { let (next_off, next_wrap) = self.ring.borrow_mut().push(tkn); @@ -330,16 +303,10 @@ impl Virtq for SplitVq { } } - /// See `Virtq.index()` documentation fn index(&self) -> VqIndex { self.index } - /// Creates a new Virtq of the specified (VqSize)[VqSize] and the (VqIndex)[VqIndex]. - /// The index represents the "ID" of the virtqueue. - /// Upon creation the virtqueue is "registered" at the device via the `ComCfg` struct. - /// - /// Be aware, that devices define a maximum number of queues and a maximal size they can handle. fn new( com_cfg: &mut ComCfg, notif_cfg: &NotifCfg, @@ -446,7 +413,6 @@ impl Virtq for SplitVq { }) } - /// See `Virtq.prep_transfer_from_raw()` documentation. fn prep_transfer_from_raw( self: Rc, send: Option<(&[u8], BuffSpec<'_>)>, @@ -1004,7 +970,6 @@ impl Virtq for SplitVq { } } - /// See `Virtq.prep_buffer()` documentation. fn prep_buffer( self: Rc, send: Option>, From a0c1b5a1e125954956135a297a3202ee8995ee35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Wed, 21 Feb 2024 17:47:10 +0100 Subject: [PATCH 4/4] virtq: remove duplicate method implementations prep_buffer and prep_transfer_from_raw are implemented the exact same way for SplitVq and PackedVq. This commit merges them into default implementations inside the trait. --- src/drivers/virtio/virtqueue/mod.rs | 997 ++++++++++++++++++++++++- src/drivers/virtio/virtqueue/packed.rs | 959 +----------------------- src/drivers/virtio/virtqueue/split.rs | 960 +----------------------- 3 files changed, 1012 insertions(+), 1904 deletions(-) diff --git a/src/drivers/virtio/virtqueue/mod.rs b/src/drivers/virtio/virtqueue/mod.rs index f2e07b738c..7059ea3cb1 100644 --- a/src/drivers/virtio/virtqueue/mod.rs +++ b/src/drivers/virtio/virtqueue/mod.rs @@ -108,7 +108,8 @@ struct Descriptor { /// might not provide the complete feature set of each queue. Drivers who /// do need these features should refrain from providing support for both /// Virtqueue types and use the structs directly instead. -pub trait Virtq { +#[allow(private_bounds)] +pub trait Virtq: VirtqPrivate { /// Entry function which the TransferTokens can use, when they are dispatching /// themselves via their `Rc` reference /// @@ -249,6 +250,577 @@ pub trait Virtq { recv: Option<(&mut [u8], BuffSpec<'_>)>, ) -> Result; + /// The implementation of the method requires constraints that are incompatible with a trait object. + /// Because of this, we constrain it to static objects (via Sized) and call it from the implementation + /// of [Self::prep_buffer] inside the implementor. + fn prep_transfer_from_raw_static( + self: Rc, + send: Option<(&[u8], BuffSpec<'_>)>, + recv: Option<(&mut [u8], BuffSpec<'_>)>, + ) -> Result + where + Self: Sized + 'static, + { + match (send, recv) { + (None, None) => Err(VirtqError::BufferNotSpecified), + (Some((send_data, send_spec)), None) => { + match send_spec { + BuffSpec::Single(size) => { + // Buffer must have the right size + if send_data.len() != size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); + } + + let desc = match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), send_data) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Single { + desc_lst: vec![desc].into_boxed_slice(), + len: send_data.len(), + next_write: 0, + }), + recv_buff: None, + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + BuffSpec::Multiple(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut index = 0usize; + + for byte in size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match send_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), + }; + + match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) + { + Ok(desc) => desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + }; + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Multiple { + desc_lst: desc_lst.into_boxed_slice(), + len: send_data.len(), + next_write: 0, + }), + recv_buff: None, + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + BuffSpec::Indirect(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut index = 0usize; + + for byte in size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match send_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), + }; + + desc_lst.push( + self.mem_pool().pull_from_raw_untracked( + Rc::clone(&self.mem_pool()), + next_slice, + ), + ); + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Indirect { + desc_lst: desc_lst.into_boxed_slice(), + ctrl_desc, + len: send_data.len(), + next_write: 0, + }), + recv_buff: None, + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + } + } + (None, Some((recv_data, recv_spec))) => { + match recv_spec { + BuffSpec::Single(size) => { + // Buffer must have the right size + if recv_data.len() != size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); + } + + let desc = match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), recv_data) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: None, + recv_buff: Some(Buffer::Single { + desc_lst: vec![desc].into_boxed_slice(), + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + BuffSpec::Multiple(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut index = 0usize; + + for byte in size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match recv_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), + }; + + match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) + { + Ok(desc) => desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + }; + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: None, + recv_buff: Some(Buffer::Multiple { + desc_lst: desc_lst.into_boxed_slice(), + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + BuffSpec::Indirect(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut index = 0usize; + + for byte in size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match recv_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), + }; + + desc_lst.push( + self.mem_pool().pull_from_raw_untracked( + Rc::clone(&self.mem_pool()), + next_slice, + ), + ); + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: None, + recv_buff: Some(Buffer::Indirect { + desc_lst: desc_lst.into_boxed_slice(), + ctrl_desc, + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + } + } + (Some((send_data, send_spec)), Some((recv_data, recv_spec))) => { + match (send_spec, recv_spec) { + (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { + // Buffer must have the right size + if send_data.len() != send_size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); + } + + let send_desc = match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), send_data) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + // Buffer must have the right size + if recv_data.len() != recv_size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); + } + + let recv_desc = match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), recv_data) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Single { + desc_lst: vec![send_desc].into_boxed_slice(), + len: send_data.len(), + next_write: 0, + }), + recv_buff: Some(Buffer::Single { + desc_lst: vec![recv_desc].into_boxed_slice(), + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { + // Buffer must have the right size + if send_data.len() != send_size.into() { + return Err(VirtqError::BufferSizeWrong(send_data.len())); + } + + let send_desc = match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), send_data) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + let mut recv_desc_lst: Vec = + Vec::with_capacity(recv_size_lst.len()); + let mut index = 0usize; + + for byte in recv_size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match recv_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), + }; + + match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) + { + Ok(desc) => recv_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + }; + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Single { + desc_lst: vec![send_desc].into_boxed_slice(), + len: send_data.len(), + next_write: 0, + }), + recv_buff: Some(Buffer::Multiple { + desc_lst: recv_desc_lst.into_boxed_slice(), + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { + let mut send_desc_lst: Vec = + Vec::with_capacity(send_size_lst.len()); + let mut index = 0usize; + + for byte in send_size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match send_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), + }; + + match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) + { + Ok(desc) => send_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + }; + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + let mut recv_desc_lst: Vec = + Vec::with_capacity(recv_size_lst.len()); + let mut index = 0usize; + + for byte in recv_size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match recv_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), + }; + + match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) + { + Ok(desc) => recv_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + }; + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Multiple { + desc_lst: send_desc_lst.into_boxed_slice(), + len: send_data.len(), + next_write: 0, + }), + recv_buff: Some(Buffer::Multiple { + desc_lst: recv_desc_lst.into_boxed_slice(), + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { + let mut send_desc_lst: Vec = + Vec::with_capacity(send_size_lst.len()); + let mut index = 0usize; + + for byte in send_size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match send_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), + }; + + match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), next_slice) + { + Ok(desc) => send_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + }; + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + // Buffer must have the right size + if recv_data.len() != recv_size.into() { + return Err(VirtqError::BufferSizeWrong(recv_data.len())); + } + + let recv_desc = match self + .mem_pool() + .pull_from_raw(Rc::clone(&self.mem_pool()), recv_data) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + send_buff: Some(Buffer::Multiple { + desc_lst: send_desc_lst.into_boxed_slice(), + len: send_data.len(), + next_write: 0, + }), + recv_buff: Some(Buffer::Single { + desc_lst: vec![recv_desc].into_boxed_slice(), + len: recv_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { + let mut send_desc_lst: Vec = + Vec::with_capacity(send_size_lst.len()); + let mut index = 0usize; + + for byte in send_size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match send_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(send_data.len())), + }; + + send_desc_lst.push( + self.mem_pool().pull_from_raw_untracked( + Rc::clone(&self.mem_pool()), + next_slice, + ), + ); + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + let mut recv_desc_lst: Vec = + Vec::with_capacity(recv_size_lst.len()); + let mut index = 0usize; + + for byte in recv_size_lst { + let end_index = index + usize::from(*byte); + let next_slice = match recv_data.get(index..end_index) { + Some(slice) => slice, + None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), + }; + + recv_desc_lst.push( + self.mem_pool().pull_from_raw_untracked( + Rc::clone(&self.mem_pool()), + next_slice, + ), + ); + + // update the starting index for the next iteration + index += usize::from(*byte); + } + + let ctrl_desc = match self + .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + Ok(TransferToken { + state: TransferState::Ready, + buff_tkn: Some(BufferToken { + recv_buff: Some(Buffer::Indirect { + desc_lst: recv_desc_lst.into_boxed_slice(), + ctrl_desc: ctrl_desc.no_dealloc_clone(), + len: recv_data.len(), + next_write: 0, + }), + send_buff: Some(Buffer::Indirect { + desc_lst: send_desc_lst.into_boxed_slice(), + ctrl_desc, + len: send_data.len(), + next_write: 0, + }), + vq: self, + ret_send: false, + ret_recv: false, + reusable: false, + }), + await_queue: None, + }) + } + (BuffSpec::Indirect(_), BuffSpec::Single(_)) + | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), + (BuffSpec::Single(_), BuffSpec::Indirect(_)) + | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), + } + } + } + } + /// Provides the calley with empty buffers as specified via the `send` and `recv` function parameters, (see [BuffSpec]), in form of /// a [BufferToken]. /// Fails upon multiple circumstances. @@ -295,6 +867,429 @@ pub trait Virtq { send: Option>, recv: Option>, ) -> Result; + + /// The implementation of the method requires constraints that are incompatible with a trait object. + /// Because of this, we constrain it to static objects (via Sized) and call it from the implementation + /// of [Self::prep_buffer] inside the implementor. + fn prep_buffer_static( + self: Rc, + send: Option>, + recv: Option>, + ) -> Result + where + Self: Sized + 'static, + { + match (send, recv) { + // No buffers specified + (None, None) => Err(VirtqError::BufferNotSpecified), + // Send buffer specified, No recv buffer + (Some(spec), None) => { + match spec { + BuffSpec::Single(size) => { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), size) { + Ok(desc) => { + let buffer = Buffer::Single { + desc_lst: vec![desc].into_boxed_slice(), + len: size.into(), + next_write: 0, + }; + + Ok(BufferToken { + send_buff: Some(buffer), + recv_buff: None, + vq: self.clone(), + ret_send: true, + ret_recv: false, + reusable: true, + }) + } + Err(vq_err) => Err(vq_err), + } + } + BuffSpec::Multiple(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut len = 0usize; + + for size in size_lst { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + Ok(desc) => desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + } + len += usize::from(*size); + } + + let buffer = Buffer::Multiple { + desc_lst: desc_lst.into_boxed_slice(), + len, + next_write: 0, + }; + + Ok(BufferToken { + send_buff: Some(buffer), + recv_buff: None, + vq: self.clone(), + ret_send: true, + ret_recv: false, + reusable: true, + }) + } + BuffSpec::Indirect(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut len = 0usize; + + for size in size_lst { + // As the indirect list does only consume one descriptor for the + // control descriptor, the actual list is untracked + desc_lst.push( + self.mem_pool() + .pull_untracked(Rc::clone(&self.mem_pool()), *size), + ); + len += usize::from(*size); + } + + let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + let buffer = Buffer::Indirect { + desc_lst: desc_lst.into_boxed_slice(), + ctrl_desc, + len, + next_write: 0, + }; + + Ok(BufferToken { + send_buff: Some(buffer), + recv_buff: None, + vq: self.clone(), + ret_send: true, + ret_recv: false, + reusable: true, + }) + } + } + } + // No send buffer, recv buffer is specified + (None, Some(spec)) => { + match spec { + BuffSpec::Single(size) => { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), size) { + Ok(desc) => { + let buffer = Buffer::Single { + desc_lst: vec![desc].into_boxed_slice(), + len: size.into(), + next_write: 0, + }; + + Ok(BufferToken { + send_buff: None, + recv_buff: Some(buffer), + vq: self.clone(), + ret_send: false, + ret_recv: true, + reusable: true, + }) + } + Err(vq_err) => Err(vq_err), + } + } + BuffSpec::Multiple(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut len = 0usize; + + for size in size_lst { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + Ok(desc) => desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + } + len += usize::from(*size); + } + + let buffer = Buffer::Multiple { + desc_lst: desc_lst.into_boxed_slice(), + len, + next_write: 0, + }; + + Ok(BufferToken { + send_buff: None, + recv_buff: Some(buffer), + vq: self.clone(), + ret_send: false, + ret_recv: true, + reusable: true, + }) + } + BuffSpec::Indirect(size_lst) => { + let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); + let mut len = 0usize; + + for size in size_lst { + // As the indirect list does only consume one descriptor for the + // control descriptor, the actual list is untracked + desc_lst.push( + self.mem_pool() + .pull_untracked(Rc::clone(&self.mem_pool()), *size), + ); + len += usize::from(*size); + } + + let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + let buffer = Buffer::Indirect { + desc_lst: desc_lst.into_boxed_slice(), + ctrl_desc, + len, + next_write: 0, + }; + + Ok(BufferToken { + send_buff: None, + recv_buff: Some(buffer), + vq: self.clone(), + ret_send: false, + ret_recv: true, + reusable: true, + }) + } + } + } + // Send buffer specified, recv buffer specified + (Some(send_spec), Some(recv_spec)) => { + match (send_spec, recv_spec) { + (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { + let send_buff = + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), send_size) { + Ok(send_desc) => Some(Buffer::Single { + desc_lst: vec![send_desc].into_boxed_slice(), + len: send_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; + + let recv_buff = + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), recv_size) { + Ok(recv_desc) => Some(Buffer::Single { + desc_lst: vec![recv_desc].into_boxed_slice(), + len: recv_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; + + Ok(BufferToken { + send_buff, + recv_buff, + vq: self.clone(), + ret_send: true, + ret_recv: true, + reusable: true, + }) + } + (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { + let send_buff = + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), send_size) { + Ok(send_desc) => Some(Buffer::Single { + desc_lst: vec![send_desc].into_boxed_slice(), + len: send_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; + + let mut recv_desc_lst: Vec = + Vec::with_capacity(recv_size_lst.len()); + let mut recv_len = 0usize; + + for size in recv_size_lst { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + Ok(desc) => recv_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + } + recv_len += usize::from(*size); + } + + let recv_buff = Some(Buffer::Multiple { + desc_lst: recv_desc_lst.into_boxed_slice(), + len: recv_len, + next_write: 0, + }); + + Ok(BufferToken { + send_buff, + recv_buff, + vq: self.clone(), + ret_send: true, + ret_recv: true, + reusable: true, + }) + } + (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { + let mut send_desc_lst: Vec = + Vec::with_capacity(send_size_lst.len()); + let mut send_len = 0usize; + for size in send_size_lst { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + Ok(desc) => send_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + } + send_len += usize::from(*size); + } + + let send_buff = Some(Buffer::Multiple { + desc_lst: send_desc_lst.into_boxed_slice(), + len: send_len, + next_write: 0, + }); + + let mut recv_desc_lst: Vec = + Vec::with_capacity(recv_size_lst.len()); + let mut recv_len = 0usize; + + for size in recv_size_lst { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + Ok(desc) => recv_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + } + recv_len += usize::from(*size); + } + + let recv_buff = Some(Buffer::Multiple { + desc_lst: recv_desc_lst.into_boxed_slice(), + len: recv_len, + next_write: 0, + }); + + Ok(BufferToken { + send_buff, + recv_buff, + vq: self.clone(), + ret_send: true, + ret_recv: true, + reusable: true, + }) + } + (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { + let mut send_desc_lst: Vec = + Vec::with_capacity(send_size_lst.len()); + let mut send_len = 0usize; + + for size in send_size_lst { + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), *size) { + Ok(desc) => send_desc_lst.push(desc), + Err(vq_err) => return Err(vq_err), + } + send_len += usize::from(*size); + } + + let send_buff = Some(Buffer::Multiple { + desc_lst: send_desc_lst.into_boxed_slice(), + len: send_len, + next_write: 0, + }); + + let recv_buff = + match self.mem_pool().pull(Rc::clone(&self.mem_pool()), recv_size) { + Ok(recv_desc) => Some(Buffer::Single { + desc_lst: vec![recv_desc].into_boxed_slice(), + len: recv_size.into(), + next_write: 0, + }), + Err(vq_err) => return Err(vq_err), + }; + + Ok(BufferToken { + send_buff, + recv_buff, + vq: self.clone(), + ret_send: true, + ret_recv: true, + reusable: true, + }) + } + (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { + let mut send_desc_lst: Vec = + Vec::with_capacity(send_size_lst.len()); + let mut send_len = 0usize; + + for size in send_size_lst { + // As the indirect list does only consume one descriptor for the + // control descriptor, the actual list is untracked + send_desc_lst.push( + self.mem_pool() + .pull_untracked(Rc::clone(&self.mem_pool()), *size), + ); + send_len += usize::from(*size); + } + + let mut recv_desc_lst: Vec = + Vec::with_capacity(recv_size_lst.len()); + let mut recv_len = 0usize; + + for size in recv_size_lst { + // As the indirect list does only consume one descriptor for the + // control descriptor, the actual list is untracked + recv_desc_lst.push( + self.mem_pool() + .pull_untracked(Rc::clone(&self.mem_pool()), *size), + ); + recv_len += usize::from(*size); + } + + let ctrl_desc = match self + .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) + { + Ok(desc) => desc, + Err(vq_err) => return Err(vq_err), + }; + + let recv_buff = Some(Buffer::Indirect { + desc_lst: recv_desc_lst.into_boxed_slice(), + ctrl_desc: ctrl_desc.no_dealloc_clone(), + len: recv_len, + next_write: 0, + }); + let send_buff = Some(Buffer::Indirect { + desc_lst: send_desc_lst.into_boxed_slice(), + ctrl_desc, + len: send_len, + next_write: 0, + }); + + Ok(BufferToken { + send_buff, + recv_buff, + vq: self.clone(), + ret_send: true, + ret_recv: true, + reusable: true, + }) + } + (BuffSpec::Indirect(_), BuffSpec::Single(_)) + | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), + (BuffSpec::Single(_), BuffSpec::Indirect(_)) + | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), + } + } + } + } +} + +/// These methods are an implementation detail and are meant only for consumption by the default method +/// implementations in [Virtq]. +trait VirtqPrivate { + fn create_indirect_ctrl( + &self, + send: Option<&Vec>, + recv: Option<&Vec>, + ) -> Result; + + fn mem_pool(&self) -> Rc; } /// Allows to check, if a given structure crosses a physical page boundary. diff --git a/src/drivers/virtio/virtqueue/packed.rs b/src/drivers/virtio/virtqueue/packed.rs index 8a0d1d9191..e93944a7b1 100644 --- a/src/drivers/virtio/virtqueue/packed.rs +++ b/src/drivers/virtio/virtqueue/packed.rs @@ -20,7 +20,7 @@ use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::{ BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, TransferState, - TransferToken, Virtq, VqIndex, VqSize, + TransferToken, Virtq, VirtqPrivate, VqIndex, VqSize, }; use crate::arch::mm::paging::{BasePageSize, PageSize}; use crate::arch::mm::{paging, VirtAddr}; @@ -1201,556 +1201,7 @@ impl Virtq for PackedVq { send: Option<(&[u8], BuffSpec<'_>)>, recv: Option<(&mut [u8], BuffSpec<'_>)>, ) -> Result { - match (send, recv) { - (None, None) => Err(VirtqError::BufferNotSpecified), - (Some((send_data, send_spec)), None) => { - match send_spec { - BuffSpec::Single(size) => { - // Buffer must have the right size - if send_data.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - } - } - (None, Some((recv_data, recv_spec))) => { - match recv_spec { - BuffSpec::Single(size) => { - // Buffer must have the right size - if recv_data.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - } - } - (Some((send_data, send_spec)), Some((recv_data, recv_spec))) => { - match (send_spec, recv_spec) { - (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - // Buffer must have the right size - if send_data.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let send_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - // Buffer must have the right size - if recv_data.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let recv_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - // Buffer must have the right size - if send_data.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let send_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - // Buffer must have the right size - if recv_data.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let recv_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - send_desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - recv_desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self - .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - recv_buff: Some(Buffer::Indirect { - desc_lst: recv_desc_lst.into_boxed_slice(), - ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_data.len(), - next_write: 0, - }), - send_buff: Some(Buffer::Indirect { - desc_lst: send_desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Indirect(_), BuffSpec::Single(_)) - | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), - (BuffSpec::Single(_), BuffSpec::Indirect(_)) - | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), - } - } - } + self.prep_transfer_from_raw_static(send, recv) } fn prep_buffer( @@ -1758,404 +1209,7 @@ impl Virtq for PackedVq { send: Option>, recv: Option>, ) -> Result { - match (send, recv) { - // No buffers specified - (None, None) => Err(VirtqError::BufferNotSpecified), - // Send buffer specified, No recv buffer - (Some(spec), None) => { - match spec { - BuffSpec::Single(size) => { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), size) { - Ok(desc) => { - let buffer = Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: size.into(), - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - Err(vq_err) => Err(vq_err), - } - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - len += usize::from(*size); - } - - let buffer = Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - len += usize::from(*size); - } - - let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let buffer = Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - } - } - // No send buffer, recv buffer is specified - (None, Some(spec)) => { - match spec { - BuffSpec::Single(size) => { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), size) { - Ok(desc) => { - let buffer = Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: size.into(), - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - Err(vq_err) => Err(vq_err), - } - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - len += usize::from(*size); - } - - let buffer = Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - len += usize::from(*size); - } - - let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let buffer = Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - } - } - // Send buffer specified, recv buffer specified - (Some(send_spec), Some(recv_spec)) => { - match (send_spec, recv_spec) { - (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - let send_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), send_size) { - Ok(send_desc) => Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - let recv_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), recv_size) { - Ok(recv_desc) => Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - let send_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), send_size) { - Ok(send_desc) => Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut recv_len = 0usize; - - for size in recv_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - recv_len += usize::from(*size); - } - - let recv_buff = Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_len, - next_write: 0, - }); - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut send_len = 0usize; - for size in send_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - send_len += usize::from(*size); - } - - let send_buff = Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_len, - next_write: 0, - }); - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut recv_len = 0usize; - - for size in recv_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - recv_len += usize::from(*size); - } - - let recv_buff = Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_len, - next_write: 0, - }); - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut send_len = 0usize; - - for size in send_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - send_len += usize::from(*size); - } - - let send_buff = Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_len, - next_write: 0, - }); - - let recv_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), recv_size) { - Ok(recv_desc) => Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut send_len = 0usize; - - for size in send_size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - send_desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - send_len += usize::from(*size); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut recv_len = 0usize; - - for size in recv_size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - recv_desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - recv_len += usize::from(*size); - } - - let ctrl_desc = match self - .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let recv_buff = Some(Buffer::Indirect { - desc_lst: recv_desc_lst.into_boxed_slice(), - ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_len, - next_write: 0, - }); - let send_buff = Some(Buffer::Indirect { - desc_lst: send_desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_len, - next_write: 0, - }); - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Indirect(_), BuffSpec::Single(_)) - | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), - (BuffSpec::Single(_), BuffSpec::Indirect(_)) - | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), - } - } - } + self.prep_buffer_static(send, recv) } fn size(&self) -> VqSize { @@ -2163,8 +1217,11 @@ impl Virtq for PackedVq { } } -// Private Interface for PackedVq -impl PackedVq { +impl VirtqPrivate for PackedVq { + fn mem_pool(&self) -> Rc { + self.mem_pool.clone() + } + fn create_indirect_ctrl( &self, send: Option<&Vec>, diff --git a/src/drivers/virtio/virtqueue/split.rs b/src/drivers/virtio/virtqueue/split.rs index 17c23fd32a..3906f3d83b 100644 --- a/src/drivers/virtio/virtqueue/split.rs +++ b/src/drivers/virtio/virtqueue/split.rs @@ -17,8 +17,8 @@ use super::super::transport::mmio::{ComCfg, NotifCfg, NotifCtrl}; use super::super::transport::pci::{ComCfg, NotifCfg, NotifCtrl}; use super::error::VirtqError; use super::{ - BuffSpec, Buffer, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, TransferState, - TransferToken, Virtq, VqIndex, VqSize, + BuffSpec, BufferToken, Bytes, DescrFlags, MemDescr, MemPool, Transfer, TransferState, + TransferToken, Virtq, VirtqPrivate, VqIndex, VqSize, }; use crate::arch::memory_barrier; use crate::arch::mm::paging::{BasePageSize, PageSize}; @@ -418,556 +418,7 @@ impl Virtq for SplitVq { send: Option<(&[u8], BuffSpec<'_>)>, recv: Option<(&mut [u8], BuffSpec<'_>)>, ) -> Result { - match (send, recv) { - (None, None) => Err(VirtqError::BufferNotSpecified), - (Some((send_data, send_spec)), None) => { - match send_spec { - BuffSpec::Single(size) => { - // Buffer must have the right size - if send_data.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_data.len(), - next_write: 0, - }), - recv_buff: None, - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - } - } - (None, Some((recv_data, recv_spec))) => { - match recv_spec { - BuffSpec::Single(size) => { - // Buffer must have the right size - if recv_data.len() != size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut index = 0usize; - - for byte in size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: None, - recv_buff: Some(Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - } - } - (Some((send_data, send_spec)), Some((recv_data, recv_spec))) => { - match (send_spec, recv_spec) { - (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - // Buffer must have the right size - if send_data.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let send_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - // Buffer must have the right size - if recv_data.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let recv_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - // Buffer must have the right size - if send_data.len() != send_size.into() { - return Err(VirtqError::BufferSizeWrong(send_data.len())); - } - - let send_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), send_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), next_slice) - { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - }; - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - // Buffer must have the right size - if recv_data.len() != recv_size.into() { - return Err(VirtqError::BufferSizeWrong(recv_data.len())); - } - - let recv_desc = match self - .mem_pool - .pull_from_raw(Rc::clone(&self.mem_pool), recv_data) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - send_buff: Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_data.len(), - next_write: 0, - }), - recv_buff: Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut index = 0usize; - - for byte in send_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match send_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(send_data.len())), - }; - - send_desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut index = 0usize; - - for byte in recv_size_lst { - let end_index = index + usize::from(*byte); - let next_slice = match recv_data.get(index..end_index) { - Some(slice) => slice, - None => return Err(VirtqError::BufferSizeWrong(recv_data.len())), - }; - - recv_desc_lst.push( - self.mem_pool - .pull_from_raw_untracked(Rc::clone(&self.mem_pool), next_slice), - ); - - // update the starting index for the next iteration - index += usize::from(*byte); - } - - let ctrl_desc = match self - .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - Ok(TransferToken { - state: TransferState::Ready, - buff_tkn: Some(BufferToken { - recv_buff: Some(Buffer::Indirect { - desc_lst: recv_desc_lst.into_boxed_slice(), - ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_data.len(), - next_write: 0, - }), - send_buff: Some(Buffer::Indirect { - desc_lst: send_desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_data.len(), - next_write: 0, - }), - vq: self, - ret_send: false, - ret_recv: false, - reusable: false, - }), - await_queue: None, - }) - } - (BuffSpec::Indirect(_), BuffSpec::Single(_)) - | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), - (BuffSpec::Single(_), BuffSpec::Indirect(_)) - | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), - } - } - } + self.prep_transfer_from_raw_static(send, recv) } fn prep_buffer( @@ -975,404 +426,7 @@ impl Virtq for SplitVq { send: Option>, recv: Option>, ) -> Result { - match (send, recv) { - // No buffers specified - (None, None) => Err(VirtqError::BufferNotSpecified), - // Send buffer specified, No recv buffer - (Some(spec), None) => { - match spec { - BuffSpec::Single(size) => { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), size) { - Ok(desc) => { - let buffer = Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: size.into(), - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - Err(vq_err) => Err(vq_err), - } - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - len += usize::from(*size); - } - - let buffer = Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - len += usize::from(*size); - } - - let ctrl_desc = match self.create_indirect_ctrl(Some(&desc_lst), None) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let buffer = Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: Some(buffer), - recv_buff: None, - vq: self.clone(), - ret_send: true, - ret_recv: false, - reusable: true, - }) - } - } - } - // No send buffer, recv buffer is specified - (None, Some(spec)) => { - match spec { - BuffSpec::Single(size) => { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), size) { - Ok(desc) => { - let buffer = Buffer::Single { - desc_lst: vec![desc].into_boxed_slice(), - len: size.into(), - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - Err(vq_err) => Err(vq_err), - } - } - BuffSpec::Multiple(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - len += usize::from(*size); - } - - let buffer = Buffer::Multiple { - desc_lst: desc_lst.into_boxed_slice(), - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - BuffSpec::Indirect(size_lst) => { - let mut desc_lst: Vec = Vec::with_capacity(size_lst.len()); - let mut len = 0usize; - - for size in size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - len += usize::from(*size); - } - - let ctrl_desc = match self.create_indirect_ctrl(None, Some(&desc_lst)) { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let buffer = Buffer::Indirect { - desc_lst: desc_lst.into_boxed_slice(), - ctrl_desc, - len, - next_write: 0, - }; - - Ok(BufferToken { - send_buff: None, - recv_buff: Some(buffer), - vq: self.clone(), - ret_send: false, - ret_recv: true, - reusable: true, - }) - } - } - } - // Send buffer specified, recv buffer specified - (Some(send_spec), Some(recv_spec)) => { - match (send_spec, recv_spec) { - (BuffSpec::Single(send_size), BuffSpec::Single(recv_size)) => { - let send_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), send_size) { - Ok(send_desc) => Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - let recv_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), recv_size) { - Ok(recv_desc) => Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Single(send_size), BuffSpec::Multiple(recv_size_lst)) => { - let send_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), send_size) { - Ok(send_desc) => Some(Buffer::Single { - desc_lst: vec![send_desc].into_boxed_slice(), - len: send_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut recv_len = 0usize; - - for size in recv_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - recv_len += usize::from(*size); - } - - let recv_buff = Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_len, - next_write: 0, - }); - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Multiple(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut send_len = 0usize; - for size in send_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - send_len += usize::from(*size); - } - - let send_buff = Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_len, - next_write: 0, - }); - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut recv_len = 0usize; - - for size in recv_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => recv_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - recv_len += usize::from(*size); - } - - let recv_buff = Some(Buffer::Multiple { - desc_lst: recv_desc_lst.into_boxed_slice(), - len: recv_len, - next_write: 0, - }); - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Multiple(send_size_lst), BuffSpec::Single(recv_size)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut send_len = 0usize; - - for size in send_size_lst { - match self.mem_pool.pull(Rc::clone(&self.mem_pool), *size) { - Ok(desc) => send_desc_lst.push(desc), - Err(vq_err) => return Err(vq_err), - } - send_len += usize::from(*size); - } - - let send_buff = Some(Buffer::Multiple { - desc_lst: send_desc_lst.into_boxed_slice(), - len: send_len, - next_write: 0, - }); - - let recv_buff = - match self.mem_pool.pull(Rc::clone(&self.mem_pool), recv_size) { - Ok(recv_desc) => Some(Buffer::Single { - desc_lst: vec![recv_desc].into_boxed_slice(), - len: recv_size.into(), - next_write: 0, - }), - Err(vq_err) => return Err(vq_err), - }; - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Indirect(send_size_lst), BuffSpec::Indirect(recv_size_lst)) => { - let mut send_desc_lst: Vec = - Vec::with_capacity(send_size_lst.len()); - let mut send_len = 0usize; - - for size in send_size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - send_desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - send_len += usize::from(*size); - } - - let mut recv_desc_lst: Vec = - Vec::with_capacity(recv_size_lst.len()); - let mut recv_len = 0usize; - - for size in recv_size_lst { - // As the indirect list does only consume one descriptor for the - // control descriptor, the actual list is untracked - recv_desc_lst.push( - self.mem_pool - .pull_untracked(Rc::clone(&self.mem_pool), *size), - ); - recv_len += usize::from(*size); - } - - let ctrl_desc = match self - .create_indirect_ctrl(Some(&send_desc_lst), Some(&recv_desc_lst)) - { - Ok(desc) => desc, - Err(vq_err) => return Err(vq_err), - }; - - let recv_buff = Some(Buffer::Indirect { - desc_lst: recv_desc_lst.into_boxed_slice(), - ctrl_desc: ctrl_desc.no_dealloc_clone(), - len: recv_len, - next_write: 0, - }); - let send_buff = Some(Buffer::Indirect { - desc_lst: send_desc_lst.into_boxed_slice(), - ctrl_desc, - len: send_len, - next_write: 0, - }); - - Ok(BufferToken { - send_buff, - recv_buff, - vq: self.clone(), - ret_send: true, - ret_recv: true, - reusable: true, - }) - } - (BuffSpec::Indirect(_), BuffSpec::Single(_)) - | (BuffSpec::Indirect(_), BuffSpec::Multiple(_)) => Err(VirtqError::BufferInWithDirect), - (BuffSpec::Single(_), BuffSpec::Indirect(_)) - | (BuffSpec::Multiple(_), BuffSpec::Indirect(_)) => Err(VirtqError::BufferInWithDirect), - } - } - } + self.prep_buffer_static(send, recv) } fn size(&self) -> VqSize { @@ -1380,8 +434,7 @@ impl Virtq for SplitVq { } } -// Private Interface for PackedVq -impl SplitVq { +impl VirtqPrivate for SplitVq { fn create_indirect_ctrl( &self, send: Option<&Vec>, @@ -1515,4 +568,7 @@ impl SplitVq { } } } + fn mem_pool(&self) -> Rc { + self.mem_pool.clone() + } }