diff --git a/fuzz/common/src/blk.rs b/fuzz/common/src/blk.rs index 3a4f5fad..c3e49e32 100644 --- a/fuzz/common/src/blk.rs +++ b/fuzz/common/src/blk.rs @@ -19,7 +19,7 @@ pub mod tests { use virtio_bindings::bindings::virtio_blk::VIRTIO_BLK_T_IN; use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; use virtio_blk::request::{Request, RequestType}; - use virtio_queue::{mock::MockSplitQueue, Descriptor}; + use virtio_queue::{desc::RawDescriptor, mock::MockSplitQueue}; use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemoryMmap}; // The same as the RequestHeader type in virtio_blk, with exposed fields @@ -91,7 +91,7 @@ pub mod tests { }, ]; - let q_descriptors: Vec = + let q_descriptors: Vec = descriptors.into_iter().map(|desc| desc.into()).collect(); let mut chain = vq.build_multiple_desc_chains(&q_descriptors).unwrap(); diff --git a/fuzz/common/src/lib.rs b/fuzz/common/src/lib.rs index e8b3ea2f..473108e3 100644 --- a/fuzz/common/src/lib.rs +++ b/fuzz/common/src/lib.rs @@ -1,4 +1,7 @@ -use ::virtio_queue::{Descriptor, Queue, QueueOwnedT, QueueT}; +use ::virtio_queue::{ + desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, + Queue, QueueOwnedT, QueueT, +}; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; @@ -183,9 +186,11 @@ impl Into for LoadOrdering { } } -impl Into for FuzzingDescriptor { - fn into(self) -> Descriptor { - Descriptor::new(self.addr, self.len, self.flags, self.next) +impl Into for FuzzingDescriptor { + fn into(self) -> RawDescriptor { + RawDescriptor::from(SplitDescriptor::new( + self.addr, self.len, self.flags, self.next, + )) } } diff --git a/fuzz/common/src/virtio_queue.rs b/fuzz/common/src/virtio_queue.rs index f5bc140b..1f4eac3f 100644 --- a/fuzz/common/src/virtio_queue.rs +++ b/fuzz/common/src/virtio_queue.rs @@ -20,7 +20,7 @@ pub mod tests { use crate::create_corpus_file; use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; - use virtio_queue::{mock::MockSplitQueue, Descriptor, Queue, QueueT}; + use virtio_queue::{desc::RawDescriptor, mock::MockSplitQueue, Queue, QueueT}; use vm_memory::{GuestAddress, GuestMemoryMmap}; pub fn create_basic_virtio_queue_ops() -> VirtioQueueInput { @@ -51,7 +51,7 @@ pub mod tests { // To be able to call the functions we actually need to create the environment for running. let mem = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap(); let vq = MockSplitQueue::new(&mem, DEFAULT_QUEUE_SIZE); - let q_descriptors: Vec = + let q_descriptors: Vec = descriptors.iter().map(|desc| (*desc).into()).collect(); vq.build_multiple_desc_chains(&q_descriptors).unwrap(); let mut q: Queue = vq.create_queue().unwrap(); diff --git a/fuzz/common/src/vsock.rs b/fuzz/common/src/vsock.rs index a9518874..9d5e4883 100644 --- a/fuzz/common/src/vsock.rs +++ b/fuzz/common/src/vsock.rs @@ -174,8 +174,8 @@ mod tests { use crate::virtio_queue::DEFAULT_QUEUE_SIZE; use std::io::Write; use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; + use virtio_queue::desc::RawDescriptor; use virtio_queue::mock::MockSplitQueue; - use virtio_queue::Descriptor; use virtio_vsock::packet::VsockPacket; use vm_memory::{Bytes, GuestAddress, GuestMemory, GuestMemoryMmap}; @@ -332,7 +332,7 @@ mod tests { next: 0, }, ]; - let q_descriptors: Vec = + let q_descriptors: Vec = descriptors.iter().map(|desc| (*desc).into()).collect(); let mut chain = vq.build_multiple_desc_chains(&q_descriptors).unwrap(); @@ -382,7 +382,7 @@ mod tests { next: 0, }, ]; - let q_descriptors: Vec = + let q_descriptors: Vec = descriptors.iter().map(|desc| (*desc).into()).collect(); let mut chain = vq.build_multiple_desc_chains(&q_descriptors).unwrap(); diff --git a/fuzz/fuzz_targets/blk.rs b/fuzz/fuzz_targets/blk.rs index 91e08e94..650df14e 100644 --- a/fuzz/fuzz_targets/blk.rs +++ b/fuzz/fuzz_targets/blk.rs @@ -6,7 +6,7 @@ use libfuzzer_sys::fuzz_target; use std::hint::black_box; use virtio_blk::request::Request; use virtio_blk::stdio_executor::StdIoBackend; -use virtio_queue::{mock::MockSplitQueue, Descriptor}; +use virtio_queue::{desc::RawDescriptor, mock::MockSplitQueue}; use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap}; fuzz_target!(|data: &[u8]| { @@ -23,7 +23,7 @@ fuzz_target!(|data: &[u8]| { let vq = MockSplitQueue::create(&m, start_addr, DEFAULT_QUEUE_SIZE); - let descriptors: Vec = fuzz_input + let descriptors: Vec = fuzz_input .descriptors .iter() .map(|desc| (*desc).into()) diff --git a/fuzz/fuzz_targets/virtio_queue.rs b/fuzz/fuzz_targets/virtio_queue.rs index dd07a2eb..3a7a2931 100644 --- a/fuzz/fuzz_targets/virtio_queue.rs +++ b/fuzz/fuzz_targets/virtio_queue.rs @@ -4,7 +4,7 @@ use common::{ virtio_queue::{VirtioQueueInput, DEFAULT_QUEUE_SIZE}, }; use libfuzzer_sys::fuzz_target; -use virtio_queue::{mock::MockSplitQueue, Descriptor}; +use virtio_queue::{desc::RawDescriptor, mock::MockSplitQueue}; use vm_memory::{GuestAddress, GuestMemoryMmap}; fuzz_target!(|data: &[u8]| { @@ -20,7 +20,7 @@ fuzz_target!(|data: &[u8]| { let start_addr = GuestAddress(0x1000); let m = GuestMemoryMmap::<()>::from_ranges(&[(start_addr, 0x11000)]).unwrap(); let vq = MockSplitQueue::create(&m, start_addr, DEFAULT_QUEUE_SIZE); - let descriptors: Vec = fuzz_input + let descriptors: Vec = fuzz_input .descriptors .iter() .map(|desc| (*desc).into()) diff --git a/fuzz/fuzz_targets/virtio_queue_ser.rs b/fuzz/fuzz_targets/virtio_queue_ser.rs index 7fdeb4ff..e464ee7e 100644 --- a/fuzz/fuzz_targets/virtio_queue_ser.rs +++ b/fuzz/fuzz_targets/virtio_queue_ser.rs @@ -5,7 +5,7 @@ use common::{ }; use libfuzzer_sys::fuzz_target; use std::convert::{Into, TryFrom}; -use virtio_queue::{mock::MockSplitQueue, Descriptor, Queue, QueueState}; +use virtio_queue::{desc::RawDescriptor, mock::MockSplitQueue, Queue, QueueState}; use vm_memory::{GuestAddress, GuestMemoryMmap}; fuzz_target!(|data: &[u8]| { @@ -22,7 +22,7 @@ fuzz_target!(|data: &[u8]| { let m = GuestMemoryMmap::<()>::from_ranges(&[(start_addr, 0x11000)]).unwrap(); let vq = MockSplitQueue::create(&m, start_addr, DEFAULT_QUEUE_SIZE); - let descriptors: Vec = fuzz_input + let descriptors: Vec = fuzz_input .descriptors .iter() .map(|desc| (*desc).into()) diff --git a/fuzz/fuzz_targets/vsock.rs b/fuzz/fuzz_targets/vsock.rs index 0d0977e9..519f7ab1 100644 --- a/fuzz/fuzz_targets/vsock.rs +++ b/fuzz/fuzz_targets/vsock.rs @@ -2,7 +2,7 @@ use common::virtio_queue::DEFAULT_QUEUE_SIZE; use common::vsock::{InitFunction, VsockInput}; use libfuzzer_sys::fuzz_target; -use virtio_queue::{mock::MockSplitQueue, Descriptor}; +use virtio_queue::{desc::RawDescriptor, mock::MockSplitQueue}; use virtio_vsock::packet::VsockPacket; use vm_memory::{GuestAddress, GuestMemoryMmap}; @@ -19,7 +19,7 @@ fuzz_target!(|data: &[u8]| { let m = GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0x1000), 0x11000)]).unwrap(); let vq = MockSplitQueue::create(&m, start_addr, DEFAULT_QUEUE_SIZE); - let descriptors: Vec = fuzz_input + let descriptors: Vec = fuzz_input .descriptors .iter() .map(|desc| (*desc).into()) diff --git a/virtio-blk/src/request.rs b/virtio-blk/src/request.rs index 61f31601..cee57323 100644 --- a/virtio-blk/src/request.rs +++ b/virtio-blk/src/request.rs @@ -32,7 +32,10 @@ use virtio_bindings::bindings::virtio_blk::{ VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, }; -use virtio_queue::{Descriptor, DescriptorChain}; +use virtio_queue::{ + desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, + DescriptorChain, +}; use vm_memory::{ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError}; /// Block request parsing errors. @@ -158,10 +161,11 @@ impl Request { } // Checks that a descriptor meets the minimal requirements for a valid status descriptor. - fn check_status_desc(mem: &M, desc: Descriptor) -> Result<()> + fn check_status_desc(mem: &M, desc: RawDescriptor) -> Result<()> where M: GuestMemory + ?Sized, { + let desc = SplitDescriptor::from(desc); // The status MUST always be writable. if !desc.is_write_only() { return Err(Error::UnexpectedReadOnlyDescriptor); @@ -182,7 +186,8 @@ impl Request { } // Checks that a descriptor meets the minimal requirements for a valid data descriptor. - fn check_data_desc(desc: Descriptor, request_type: RequestType) -> Result<()> { + fn check_data_desc(desc: RawDescriptor, request_type: RequestType) -> Result<()> { + let desc = SplitDescriptor::from(desc); // We do this check only for the device-readable buffers, as opposed to // also check that the device doesn't want to read a device-writable buffer // because this one is not a MUST (the device MAY do that for debugging or @@ -234,14 +239,14 @@ impl Request { let mut desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?; while desc.has_next() { - Request::check_data_desc(desc, request.request_type)?; + Request::check_data_desc(RawDescriptor::from(desc), request.request_type)?; request.data.push((desc.addr(), desc.len())); desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?; } let status_desc = desc; - Request::check_status_desc(desc_chain.memory(), status_desc)?; + Request::check_status_desc(desc_chain.memory(), RawDescriptor::from(status_desc))?; request.status_addr = status_desc.addr(); Ok(request) @@ -298,9 +303,24 @@ mod tests { // The `build_desc_chain` function will populate the `NEXT` related flags and field. let v = [ // A device-writable request header descriptor. - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x30_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x30_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; // Create a queue of max 16 descriptors and a descriptor chain based on the array above. let queue = MockSplitQueue::new(&mem, 16); @@ -320,10 +340,15 @@ mod tests { ); let v = [ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), // A device-readable request status descriptor. - Descriptor::new(0x30_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x30_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v[..3]).unwrap(); @@ -334,10 +359,20 @@ mod tests { ); let v = [ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), // Status descriptor with len = 0. - Descriptor::new(0x30_0000, 0x0, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x30_0000, + 0x0, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v[..3]).unwrap(); assert_eq!( @@ -346,9 +381,14 @@ mod tests { ); let v = [ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, 0, 0), - Descriptor::new(0x30_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x30_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v[..3]).unwrap(); @@ -378,10 +418,25 @@ mod tests { // Invalid status address. let v = [ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x30_0000, 0x200, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x1100_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x30_0000, + 0x200, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x1100_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let req_header = RequestHeader { request_type: VIRTIO_BLK_T_OUT, @@ -403,10 +458,25 @@ mod tests { // Valid descriptor chain for OUT. let v = [ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x30_0000, 0x200, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x40_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x30_0000, + 0x200, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x40_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let req_header = RequestHeader { request_type: VIRTIO_BLK_T_OUT, @@ -448,8 +518,13 @@ mod tests { // Valid descriptor chain for FLUSH. let v = [ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x40_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x40_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let req_header = RequestHeader { request_type: VIRTIO_BLK_T_FLUSH, diff --git a/virtio-console/src/console.rs b/virtio-console/src/console.rs index 05e3ef7f..46e20cf2 100644 --- a/virtio-console/src/console.rs +++ b/virtio-console/src/console.rs @@ -282,8 +282,8 @@ where mod tests { use super::*; use virtio_bindings::bindings::virtio_ring::VRING_DESC_F_WRITE; + use virtio_queue::desc::{split::Descriptor as SplitDescriptor, RawDescriptor}; use virtio_queue::mock::MockSplitQueue; - use virtio_queue::Descriptor; use vm_memory::{GuestAddress, GuestMemoryMmap}; impl PartialEq for Error { @@ -352,8 +352,13 @@ mod tests { // One descriptor is write only let v = [ - Descriptor::new(0x1000, INPUT_SIZE, 0, 0), - Descriptor::new(0x2000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x1000, INPUT_SIZE, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x2000, + INPUT_SIZE, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); @@ -366,8 +371,8 @@ mod tests { // Descriptor is outside of the memory bounds let v = [ - Descriptor::new(0x0001_0000, INPUT_SIZE, 0, 0), - Descriptor::new(0x0002_0000, INPUT_SIZE, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x0001_0000, INPUT_SIZE, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x0002_0000, INPUT_SIZE, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v[..2]).unwrap(); assert_eq!( @@ -379,8 +384,8 @@ mod tests { // Test normal functionality. let v = [ - Descriptor::new(0x3000, INPUT_SIZE, 0, 0), - Descriptor::new(0x4000, INPUT_SIZE, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x3000, INPUT_SIZE, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x4000, INPUT_SIZE, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v[..2]).unwrap(); mem.write_slice( @@ -419,8 +424,13 @@ mod tests { // One descriptor is read only let v = [ - Descriptor::new(0x1000, 0x10, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x2000, INPUT_SIZE, 0, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x1000, + 0x10, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new(0x2000, INPUT_SIZE, 0, 0)), ]; let queue = MockSplitQueue::new(&mem, 16); @@ -433,8 +443,18 @@ mod tests { // Descriptor is out of memory bounds let v = [ - Descriptor::new(0x0001_0000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x0002_0000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x0001_0000, + INPUT_SIZE, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x0002_0000, + INPUT_SIZE, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); @@ -455,8 +475,18 @@ mod tests { .enqueue_data(&mut vec![INPUT_VALUE * 2; INPUT_SIZE as usize]) .unwrap(); let v = [ - Descriptor::new(0x3000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x4000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x3000, + INPUT_SIZE, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x4000, + INPUT_SIZE, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); @@ -477,12 +507,12 @@ mod tests { console .enqueue_data(&mut vec![INPUT_VALUE; 2 * INPUT_SIZE as usize]) .unwrap(); - let v = [Descriptor::new( + let v = [RawDescriptor::from(SplitDescriptor::new( 0x5000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0, - )]; + ))]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v[..1]).unwrap(); @@ -497,12 +527,12 @@ mod tests { assert!(!console.is_input_buffer_empty()); - let v = [Descriptor::new( + let v = [RawDescriptor::from(SplitDescriptor::new( 0x6000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0, - )]; + ))]; let mut chain = queue.build_desc_chain(&v[..1]).unwrap(); assert_eq!( @@ -516,12 +546,12 @@ mod tests { assert!(console.is_input_buffer_empty()); // Input buffer is empty. - let v = [Descriptor::new( + let v = [RawDescriptor::from(SplitDescriptor::new( 0x7000, INPUT_SIZE, VRING_DESC_F_WRITE as u16, 0, - )]; + ))]; let mut chain = queue.build_desc_chain(&v[..1]).unwrap(); assert_eq!(console.process_receiveq_chain(&mut chain).unwrap(), 0); diff --git a/virtio-queue/CHANGELOG.md b/virtio-queue/CHANGELOG.md index 69280596..efdc3e00 100644 --- a/virtio-queue/CHANGELOG.md +++ b/virtio-queue/CHANGELOG.md @@ -7,6 +7,12 @@ ## Changed - Updated virtio-bindings from 0.2.4 to 0.2.5. +- Use `RawDescriptor` to represent the memory layout of the split and packed descriptor in virtio-queue/desc. +- Move the split descriptor to the virtio-queue/desc. + +## Added + +- Add packed descriptor in virtio-queue # v0.14.0 diff --git a/virtio-queue/src/chain.rs b/virtio-queue/src/chain.rs index 19598e14..993ddcde 100644 --- a/virtio-queue/src/chain.rs +++ b/virtio-queue/src/chain.rs @@ -17,7 +17,7 @@ use std::ops::Deref; use vm_memory::bitmap::{BitmapSlice, WithBitmapSlice}; use vm_memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryRegion}; -use crate::{Descriptor, Error, Reader, Writer}; +use crate::{desc::split::Descriptor, Error, Reader, Writer}; use virtio_bindings::bindings::virtio_ring::VRING_DESC_ALIGN_SIZE; /// A virtio descriptor chain. @@ -253,6 +253,7 @@ where #[cfg(test)] mod tests { use super::*; + use crate::desc::{split::Descriptor as SplitDescriptor, RawDescriptor}; use crate::mock::{DescriptorTable, MockSplitQueue}; use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_INDIRECT, VRING_DESC_F_NEXT}; use vm_memory::GuestMemoryMmap; @@ -281,7 +282,12 @@ mod tests { { // the first desc has a normal len, and the next_descriptor flag is set // but the the index of the next descriptor is too large - let desc = Descriptor::new(0x1000, 0x1000, VRING_DESC_F_NEXT as u16, 16); + let desc = RawDescriptor::from(SplitDescriptor::new( + 0x1000, + 0x1000, + VRING_DESC_F_NEXT as u16, + 16, + )); vq.desc_table().store(0, desc).unwrap(); let mut c = DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), 16, 0); @@ -291,10 +297,15 @@ mod tests { // finally, let's test an ok chain { - let desc = Descriptor::new(0x1000, 0x1000, VRING_DESC_F_NEXT as u16, 1); + let desc = RawDescriptor::from(SplitDescriptor::new( + 0x1000, + 0x1000, + VRING_DESC_F_NEXT as u16, + 1, + )); vq.desc_table().store(0, desc).unwrap(); - let desc = Descriptor::new(0x2000, 0x1000, 0, 0); + let desc = RawDescriptor::from(SplitDescriptor::new(0x2000, 0x1000, 0, 0)); vq.desc_table().store(1, desc).unwrap(); let mut c = DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), 16, 0); @@ -333,15 +344,15 @@ mod tests { // Populate the entire descriptor table with entries. Only the last one should not have the // VIRTQ_DESC_F_NEXT set. for i in 0..QUEUE_SIZE - 1 { - let desc = Descriptor::new( + let desc = RawDescriptor::from(SplitDescriptor::new( 0x1000 * (i + 1) as u64, 0x1000, VRING_DESC_F_NEXT as u16, i + 1, - ); + )); vq.desc_table().store(i, desc).unwrap(); } - let desc = Descriptor::new((0x1000 * 16) as u64, 0x1000, 0, 0); + let desc = RawDescriptor::from(SplitDescriptor::new((0x1000 * 16) as u64, 0x1000, 0, 0)); vq.desc_table().store(QUEUE_SIZE - 1, desc).unwrap(); let mut c = DescriptorChain::<&GuestMemoryMmap>::new(m, vq.start(), QUEUE_SIZE, 0); @@ -366,18 +377,23 @@ mod tests { let dtable = vq.desc_table(); // Create a chain with one normal descriptor and one pointing to an indirect table. - let desc = Descriptor::new(0x6000, 0x1000, VRING_DESC_F_NEXT as u16, 1); + let desc = RawDescriptor::from(SplitDescriptor::new( + 0x6000, + 0x1000, + VRING_DESC_F_NEXT as u16, + 1, + )); dtable.store(0, desc).unwrap(); // The spec forbids setting both VIRTQ_DESC_F_INDIRECT and VIRTQ_DESC_F_NEXT in flags. We do // not currently enforce this rule, we just ignore the VIRTQ_DESC_F_NEXT flag. - let desc = Descriptor::new( + let desc = RawDescriptor::from(SplitDescriptor::new( 0x7000, 0x1000, (VRING_DESC_F_INDIRECT | VRING_DESC_F_NEXT) as u16, 2, - ); + )); dtable.store(1, desc).unwrap(); - let desc = Descriptor::new(0x8000, 0x1000, 0, 0); + let desc = RawDescriptor::from(SplitDescriptor::new(0x8000, 0x1000, 0, 0)); dtable.store(2, desc).unwrap(); let mut c: DescriptorChain<&GuestMemoryMmap> = DescriptorChain::new(m, vq.start(), 16, 0); @@ -385,10 +401,15 @@ mod tests { // create an indirect table with 4 chained descriptors let idtable = DescriptorTable::new(m, GuestAddress(0x7000), 4); for i in 0..4u16 { - let desc: Descriptor = if i < 3 { - Descriptor::new(0x1000 * i as u64, 0x1000, VRING_DESC_F_NEXT as u16, i + 1) + let desc: RawDescriptor = if i < 3 { + RawDescriptor::from(SplitDescriptor::new( + 0x1000 * i as u64, + 0x1000, + VRING_DESC_F_NEXT as u16, + i + 1, + )) } else { - Descriptor::new(0x1000 * i as u64, 0x1000, 0, 0) + RawDescriptor::from(SplitDescriptor::new(0x1000 * i as u64, 0x1000, 0, 0)) }; idtable.store(i, desc).unwrap(); } @@ -423,12 +444,12 @@ mod tests { let dtable = vq.desc_table(); // Create a chain with a descriptor pointing to an indirect table with unaligned address. - let desc = Descriptor::new( + let desc = RawDescriptor::from(SplitDescriptor::new( 0x7001, 0x1000, (VRING_DESC_F_INDIRECT | VRING_DESC_F_NEXT) as u16, 2, - ); + )); dtable.store(0, desc).unwrap(); let mut c: DescriptorChain<&GuestMemoryMmap> = DescriptorChain::new(m, vq.start(), 16, 0); @@ -436,10 +457,15 @@ mod tests { // Create an indirect table with 4 chained descriptors. let idtable = DescriptorTable::new(m, GuestAddress(0x7001), 4); for i in 0..4u16 { - let desc: Descriptor = if i < 3 { - Descriptor::new(0x1000 * i as u64, 0x1000, VRING_DESC_F_NEXT as u16, i + 1) + let desc: RawDescriptor = if i < 3 { + RawDescriptor::from(SplitDescriptor::new( + 0x1000 * i as u64, + 0x1000, + VRING_DESC_F_NEXT as u16, + i + 1, + )) } else { - Descriptor::new(0x1000 * i as u64, 0x1000, 0, 0) + RawDescriptor::from(SplitDescriptor::new(0x1000 * i as u64, 0x1000, 0, 0)) }; idtable.store(i, desc).unwrap(); } @@ -465,7 +491,12 @@ mod tests { // Create a chain with a descriptor pointing to an invalid indirect table: len not a // multiple of descriptor size. - let desc = Descriptor::new(0x1000, 0x1001, VRING_DESC_F_INDIRECT as u16, 0); + let desc = RawDescriptor::from(SplitDescriptor::new( + 0x1000, + 0x1001, + VRING_DESC_F_INDIRECT as u16, + 0, + )); vq.desc_table().store(0, desc).unwrap(); let mut c: DescriptorChain<&GuestMemoryMmap> = @@ -480,12 +511,12 @@ mod tests { // Create a chain with a descriptor pointing to an invalid indirect table: table len > // u16::MAX. - let desc = Descriptor::new( + let desc = RawDescriptor::from(SplitDescriptor::new( 0x1000, (u16::MAX as u32 + 1) * VRING_DESC_ALIGN_SIZE, VRING_DESC_F_INDIRECT as u16, 0, - ); + )); vq.desc_table().store(0, desc).unwrap(); let mut c: DescriptorChain<&GuestMemoryMmap> = @@ -499,10 +530,15 @@ mod tests { let vq = MockSplitQueue::new(m, 16); // Create a chain with a descriptor pointing to an indirect table. - let desc = Descriptor::new(0x1000, 0x1000, VRING_DESC_F_INDIRECT as u16, 0); + let desc = RawDescriptor::from(SplitDescriptor::new( + 0x1000, + 0x1000, + VRING_DESC_F_INDIRECT as u16, + 0, + )); vq.desc_table().store(0, desc).unwrap(); // It's ok for an indirect descriptor to have flags = 0. - let desc = Descriptor::new(0x3000, 0x1000, 0, 0); + let desc = RawDescriptor::from(SplitDescriptor::new(0x3000, 0x1000, 0, 0)); m.write_obj(desc, GuestAddress(0x1000)).unwrap(); let mut c: DescriptorChain<&GuestMemoryMmap> = @@ -511,7 +547,12 @@ mod tests { // But it's not allowed to have an indirect descriptor that points to another indirect // table. - let desc = Descriptor::new(0x3000, 0x1000, VRING_DESC_F_INDIRECT as u16, 0); + let desc = RawDescriptor::from(SplitDescriptor::new( + 0x3000, + 0x1000, + VRING_DESC_F_INDIRECT as u16, + 0, + )); m.write_obj(desc, GuestAddress(0x1000)).unwrap(); let mut c: DescriptorChain<&GuestMemoryMmap> = diff --git a/virtio-queue/src/desc/mod.rs b/virtio-queue/src/desc/mod.rs new file mode 100644 index 00000000..19beb550 --- /dev/null +++ b/virtio-queue/src/desc/mod.rs @@ -0,0 +1,105 @@ +//! Descriptor types for virtio queue. + +use vm_memory::{ByteValued, Le16, Le32, Le64}; + +pub mod packed; +pub mod split; + +/// a virtio descriptor +#[deprecated = "Descriptor has been deprecated. Please use RawDescriptor"] +pub type Descriptor = RawDescriptor; + +/// A virtio descriptor's layout constraints with C representation. +/// This is a unified representation of the memory layout order +/// for packed descriptors and split descriptors. +/// This type corresponds to struct virtq_desc, see: +/// https://docs.oasis-open.org/virtio/virtio/v1.3/csd01/virtio-v1.3-csd01.html#x1-720008 +#[repr(C)] +#[derive(Clone, Copy, Debug, Default)] +pub struct RawDescriptor(Le64, Le32, Le16, Le16); + +// SAFETY: This is safe because `Descriptor` contains only wrappers over POD types and +// all accesses through safe `vm-memory` API will validate any garbage that could be +// included in there. +unsafe impl ByteValued for RawDescriptor {} + +impl From for RawDescriptor { + fn from(desc: split::Descriptor) -> Self { + RawDescriptor( + Le64::from(desc.addr().0), + Le32::from(desc.len()), + Le16::from(desc.flags()), + Le16::from(desc.next()), + ) + } +} + +impl From for RawDescriptor { + fn from(desc: packed::Descriptor) -> Self { + RawDescriptor( + Le64::from(desc.addr().0), + Le32::from(desc.len()), + Le16::from(desc.id()), + Le16::from(desc.flags()), + ) + } +} + +impl From for split::Descriptor { + fn from(desc: RawDescriptor) -> split::Descriptor { + split::Descriptor::new(desc.0.into(), desc.1.into(), desc.2.into(), desc.3.into()) + } +} + +impl From for packed::Descriptor { + fn from(desc: RawDescriptor) -> packed::Descriptor { + packed::Descriptor::new(desc.0.into(), desc.1.into(), desc.2.into(), desc.3.into()) + } +} + +#[cfg(test)] +mod tests { + use vm_memory::{Le16, Le32, Le64}; + + use super::{packed, split, RawDescriptor}; + + #[test] + fn test_desc_from_split() { + let split_desc = split::Descriptor::new(1, 2, 3, 4); + let desc = RawDescriptor::from(split_desc); + assert_eq!(split_desc.addr().0, desc.0); + assert_eq!(split_desc.len(), desc.1); + assert_eq!(split_desc.flags(), desc.2); + assert_eq!(split_desc.next(), desc.3); + } + + #[test] + fn test_split_from_desc() { + let desc = RawDescriptor(Le64::from(1), Le32::from(2), Le16::from(3), Le16::from(4)); + let split_desc = split::Descriptor::from(desc); + assert_eq!(split_desc.addr().0, desc.0); + assert_eq!(split_desc.len(), desc.1); + assert_eq!(split_desc.flags(), desc.2); + assert_eq!(split_desc.next(), desc.3); + } + + #[test] + fn test_desc_from_packed() { + let packed_desc = packed::Descriptor::new(1, 2, 3, 4); + let desc = RawDescriptor::from(packed_desc); + assert_eq!(packed_desc.addr().0, desc.0); + assert_eq!(packed_desc.len(), desc.1); + assert_eq!(packed_desc.id(), desc.2); + assert_eq!(packed_desc.flags(), desc.3); + } + + #[test] + fn test_packed_from_desc() { + let desc = RawDescriptor(Le64::from(1), Le32::from(2), Le16::from(3), Le16::from(4)); + let packed_desc = packed::Descriptor::from(desc); + assert_eq!(packed_desc.addr().0, desc.0); + assert_eq!(packed_desc.len(), desc.1); + assert_eq!(packed_desc.id(), desc.2); + assert_eq!(packed_desc.flags(), desc.3); + } +} diff --git a/virtio-queue/src/desc/packed.rs b/virtio-queue/src/desc/packed.rs new file mode 100644 index 00000000..7f0d60bf --- /dev/null +++ b/virtio-queue/src/desc/packed.rs @@ -0,0 +1,203 @@ +//! packed descriptor +use virtio_bindings::bindings::virtio_ring::{ + VRING_DESC_F_INDIRECT, VRING_DESC_F_NEXT, VRING_DESC_F_WRITE, +}; +use vm_memory::{ByteValued, GuestAddress, Le16, Le32, Le64}; + +/// A virtio packed descriptor constraints with C representation. +#[repr(C)] +#[derive(Default, Clone, Copy, Debug)] +pub struct Descriptor { + /// Guest physical address of device specific data. + addr: Le64, + /// Length of device specific data. + len: Le32, + /// Index of descriptor in the descriptor table. + id: Le16, + /// Includes next, write, and indirect bits. + flags: Le16, +} + +#[allow(clippy::len_without_is_empty)] +impl Descriptor { + /// Return the guest physical address of the descriptor buffer. + pub fn addr(&self) -> GuestAddress { + GuestAddress(self.addr.into()) + } + + /// Return the length of the descriptor buffer. + pub fn len(&self) -> u32 { + self.len.into() + } + + /// Return the flags for this descriptor, including next, write and indirect bits. + pub fn flags(&self) -> u16 { + self.flags.into() + } + + /// Return the index of the descriptor in the descriptor table. + pub fn id(&self) -> u16 { + self.id.into() + } + + /// Check whether this descriptor refers to a buffer containing an indirect descriptor table. + pub fn refers_to_indirect_table(&self) -> bool { + self.flags() & VRING_DESC_F_INDIRECT as u16 != 0 + } + + /// Check whether the `VIRTQ_DESC_F_NEXT` is set for the descriptor. + pub fn has_next(&self) -> bool { + self.flags() & VRING_DESC_F_NEXT as u16 != 0 + } + + /// Check if the driver designated this as a write only descriptor. + /// + /// If this is false, this descriptor is read only. + /// Write only means the the emulated device can write and the driver can read. + pub fn is_write_only(&self) -> bool { + self.flags() & VRING_DESC_F_WRITE as u16 != 0 + } +} + +impl Descriptor { + /// Create a new descriptor. + /// + /// # Arguments + /// * `addr` - the guest physical address of the descriptor buffer. + /// * `len` - the length of the descriptor buffer. + /// * `flags` - the `flags` for the descriptor. + /// * `next` - the `next` field of the descriptor. + pub fn new(addr: u64, len: u32, id: u16, flags: u16) -> Self { + Descriptor { + addr: addr.into(), + len: len.into(), + id: id.into(), + flags: flags.into(), + } + } + + /// Set the guest physical address of the descriptor buffer. + pub fn set_addr(&mut self, addr: u64) { + self.addr = addr.into(); + } + + /// Set the length of the descriptor buffer. + pub fn set_len(&mut self, len: u32) { + self.len = len.into(); + } + + /// Set the flags for this descriptor. + pub fn set_flags(&mut self, flags: u16) { + self.flags = flags.into(); + } + + /// Set the value stored in the `next` field of the descriptor. + pub fn set_id(&mut self, id: u16) { + self.id = id.into(); + } +} + +// SAFETY: This is safe because `Descriptor` contains only wrappers over POD types and +// all accesses through safe `vm-memory` API will validate any garbage that could be +// included in there. +unsafe impl ByteValued for Descriptor {} + +/// A packed descriptor event constraints with C representation. +#[repr(C)] +#[derive(Clone, Copy, Debug)] +pub struct PackedDescEvent { + off_wrap: Le16, + flags: Le16, +} + +impl PackedDescEvent { + /// Create a new `VirtqUsedElem` instance. + /// + /// # Arguments + /// * `id` - the index of the used descriptor chain. + /// * `len` - the total length of the descriptor chain which was used (written to). + #[allow(unused)] + pub(crate) fn new(off_wrap: u16, flags: u16) -> Self { + PackedDescEvent { + off_wrap: off_wrap.into(), + flags: flags.into(), + } + } +} + +// SAFETY: This is safe because `PackedDescEvent` contains only wrappers over POD types and +// all accesses through safe `vm-memory` API will validate any garbage that could be +// included in there. +unsafe impl ByteValued for PackedDescEvent {} + +#[cfg(test)] +mod tests { + use super::*; + use memoffset::offset_of; + use std::mem::{align_of, size_of}; + + #[test] + fn test_descriptor_offset() { + assert_eq!(size_of::(), 16); + assert_eq!(offset_of!(Descriptor, addr), 0); + assert_eq!(offset_of!(Descriptor, len), 8); + assert_eq!(offset_of!(Descriptor, id), 12); + assert_eq!(offset_of!(Descriptor, flags), 14); + assert!(align_of::() <= 16); + } + + #[test] + fn test_descriptor_getter_setter() { + let mut desc = Descriptor::new(0, 0, 0, 0); + + desc.set_addr(0x1000); + assert_eq!(desc.addr(), GuestAddress(0x1000)); + desc.set_len(0x2000); + assert_eq!(desc.len(), 0x2000); + desc.set_flags(VRING_DESC_F_NEXT as u16); + assert_eq!(desc.flags(), VRING_DESC_F_NEXT as u16); + assert!(desc.has_next()); + assert!(!desc.is_write_only()); + assert!(!desc.refers_to_indirect_table()); + desc.set_flags(VRING_DESC_F_WRITE as u16); + assert_eq!(desc.flags(), VRING_DESC_F_WRITE as u16); + assert!(!desc.has_next()); + assert!(desc.is_write_only()); + assert!(!desc.refers_to_indirect_table()); + desc.set_flags(VRING_DESC_F_INDIRECT as u16); + assert_eq!(desc.flags(), VRING_DESC_F_INDIRECT as u16); + assert!(!desc.is_write_only()); + assert!(desc.refers_to_indirect_table()); + desc.set_id(1); + assert_eq!(desc.id(), 1); + } + + #[test] + fn test_descriptor_copy() { + let e1 = Descriptor::new(1, 2, 0, 3); + let mut e2 = Descriptor::default(); + + e2.as_mut_slice().copy_from_slice(e1.as_slice()); + assert_eq!(e1.addr(), e2.addr()); + assert_eq!(e1.len(), e2.len()); + assert_eq!(e1.id(), e2.id()); + assert_eq!(e1.flags(), e2.flags()); + } + + #[test] + fn test_packed_desc_event_offset() { + assert_eq!(offset_of!(PackedDescEvent, off_wrap), 0); + assert_eq!(offset_of!(PackedDescEvent, flags), 2); + assert_eq!(size_of::(), 4); + } + + #[test] + fn test_packed_desc_event_copy() { + let e1 = PackedDescEvent::new(1, 2); + let mut e2 = PackedDescEvent::new(0, 0); + + e2.as_mut_slice().copy_from_slice(e1.as_slice()); + assert_eq!(e1.off_wrap, e2.off_wrap); + assert_eq!(e1.flags, e2.flags); + } +} diff --git a/virtio-queue/src/descriptor.rs b/virtio-queue/src/desc/split.rs similarity index 95% rename from virtio-queue/src/descriptor.rs rename to virtio-queue/src/desc/split.rs index 7f1564b5..2778f921 100644 --- a/virtio-queue/src/descriptor.rs +++ b/virtio-queue/src/desc/split.rs @@ -9,6 +9,7 @@ // Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved. // // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause +//! split descriptor use vm_memory::{ByteValued, GuestAddress, Le16, Le32, Le64}; @@ -23,7 +24,7 @@ use virtio_bindings::bindings::virtio_ring::{ /// ```rust /// # use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; /// # use virtio_queue::mock::MockSplitQueue; -/// use virtio_queue::{Descriptor, Queue, QueueOwnedT}; +/// use virtio_queue::{desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, Queue, QueueOwnedT}; /// use vm_memory::{GuestAddress, GuestMemoryMmap}; /// /// # fn populate_queue(m: &GuestMemoryMmap) -> Queue { @@ -31,9 +32,9 @@ use virtio_bindings::bindings::virtio_ring::{ /// # let mut q = vq.create_queue().unwrap(); /// # /// # // We have only one chain: (0, 1). -/// # let desc = Descriptor::new(0x1000, 0x1000, VRING_DESC_F_NEXT as u16, 1); +/// # let desc = RawDescriptor::from(SplitDescriptor::new(0x1000, 0x1000, VRING_DESC_F_NEXT as u16, 1)); /// # vq.desc_table().store(0, desc); -/// # let desc = Descriptor::new(0x2000, 0x1000, VRING_DESC_F_WRITE as u16, 0); +/// # let desc = RawDescriptor::from(SplitDescriptor::new(0x2000, 0x1000, VRING_DESC_F_WRITE as u16, 0)); /// # vq.desc_table().store(1, desc); /// # /// # vq.avail().ring().ref_at(0).unwrap().store(u16::to_le(0)); @@ -56,8 +57,7 @@ use virtio_bindings::bindings::virtio_ring::{ /// let _has_next = desc.has_next(); /// let _refers_to_ind_table = desc.refers_to_indirect_table(); /// ``` -// Note that the `ByteValued` implementation of this structure expects the `Descriptor` to store -// only plain old data types. +/// A virtio split descriptor constraints with C representation. #[repr(C)] #[derive(Default, Clone, Copy, Debug)] pub struct Descriptor { @@ -76,6 +76,22 @@ pub struct Descriptor { #[allow(clippy::len_without_is_empty)] impl Descriptor { + /// Create a new descriptor. + /// + /// # Arguments + /// * `addr` - the guest physical address of the descriptor buffer. + /// * `len` - the length of the descriptor buffer. + /// * `flags` - the `flags` for the descriptor. + /// * `next` - the `next` field of the descriptor. + pub fn new(addr: u64, len: u32, flags: u16, next: u16) -> Self { + Descriptor { + addr: addr.into(), + len: len.into(), + flags: flags.into(), + next: next.into(), + } + } + /// Return the guest physical address of the descriptor buffer. pub fn addr(&self) -> GuestAddress { GuestAddress(self.addr.into()) @@ -117,22 +133,6 @@ impl Descriptor { #[cfg(any(test, feature = "test-utils"))] impl Descriptor { - /// Create a new descriptor. - /// - /// # Arguments - /// * `addr` - the guest physical address of the descriptor buffer. - /// * `len` - the length of the descriptor buffer. - /// * `flags` - the `flags` for the descriptor. - /// * `next` - the `next` field of the descriptor. - pub fn new(addr: u64, len: u32, flags: u16, next: u16) -> Self { - Descriptor { - addr: addr.into(), - len: len.into(), - flags: flags.into(), - next: next.into(), - } - } - /// Set the guest physical address of the descriptor buffer. pub fn set_addr(&mut self, addr: u64) { self.addr = addr.into(); @@ -175,6 +175,7 @@ impl VirtqUsedElem { /// # Arguments /// * `id` - the index of the used descriptor chain. /// * `len` - the total length of the descriptor chain which was used (written to). + #[allow(unused)] pub(crate) fn new(id: u32, len: u32) -> Self { VirtqUsedElem { id: id.into(), diff --git a/virtio-queue/src/descriptor_utils.rs b/virtio-queue/src/descriptor_utils.rs index 5c90637b..8048141e 100644 --- a/virtio-queue/src/descriptor_utils.rs +++ b/virtio-queue/src/descriptor_utils.rs @@ -365,7 +365,10 @@ impl io::Write for Writer<'_, B> { #[cfg(test)] mod tests { use super::*; - use crate::{Descriptor, Queue, QueueOwnedT, QueueT}; + use crate::{ + desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, + Queue, QueueOwnedT, QueueT, + }; use vm_memory::{GuestAddress, GuestMemoryMmap, Le32}; use crate::mock::MockSplitQueue; @@ -402,12 +405,12 @@ mod tests { flags |= VRING_DESC_F_NEXT; } - descs.push(Descriptor::new( + descs.push(RawDescriptor::from(SplitDescriptor::new( buffers_start_addr.raw_value(), size, flags as u16, (index + 1) as u16, - )); + ))); let offset = size + spaces_between_regions; buffers_start_addr = buffers_start_addr @@ -439,7 +442,7 @@ mod tests { let queue = MockSplitQueue::create(&memory, GuestAddress(0x0), MAX_QUEUE_SIZE); // set addr out of memory - let descriptor = Descriptor::new(0x1001, 1, 0, 1_u16); + let descriptor = RawDescriptor::from(SplitDescriptor::new(0x1001, 1, 0, 1_u16)); queue.build_desc_chain(&[descriptor]).unwrap(); let avail_ring = queue.avail_addr(); diff --git a/virtio-queue/src/lib.rs b/virtio-queue/src/lib.rs index df3d1893..27e3f86c 100644 --- a/virtio-queue/src/lib.rs +++ b/virtio-queue/src/lib.rs @@ -23,18 +23,17 @@ use log::error; use vm_memory::{GuestMemory, GuestMemoryError, VolatileMemoryError}; pub use self::chain::{DescriptorChain, DescriptorChainRwIter}; -pub use self::descriptor::{Descriptor, VirtqUsedElem}; pub use self::descriptor_utils::{Reader, Writer}; pub use self::queue::{AvailIter, Queue}; pub use self::queue_sync::QueueSync; pub use self::state::QueueState; pub mod defs; +pub mod desc; #[cfg(any(test, feature = "test-utils"))] pub mod mock; mod chain; -mod descriptor; mod descriptor_utils; mod queue; mod queue_sync; diff --git a/virtio-queue/src/mock.rs b/virtio-queue/src/mock.rs index 1f435884..46169061 100644 --- a/virtio-queue/src/mock.rs +++ b/virtio-queue/src/mock.rs @@ -12,7 +12,13 @@ use vm_memory::{ }; use crate::defs::{VIRTQ_AVAIL_ELEMENT_SIZE, VIRTQ_AVAIL_RING_HEADER_SIZE}; -use crate::{Descriptor, DescriptorChain, Error, Queue, QueueOwnedT, QueueT, VirtqUsedElem}; +use crate::{ + desc::{ + split::{Descriptor as SplitDescriptor, VirtqUsedElem}, + RawDescriptor, + }, + DescriptorChain, Error, Queue, QueueOwnedT, QueueT, +}; use std::fmt::{self, Debug, Display}; use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_INDIRECT, VRING_DESC_F_NEXT}; @@ -177,7 +183,7 @@ pub type UsedRing<'a, M> = SplitQueueRing<'a, M, VirtqUsedElem>; /// Refers to the buffers the driver is using for the device. pub struct DescriptorTable<'a, M> { - table: ArrayRef<'a, M, Descriptor>, + table: ArrayRef<'a, M, RawDescriptor>, len: u16, free_descriptors: Vec, } @@ -196,14 +202,14 @@ impl<'a, M: GuestMemory> DescriptorTable<'a, M> { } /// Read one descriptor from the specified index. - pub fn load(&self, index: u16) -> Result { + pub fn load(&self, index: u16) -> Result { self.table .ref_at(index as usize) .map(|load_ref| load_ref.load()) } /// Write one descriptor at the specified index. - pub fn store(&self, index: u16, value: Descriptor) -> Result<(), MockError> { + pub fn store(&self, index: u16, value: RawDescriptor) -> Result<(), MockError> { self.table .ref_at(index as usize) .map(|store_ref| store_ref.store(value)) @@ -211,7 +217,7 @@ impl<'a, M: GuestMemory> DescriptorTable<'a, M> { /// Return the total size of the DescriptorTable in bytes. pub fn total_size(&self) -> u64 { - (self.len as usize * size_of::()) as u64 + (self.len as usize * size_of::()) as u64 } /// Create a chain of descriptors. @@ -228,7 +234,7 @@ impl<'a, M: GuestMemory> DescriptorTable<'a, M> { for (pos, index_value) in indices.iter().copied().enumerate() { // Addresses and lens constant for now. - let mut desc = Descriptor::new(0x1000, 0x1000, 0, 0); + let mut desc = SplitDescriptor::new(0x1000, 0x1000, 0, 0); // It's not the last descriptor in the chain. if pos < indices.len() - 1 { @@ -237,6 +243,8 @@ impl<'a, M: GuestMemory> DescriptorTable<'a, M> { } else { desc.set_flags(0); } + + let desc = RawDescriptor::from(desc); self.store(index_value, desc)?; } @@ -389,12 +397,13 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> { // We just allocate the indirect table and forget about it for now. let indirect_addr = self.alloc_indirect_chain(len)?; - let mut desc = self.desc_table.load(head_idx)?; + let desc = self.desc_table.load(head_idx)?; + let mut desc = SplitDescriptor::from(desc); desc.set_flags(VRING_DESC_F_INDIRECT as u16); desc.set_addr(indirect_addr.raw_value()); - desc.set_len(u32::from(len) * size_of::() as u32); + desc.set_len(u32::from(len) * size_of::() as u32); - self.desc_table.store(head_idx, desc)?; + self.desc_table.store(head_idx, RawDescriptor::from(desc))?; self.update_avail_idx(head_idx) } @@ -424,7 +433,7 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> { /// the descriptor table, and returns the first `DescriptorChain` available. pub fn build_multiple_desc_chains( &self, - descs: &[Descriptor], + descs: &[RawDescriptor], ) -> Result, MockError> { self.add_desc_chains(descs, 0)?; self.create_queue::() @@ -442,9 +451,13 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> { // TODO: make this function work with a generic queue. For now that's not possible because // we cannot create the descriptor chain from an iterator as iterator is not implemented for // a generic T, just for `Queue`. - pub fn build_desc_chain(&self, descs: &[Descriptor]) -> Result, MockError> { - let mut modified_descs: Vec = Vec::with_capacity(descs.len()); + pub fn build_desc_chain( + &self, + descs: &[RawDescriptor], + ) -> Result, MockError> { + let mut modified_descs: Vec = Vec::with_capacity(descs.len()); for (idx, desc) in descs.iter().enumerate() { + let desc = SplitDescriptor::from(*desc); let (flags, next) = if idx == descs.len() - 1 { // Clear the NEXT flag if it was set. The value of the next field of the // Descriptor doesn't matter at this point. @@ -454,7 +467,12 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> { // descriptor. This ignores any value is actually present in `desc.next`. (desc.flags() | VRING_DESC_F_NEXT as u16, idx as u16 + 1) }; - modified_descs.push(Descriptor::new(desc.addr().0, desc.len(), flags, next)); + modified_descs.push(RawDescriptor::from(SplitDescriptor::new( + desc.addr().0, + desc.len(), + flags, + next, + ))); } self.build_multiple_desc_chains(&modified_descs[..]) } @@ -465,7 +483,7 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> { // The descriptor chain related information is written in memory starting with address 0. // The `addr` fields of the input descriptors should start at a sufficiently // greater location (i.e. 1MiB, or `0x10_0000`). - pub fn add_desc_chains(&self, descs: &[Descriptor], offset: u16) -> Result<(), MockError> { + pub fn add_desc_chains(&self, descs: &[RawDescriptor], offset: u16) -> Result<(), MockError> { let mut new_entries = 0; let avail_idx: u16 = self .mem @@ -477,7 +495,9 @@ impl<'a, M: GuestMemory> MockSplitQueue<'a, M> { let i = idx as u16 + offset; self.desc_table().store(i, *desc)?; - if idx == 0 || descs[idx - 1].flags() & VRING_DESC_F_NEXT as u16 != 1 { + if idx == 0 + || SplitDescriptor::from(descs[idx - 1]).flags() & VRING_DESC_F_NEXT as u16 != 1 + { // Update the available ring position. self.mem .write_obj( diff --git a/virtio-queue/src/queue.rs b/virtio-queue/src/queue.rs index 7ab252ee..4965b082 100644 --- a/virtio-queue/src/queue.rs +++ b/virtio-queue/src/queue.rs @@ -19,10 +19,8 @@ use crate::defs::{ VIRTQ_AVAIL_ELEMENT_SIZE, VIRTQ_AVAIL_RING_HEADER_SIZE, VIRTQ_AVAIL_RING_META_SIZE, VIRTQ_USED_ELEMENT_SIZE, VIRTQ_USED_RING_HEADER_SIZE, VIRTQ_USED_RING_META_SIZE, }; -use crate::{ - error, Descriptor, DescriptorChain, Error, QueueGuard, QueueOwnedT, QueueState, QueueT, - VirtqUsedElem, -}; +use crate::desc::{split::VirtqUsedElem, RawDescriptor}; +use crate::{error, DescriptorChain, Error, QueueGuard, QueueOwnedT, QueueState, QueueT}; use virtio_bindings::bindings::virtio_ring::VRING_USED_F_NO_NOTIFY; /// The maximum queue size as defined in the Virtio Spec. @@ -301,7 +299,7 @@ impl QueueT for Queue { let desc_table = self.desc_table; // The multiplication can not overflow an u64 since we are multiplying an u16 with a // small number. - let desc_table_size = size_of::() as u64 * queue_size; + let desc_table_size = size_of::() as u64 * queue_size; let avail_ring = self.avail_ring; // The operations below can not overflow an u64 since they're working with relatively small // numbers compared to u64::MAX. @@ -614,7 +612,7 @@ impl QueueOwnedT for Queue { /// ```rust /// # use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE}; /// # use virtio_queue::mock::MockSplitQueue; -/// use virtio_queue::{Descriptor, Queue, QueueOwnedT}; +/// use virtio_queue::{desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, Queue, QueueOwnedT}; /// use vm_memory::{GuestAddress, GuestMemoryMmap}; /// /// # fn populate_queue(m: &GuestMemoryMmap) -> Queue { @@ -631,7 +629,7 @@ impl QueueOwnedT for Queue { /// # _ => VRING_DESC_F_NEXT, /// # }; /// # -/// # descs.push(Descriptor::new((0x1000 * (i + 1)) as u64, 0x1000, flags as u16, i + 1)); +/// # descs.push(RawDescriptor::from(SplitDescriptor::new((0x1000 * (i + 1)) as u64, 0x1000, flags as u16, i + 1))); /// # } /// # /// # vq.add_desc_chains(&descs, 0).unwrap(); @@ -780,8 +778,8 @@ impl PartialEq for Error { mod tests { use super::*; use crate::defs::{DEFAULT_AVAIL_RING_ADDR, DEFAULT_DESC_TABLE_ADDR, DEFAULT_USED_RING_ADDR}; + use crate::desc::{split::Descriptor as SplitDescriptor, RawDescriptor}; use crate::mock::MockSplitQueue; - use crate::Descriptor; use virtio_bindings::bindings::virtio_ring::{ VRING_DESC_F_NEXT, VRING_DESC_F_WRITE, VRING_USED_F_NO_NOTIFY, }; @@ -1065,12 +1063,12 @@ mod tests { _ => VRING_DESC_F_NEXT, }; - descs.push(Descriptor::new( + descs.push(RawDescriptor::from(SplitDescriptor::new( (0x1000 * (i + 1)) as u64, 0x1000, flags as u16, i + 1, - )); + ))); } vq.add_desc_chains(&descs, 0).unwrap(); @@ -1191,12 +1189,12 @@ mod tests { _ => VRING_DESC_F_NEXT, }; - descs.push(Descriptor::new( + descs.push(RawDescriptor::from(SplitDescriptor::new( (0x1000 * (i + 1)) as u64, 0x1000, flags as u16, i + 1, - )); + ))); } vq.add_desc_chains(&descs, 0).unwrap(); @@ -1256,12 +1254,12 @@ mod tests { // Create descriptors to fill up the queue let mut descs = Vec::new(); for i in 0..queue_size { - descs.push(Descriptor::new( + descs.push(RawDescriptor::from(SplitDescriptor::new( (0x1000 * (i + 1)) as u64, 0x1000, 0_u16, i + 1, - )); + ))); } vq.add_desc_chains(&descs, 0).unwrap(); @@ -1304,12 +1302,12 @@ mod tests { _ => VRING_DESC_F_NEXT, }; - descs.push(Descriptor::new( + descs.push(RawDescriptor::from(SplitDescriptor::new( (0x1000 * (j + 1)) as u64, 0x1000, flags as u16, j + 1, - )); + ))); } vq.add_desc_chains(&descs, 0).unwrap(); @@ -1380,12 +1378,12 @@ mod tests { _ => VRING_DESC_F_NEXT, }; - descs.push(Descriptor::new( + descs.push(RawDescriptor::from(SplitDescriptor::new( (0x1000 * (j + 1)) as u64, 0x1000, flags as u16, j + 1, - )); + ))); } vq.add_desc_chains(&descs, 0).unwrap(); @@ -1430,8 +1428,13 @@ mod tests { // total) { let descs = vec![ - Descriptor::new(0x1000, 0xffff_ffff, VRING_DESC_F_NEXT as u16, 1), - Descriptor::new(0x1000, 0x1234_5678, 0, 2), + RawDescriptor::from(SplitDescriptor::new( + 0x1000, + 0xffff_ffff, + VRING_DESC_F_NEXT as u16, + 1, + )), + RawDescriptor::from(SplitDescriptor::new(0x1000, 0x1234_5678, 0, 2)), ]; vq.add_desc_chains(&descs, 0).unwrap(); let mut yielded_bytes_by_iteration = 0_u32; @@ -1444,12 +1447,12 @@ mod tests { // Same as above, but test with a descriptor which is self-referential { - let descs = vec![Descriptor::new( + let descs = vec![RawDescriptor::from(SplitDescriptor::new( 0x1000, 0xffff_ffff, VRING_DESC_F_NEXT as u16, 0, - )]; + ))]; vq.add_desc_chains(&descs, 0).unwrap(); let mut yielded_bytes_by_iteration = 0_u32; for d in q.iter(m).unwrap().next().unwrap() { @@ -1467,12 +1470,12 @@ mod tests { let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap(); let vq = MockSplitQueue::new(m, 1); // This input was generated by the fuzzer, both for the QueueS and the Descriptor - let descriptors: Vec = vec![Descriptor::new( + let descriptors: Vec = vec![RawDescriptor::from(SplitDescriptor::new( 14178673876262995140, 3301229764, 50372, 50372, - )]; + ))]; vq.build_desc_chain(&descriptors).unwrap(); let mut q = Queue { @@ -1534,14 +1537,19 @@ mod tests { let vq = MockSplitQueue::new(m, 1024); // This input below was generated by the fuzzer. - let descriptors: Vec = vec![ - Descriptor::new(21508325467, 0, 1, 4), - Descriptor::new(2097152, 4096, 3, 0), - Descriptor::new(18374686479672737792, 4294967295, 65535, 29), - Descriptor::new(76842670169653248, 1114115, 0, 0), - Descriptor::new(16, 983040, 126, 3), - Descriptor::new(897648164864, 0, 0, 0), - Descriptor::new(111669149722, 0, 0, 0), + let descriptors: Vec = vec![ + RawDescriptor::from(SplitDescriptor::new(21508325467, 0, 1, 4)), + RawDescriptor::from(SplitDescriptor::new(2097152, 4096, 3, 0)), + RawDescriptor::from(SplitDescriptor::new( + 18374686479672737792, + 4294967295, + 65535, + 29, + )), + RawDescriptor::from(SplitDescriptor::new(76842670169653248, 1114115, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(16, 983040, 126, 3)), + RawDescriptor::from(SplitDescriptor::new(897648164864, 0, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(111669149722, 0, 0, 0)), ]; vq.build_multiple_desc_chains(&descriptors).unwrap(); diff --git a/virtio-vsock/src/packet.rs b/virtio-vsock/src/packet.rs index a3aee4a3..7be82ccc 100644 --- a/virtio-vsock/src/packet.rs +++ b/virtio-vsock/src/packet.rs @@ -195,7 +195,7 @@ impl<'a, B: BitmapSlice> VsockPacket<'a, B> { /// ```rust /// # use virtio_bindings::bindings::virtio_ring::VRING_DESC_F_WRITE; /// # use virtio_queue::mock::MockSplitQueue; - /// # use virtio_queue::{Descriptor, Queue, QueueT}; + /// # use virtio_queue::{desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, Queue, QueueT}; /// use virtio_vsock::packet::{VsockPacket, PKT_HEADER_SIZE}; /// # use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryMmap}; /// @@ -206,8 +206,8 @@ impl<'a, B: BitmapSlice> VsockPacket<'a, B> { /// # let mut q = vq.create_queue().unwrap(); /// # /// # let v = vec![ - /// # Descriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - /// # Descriptor::new(0x8_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + /// # RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0)), + /// # RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, VRING_DESC_F_WRITE as u16, 0)), /// # ]; /// # let mut chain = vq.build_desc_chain(&v); /// # q @@ -374,7 +374,7 @@ impl<'a, B: BitmapSlice> VsockPacket<'a, B> { /// /// ```rust /// # use virtio_queue::mock::MockSplitQueue; - /// # use virtio_queue::{Descriptor, Queue, QueueT}; + /// # use virtio_queue::{desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, Queue, QueueT}; /// use virtio_vsock::packet::{VsockPacket, PKT_HEADER_SIZE}; /// # use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryMmap}; /// @@ -386,8 +386,8 @@ impl<'a, B: BitmapSlice> VsockPacket<'a, B> { /// # let mut q = vq.create_queue().unwrap(); /// # /// # let v = vec![ - /// # Descriptor::new(0x5_0000, 0x100, 0, 0), - /// # Descriptor::new(0x8_0000, 0x100, 0, 0), + /// # RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), + /// # RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)), /// # ]; /// # let mut chain = vq.build_desc_chain(&v); /// # q @@ -516,7 +516,7 @@ impl<'a, B: BitmapSlice> VsockPacket<'a, B> { /// ```rust /// # use virtio_bindings::bindings::virtio_ring::VRING_DESC_F_WRITE; /// # use virtio_queue::mock::MockSplitQueue; - /// # use virtio_queue::{Descriptor, Queue, QueueT}; + /// # use virtio_queue::{desc::{split::Descriptor as SplitDescriptor, RawDescriptor}, Queue, QueueT}; /// use virtio_vsock::packet::{VsockPacket, PKT_HEADER_SIZE}; /// # use vm_memory::{Bytes, GuestAddress, GuestAddressSpace, GuestMemoryMmap}; /// @@ -538,8 +538,8 @@ impl<'a, B: BitmapSlice> VsockPacket<'a, B> { /// # let mut q = vq.create_queue().unwrap(); /// # /// # let v = vec![ - /// # Descriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - /// # Descriptor::new(0x8_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + /// # RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0)), + /// # RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, VRING_DESC_F_WRITE as u16, 0)), /// # ]; /// # let mut chain = vq.build_desc_chain(&v); /// # q @@ -684,8 +684,8 @@ mod tests { use vm_memory::{GuestAddress, GuestMemoryMmap}; use virtio_bindings::bindings::virtio_ring::VRING_DESC_F_WRITE; + use virtio_queue::desc::{split::Descriptor as SplitDescriptor, RawDescriptor}; use virtio_queue::mock::MockSplitQueue; - use virtio_queue::Descriptor; impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { @@ -734,8 +734,13 @@ mod tests { // The `build_desc_chain` function will populate the `NEXT` related flags and field. let v = vec![ // A device-readable packet header descriptor should be invalid. - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -746,13 +751,18 @@ mod tests { let v = vec![ // A header length < PKT_HEADER_SIZE is invalid. - Descriptor::new( + RawDescriptor::from(SplitDescriptor::new( 0x10_0000, PKT_HEADER_SIZE as u32 - 1, VRING_DESC_F_WRITE as u16, 0, - ), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + )), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -761,18 +771,18 @@ mod tests { ); let v = vec![ - Descriptor::new( + RawDescriptor::from(SplitDescriptor::new( 0x10_0000, PKT_HEADER_SIZE as u32, VRING_DESC_F_WRITE as u16, 0, - ), - Descriptor::new( + )), + RawDescriptor::from(SplitDescriptor::new( 0x20_0000, MAX_PKT_BUF_SIZE + 1, VRING_DESC_F_WRITE as u16, 0, - ), + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -782,12 +792,12 @@ mod tests { let v = vec![ // The data descriptor should always be present on the RX path. - Descriptor::new( + RawDescriptor::from(SplitDescriptor::new( 0x10_0000, PKT_HEADER_SIZE as u32, VRING_DESC_F_WRITE as u16, 0, - ), + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -796,8 +806,13 @@ mod tests { ); let v = vec![ - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -810,8 +825,18 @@ mod tests { let v = vec![ // The header doesn't fit entirely in the memory bounds. - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -822,8 +847,18 @@ mod tests { let v = vec![ // The header is outside the memory bounds. - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x30_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x30_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -834,9 +869,14 @@ mod tests { ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x5_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), // A device-readable packet data descriptor should be invalid. - Descriptor::new(0x8_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -844,9 +884,19 @@ mod tests { Error::UnexpectedReadOnlyDescriptor ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x5_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), // The data array doesn't fit entirely in the memory bounds. - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -855,9 +905,19 @@ mod tests { ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x5_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), // The data array is outside the memory bounds. - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -869,8 +929,18 @@ mod tests { // Let's also test a valid descriptor chain. let v = vec![ - Descriptor::new(0x5_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x8_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x5_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x8_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -899,12 +969,12 @@ mod tests { // Let's also test a valid descriptor chain, with both header and data on a single // descriptor. - let v = vec![Descriptor::new( + let v = vec![RawDescriptor::from(SplitDescriptor::new( 0x5_0000, PKT_HEADER_SIZE as u32 + 0x100, VRING_DESC_F_WRITE as u16, 0, - )]; + ))]; let mut chain = queue.build_desc_chain(&v).unwrap(); let packet = VsockPacket::from_rx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap(); @@ -933,8 +1003,13 @@ mod tests { // The `build_desc_chain` function will populate the `NEXT` related flags and field. let v = vec![ // A device-writable packet header descriptor should be invalid. - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x20_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -945,8 +1020,13 @@ mod tests { let v = vec![ // A header length < PKT_HEADER_SIZE is invalid. - Descriptor::new(0x10_0000, PKT_HEADER_SIZE as u32 - 1, 0, 0), - Descriptor::new(0x20_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + PKT_HEADER_SIZE as u32 - 1, + 0, + 0, + )), + RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -955,7 +1035,12 @@ mod tests { ); // On the TX path, it is allowed to not have a data descriptor. - let v = vec![Descriptor::new(0x10_0000, PKT_HEADER_SIZE as u32, 0, 0)]; + let v = vec![RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + PKT_HEADER_SIZE as u32, + 0, + 0, + ))]; let mut chain = queue.build_desc_chain(&v).unwrap(); let header = PacketHeader { @@ -987,8 +1072,8 @@ mod tests { let v = vec![ // The header doesn't fit entirely in the memory bounds. - Descriptor::new(0x10_0000, 0x100, 0, 0), - Descriptor::new(0x20_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -999,8 +1084,8 @@ mod tests { let v = vec![ // The header is outside the memory bounds. - Descriptor::new(0x20_0000, 0x100, 0, 0), - Descriptor::new(0x30_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x30_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1026,8 +1111,8 @@ mod tests { }; mem.write_obj(header, GuestAddress(0x5_0000)).unwrap(); let v = vec![ - Descriptor::new(0x5_0000, 0x100, 0, 0), - Descriptor::new(0x8_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1051,7 +1136,7 @@ mod tests { mem.write_obj(header, GuestAddress(0x5_0000)).unwrap(); let v = vec![ // The data descriptor is missing. - Descriptor::new(0x5_0000, PKT_HEADER_SIZE as u32, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, PKT_HEADER_SIZE as u32, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1060,9 +1145,9 @@ mod tests { ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), // The data array doesn't fit entirely in the memory bounds. - Descriptor::new(0x10_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x10_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1071,9 +1156,9 @@ mod tests { ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), // The data array is outside the memory bounds. - Descriptor::new(0x20_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x20_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1084,9 +1169,14 @@ mod tests { ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), // A device-writable packet data descriptor should be invalid. - Descriptor::new(0x8_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x8_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1095,9 +1185,9 @@ mod tests { ); let v = vec![ - Descriptor::new(0x5_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), // A data length < the length of data as described by the header. - Descriptor::new(0x8_0000, LEN - 1, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x8_0000, LEN - 1, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); assert_eq!( @@ -1107,8 +1197,8 @@ mod tests { // Let's also test a valid descriptor chain, with both header and data. let v = vec![ - Descriptor::new(0x5_0000, 0x100, 0, 0), - Descriptor::new(0x8_0000, 0x100, 0, 0), + RawDescriptor::from(SplitDescriptor::new(0x5_0000, 0x100, 0, 0)), + RawDescriptor::from(SplitDescriptor::new(0x8_0000, 0x100, 0, 0)), ]; let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -1139,12 +1229,12 @@ mod tests { // Let's also test a valid descriptor chain, with both header and data on a single // descriptor. - let v = vec![Descriptor::new( + let v = vec![RawDescriptor::from(SplitDescriptor::new( 0x5_0000, PKT_HEADER_SIZE as u32 + 0x100, 0, 0, - )]; + ))]; let mut chain = queue.build_desc_chain(&v).unwrap(); let packet = VsockPacket::from_tx_virtq_chain(&mem, &mut chain, MAX_PKT_BUF_SIZE).unwrap(); @@ -1173,8 +1263,18 @@ mod tests { GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x30_0000)]).unwrap(); // The `build_desc_chain` function will populate the `NEXT` related flags and field. let v = vec![ - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -1297,8 +1397,18 @@ mod tests { GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x30_0000)]).unwrap(); // The `build_desc_chain` function will populate the `NEXT` related flags and field. let v = vec![ - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap(); @@ -1385,8 +1495,18 @@ mod tests { GuestMemoryMmap::from_ranges(&[(GuestAddress(0), 0x30_0000)]).unwrap(); // The `build_desc_chain` function will populate the `NEXT` related flags and field. let v = vec![ - Descriptor::new(0x10_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), - Descriptor::new(0x20_0000, 0x100, VRING_DESC_F_WRITE as u16, 0), + RawDescriptor::from(SplitDescriptor::new( + 0x10_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), + RawDescriptor::from(SplitDescriptor::new( + 0x20_0000, + 0x100, + VRING_DESC_F_WRITE as u16, + 0, + )), ]; let queue = MockSplitQueue::new(&mem, 16); let mut chain = queue.build_desc_chain(&v).unwrap();