blob: 2e9bac18c5b41ee9953997195bfd87121d863fb2 [file] [log] [blame]
// Portions Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-BSD-3-Clause file.
//
// Copyright (C) 2024 Red Hat, Inc. All rights reserved.
//
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
use std::collections::VecDeque;
use std::io::{self, Read, Write};
use std::mem::{size_of, MaybeUninit};
use std::ops::Deref;
use std::ptr::copy_nonoverlapping;
use std::{cmp, result};
use crate::{DescriptorChain, Error};
use vm_memory::bitmap::{BitmapSlice, WithBitmapSlice};
use vm_memory::{
Address, ByteValued, GuestMemory, GuestMemoryRegion, MemoryRegionAddress, VolatileSlice,
};
pub type Result<T> = result::Result<T, Error>;
#[derive(Clone)]
struct DescriptorChainConsumer<'a, B> {
buffers: VecDeque<VolatileSlice<'a, B>>,
bytes_consumed: usize,
}
impl<'a, B: BitmapSlice> DescriptorChainConsumer<'a, B> {
fn available_bytes(&self) -> usize {
// This is guaranteed not to overflow because the total length of the chain
// is checked during all creations of `DescriptorChainConsumer` (see
// `Reader::new()` and `Writer::new()`).
self.buffers
.iter()
.fold(0usize, |count, vs| count + vs.len())
}
fn bytes_consumed(&self) -> usize {
self.bytes_consumed
}
/// Consumes at most `count` bytes from the `DescriptorChain`. Callers must provide a function
/// that takes a `&[VolatileSlice]` and returns the total number of bytes consumed. This
/// function guarantees that the combined length of all the slices in the `&[VolatileSlice]` is
/// less than or equal to `count`.
///
/// # Errors
///
/// If the provided function returns any error then no bytes are consumed from the buffer and
/// the error is returned to the caller.
fn consume<F>(&mut self, count: usize, f: F) -> io::Result<usize>
where
F: FnOnce(&[&VolatileSlice<B>]) -> io::Result<usize>,
{
let mut buflen = 0;
let mut bufs = Vec::with_capacity(self.buffers.len());
for vs in &self.buffers {
if buflen >= count {
break;
}
bufs.push(vs);
let rem = count - buflen;
if rem < vs.len() {
buflen += rem;
} else {
buflen += vs.len();
}
}
if bufs.is_empty() {
return Ok(0);
}
let bytes_consumed = f(&bufs)?;
// This can happen if a driver tricks a device into reading/writing more data than
// fits in a `usize`.
let total_bytes_consumed =
self.bytes_consumed
.checked_add(bytes_consumed)
.ok_or_else(|| {
io::Error::new(io::ErrorKind::InvalidData, Error::DescriptorChainOverflow)
})?;
let mut rem = bytes_consumed;
while let Some(vs) = self.buffers.pop_front() {
if rem < vs.len() {
// Split the slice and push the remainder back into the buffer list. Safe because we
// know that `rem` is not out of bounds due to the check and we checked the bounds
// on `vs` when we added it to the buffer list.
self.buffers.push_front(vs.offset(rem).unwrap());
break;
}
// No need for checked math because we know that `vs.size() <= rem`.
rem -= vs.len();
}
self.bytes_consumed = total_bytes_consumed;
Ok(bytes_consumed)
}
fn split_at(&mut self, offset: usize) -> Result<DescriptorChainConsumer<'a, B>> {
let mut rem = offset;
let pos = self.buffers.iter().position(|vs| {
if rem < vs.len() {
true
} else {
rem -= vs.len();
false
}
});
if let Some(at) = pos {
let mut other = self.buffers.split_off(at);
if rem > 0 {
// There must be at least one element in `other` because we checked
// its `size` value in the call to `position` above.
let front = other.pop_front().expect("empty VecDeque after split");
self.buffers
.push_back(front.subslice(0, rem).map_err(Error::VolatileMemoryError)?);
other.push_front(front.offset(rem).map_err(Error::VolatileMemoryError)?);
}
Ok(DescriptorChainConsumer {
buffers: other,
bytes_consumed: 0,
})
} else if rem == 0 {
Ok(DescriptorChainConsumer {
buffers: VecDeque::new(),
bytes_consumed: 0,
})
} else {
Err(Error::SplitOutOfBounds(offset))
}
}
}
/// Provides high-level interface over the sequence of memory regions
/// defined by readable descriptors in the descriptor chain.
///
/// Note that virtio spec requires driver to place any device-writable
/// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1).
/// Reader will skip iterating over descriptor chain when first writable
/// descriptor is encountered.
#[derive(Clone)]
pub struct Reader<'a, B = ()> {
buffer: DescriptorChainConsumer<'a, B>,
}
impl<'a, B: BitmapSlice> Reader<'a, B> {
/// Construct a new Reader wrapper over `desc_chain`.
pub fn new<M, T>(mem: &'a M, desc_chain: DescriptorChain<T>) -> Result<Reader<'a, B>>
where
M: GuestMemory,
<<M as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
T: Deref,
T::Target: GuestMemory + Sized,
{
let mut total_len: usize = 0;
let buffers = desc_chain
.readable()
.map(|desc| {
// Verify that summing the descriptor sizes does not overflow.
// This can happen if a driver tricks a device into reading more data than
// fits in a `usize`.
total_len = total_len
.checked_add(desc.len() as usize)
.ok_or(Error::DescriptorChainOverflow)?;
let region = mem
.find_region(desc.addr())
.ok_or(Error::FindMemoryRegion)?;
let offset = desc
.addr()
.checked_sub(region.start_addr().raw_value())
.unwrap();
region
.get_slice(MemoryRegionAddress(offset.raw_value()), desc.len() as usize)
.map_err(Error::GuestMemoryError)
})
.collect::<Result<VecDeque<VolatileSlice<'a, B>>>>()?;
Ok(Reader {
buffer: DescriptorChainConsumer {
buffers,
bytes_consumed: 0,
},
})
}
/// Reads an object from the descriptor chain buffer.
pub fn read_obj<T: ByteValued>(&mut self) -> io::Result<T> {
let mut obj = MaybeUninit::<T>::uninit();
// SAFETY: `MaybeUninit` guarantees that the pointer is valid for
// `size_of::<T>()` bytes.
let buf = unsafe {
::std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::<T>())
};
self.read_exact(buf)?;
// SAFETY: any type that implements `ByteValued` can be considered initialized
// even if it is filled with random data.
Ok(unsafe { obj.assume_init() })
}
/// Returns number of bytes available for reading. May return an error if the combined
/// lengths of all the buffers in the DescriptorChain would cause an integer overflow.
pub fn available_bytes(&self) -> usize {
self.buffer.available_bytes()
}
/// Returns number of bytes already read from the descriptor chain buffer.
pub fn bytes_read(&self) -> usize {
self.buffer.bytes_consumed()
}
/// Splits this `Reader` into two at the given offset in the `DescriptorChain` buffer.
/// After the split, `self` will be able to read up to `offset` bytes while the returned
/// `Reader` can read up to `available_bytes() - offset` bytes. Returns an error if
/// `offset > self.available_bytes()`.
pub fn split_at(&mut self, offset: usize) -> Result<Reader<'a, B>> {
self.buffer.split_at(offset).map(|buffer| Reader { buffer })
}
}
impl<'a, B: BitmapSlice> io::Read for Reader<'a, B> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.buffer.consume(buf.len(), |bufs| {
let mut rem = buf;
let mut total = 0;
for vs in bufs {
let copy_len = cmp::min(rem.len(), vs.len());
// SAFETY: Safe because we verify that we do not read outside
// of the slice's bound. The slice guard will only get dropped
// after the function returns. This will keep the pointer valid
// while reads are happening.
unsafe {
copy_nonoverlapping(vs.ptr_guard().as_ptr(), rem.as_mut_ptr(), copy_len);
}
rem = &mut rem[copy_len..];
total += copy_len;
}
Ok(total)
})
}
}
/// Provides high-level interface over the sequence of memory regions
/// defined by writable descriptors in the descriptor chain.
///
/// Note that virtio spec requires driver to place any device-writable
/// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1).
/// Writer will start iterating the descriptors from the first writable one and will
/// assume that all following descriptors are writable.
#[derive(Clone)]
pub struct Writer<'a, B = ()> {
buffer: DescriptorChainConsumer<'a, B>,
}
impl<'a, B: BitmapSlice> Writer<'a, B> {
/// Construct a new Writer wrapper over `desc_chain`.
pub fn new<M, T>(mem: &'a M, desc_chain: DescriptorChain<T>) -> Result<Writer<'a, B>>
where
M: GuestMemory,
<<M as GuestMemory>::R as GuestMemoryRegion>::B: WithBitmapSlice<'a, S = B>,
T: Deref,
T::Target: GuestMemory + Sized,
{
let mut total_len: usize = 0;
let buffers = desc_chain
.writable()
.map(|desc| {
// Verify that summing the descriptor sizes does not overflow.
// This can happen if a driver tricks a device into writing more data than
// fits in a `usize`.
total_len = total_len
.checked_add(desc.len() as usize)
.ok_or(Error::DescriptorChainOverflow)?;
let region = mem
.find_region(desc.addr())
.ok_or(Error::FindMemoryRegion)?;
let offset = desc
.addr()
.checked_sub(region.start_addr().raw_value())
.unwrap();
region
.get_slice(MemoryRegionAddress(offset.raw_value()), desc.len() as usize)
.map_err(Error::GuestMemoryError)
})
.collect::<Result<VecDeque<VolatileSlice<'a, B>>>>()?;
Ok(Writer {
buffer: DescriptorChainConsumer {
buffers,
bytes_consumed: 0,
},
})
}
/// Writes an object to the descriptor chain buffer.
pub fn write_obj<T: ByteValued>(&mut self, val: T) -> io::Result<()> {
self.write_all(val.as_slice())
}
/// Returns number of bytes available for writing. May return an error if the combined
/// lengths of all the buffers in the DescriptorChain would cause an overflow.
pub fn available_bytes(&self) -> usize {
self.buffer.available_bytes()
}
/// Returns number of bytes already written to the descriptor chain buffer.
pub fn bytes_written(&self) -> usize {
self.buffer.bytes_consumed()
}
/// Splits this `Writer` into two at the given offset in the `DescriptorChain` buffer.
/// After the split, `self` will be able to write up to `offset` bytes while the returned
/// `Writer` can write up to `available_bytes() - offset` bytes. Returns an error if
/// `offset > self.available_bytes()`.
pub fn split_at(&mut self, offset: usize) -> Result<Writer<'a, B>> {
self.buffer.split_at(offset).map(|buffer| Writer { buffer })
}
}
impl<'a, B: BitmapSlice> io::Write for Writer<'a, B> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.buffer.consume(buf.len(), |bufs| {
let mut rem = buf;
let mut total = 0;
for vs in bufs {
let copy_len = cmp::min(rem.len(), vs.len());
// SAFETY: Safe because we ensure that we do not write over the
// slice's bounds. The slice guard will only get dropped after
// the function returns. This will keep the pointer valid while
// writes are happening.
unsafe {
copy_nonoverlapping(rem.as_ptr(), vs.ptr_guard_mut().as_ptr(), copy_len);
}
vs.bitmap().mark_dirty(0, copy_len);
rem = &rem[copy_len..];
total += copy_len;
}
Ok(total)
})
}
fn flush(&mut self) -> io::Result<()> {
// Nothing to flush since the writes go straight into the buffer.
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Descriptor, Queue, QueueOwnedT, QueueT};
use vm_memory::{GuestAddress, GuestMemoryMmap, Le32};
use crate::mock::MockSplitQueue;
use virtio_bindings::bindings::virtio_ring::{VRING_DESC_F_NEXT, VRING_DESC_F_WRITE};
const MAX_QUEUE_SIZE: u16 = 16;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum DescriptorType {
Readable,
Writable,
}
/// Test utility function to create a descriptor chain in guest memory.
pub fn create_descriptor_chain(
memory: &GuestMemoryMmap,
descriptor_array_addr: GuestAddress,
descriptors: Vec<(DescriptorType, u32)>,
spaces_between_regions: u32,
) -> Result<DescriptorChain<&GuestMemoryMmap>> {
let descriptors_len = descriptors.len();
let mut descs = vec![];
let queue = MockSplitQueue::create(memory, descriptor_array_addr, MAX_QUEUE_SIZE);
let mut buffers_start_addr = queue.end();
for (index, (type_, size)) in descriptors.into_iter().enumerate() {
let mut flags = 0;
if let DescriptorType::Writable = type_ {
flags |= VRING_DESC_F_WRITE;
}
if index + 1 < descriptors_len {
flags |= VRING_DESC_F_NEXT;
}
descs.push(Descriptor::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
.checked_add(u64::from(offset))
.ok_or(Error::InvalidChain)?;
}
queue.build_desc_chain(&descs).unwrap();
let avail_ring = queue.avail_addr();
let mut queue: Queue = Queue::new(MAX_QUEUE_SIZE).unwrap();
queue
.try_set_desc_table_address(descriptor_array_addr)
.unwrap();
queue.try_set_avail_ring_address(avail_ring).unwrap();
queue.set_ready(true);
let chain = queue.iter(memory).unwrap().next().unwrap();
Ok(chain.clone())
}
#[test]
fn reader_test_inv_desc_addr() {
let memory: GuestMemoryMmap =
GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), 0x1000)]).unwrap();
let queue = MockSplitQueue::create(&memory, GuestAddress(0x0), MAX_QUEUE_SIZE);
// set addr out of memory
let descriptor = Descriptor::new(0x1001, 1, 0, 1_u16);
queue.build_desc_chain(&[descriptor]).unwrap();
let avail_ring = queue.avail_addr();
let mut queue: Queue = Queue::new(MAX_QUEUE_SIZE).unwrap();
queue.try_set_desc_table_address(GuestAddress(0x0)).unwrap();
queue.try_set_avail_ring_address(avail_ring).unwrap();
queue.set_ready(true);
let chain = queue.iter(&memory).unwrap().next().unwrap();
assert!(Reader::new(&memory, chain).is_err());
}
#[test]
fn reader_test_simple_chain() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 8),
(Readable, 16),
(Readable, 18),
(Readable, 64),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
assert_eq!(reader.available_bytes(), 106);
assert_eq!(reader.bytes_read(), 0);
let mut buffer = [0_u8; 64];
if let Err(e) = reader.read_exact(&mut buffer) {
panic!("read_exact should not fail here: {:?}", e);
}
assert_eq!(reader.available_bytes(), 42);
assert_eq!(reader.bytes_read(), 64);
match reader.read(&mut buffer) {
Err(e) => panic!("read should not fail here: {:?}", e),
Ok(length) => assert_eq!(length, 42),
}
assert_eq!(reader.available_bytes(), 0);
assert_eq!(reader.bytes_read(), 106);
}
#[test]
fn writer_test_simple_chain() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Writable, 8),
(Writable, 16),
(Writable, 18),
(Writable, 64),
],
0,
)
.expect("create_descriptor_chain failed");
let mut writer = Writer::new(&memory, chain).expect("failed to create Writer");
assert_eq!(writer.available_bytes(), 106);
assert_eq!(writer.bytes_written(), 0);
let buffer = [0_u8; 64];
if let Err(e) = writer.write_all(&buffer) {
panic!("write_all should not fail here: {:?}", e);
}
assert_eq!(writer.available_bytes(), 42);
assert_eq!(writer.bytes_written(), 64);
match writer.write(&buffer) {
Err(e) => panic!("write should not fail here {:?}", e),
Ok(length) => assert_eq!(length, 42),
}
assert_eq!(writer.available_bytes(), 0);
assert_eq!(writer.bytes_written(), 106);
}
#[test]
fn reader_test_incompatible_chain() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(&memory, GuestAddress(0x0), vec![(Writable, 8)], 0)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
assert_eq!(reader.available_bytes(), 0);
assert_eq!(reader.bytes_read(), 0);
assert!(reader.read_obj::<u8>().is_err());
assert_eq!(reader.available_bytes(), 0);
assert_eq!(reader.bytes_read(), 0);
}
#[test]
fn writer_test_incompatible_chain() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(&memory, GuestAddress(0x0), vec![(Readable, 8)], 0)
.expect("create_descriptor_chain failed");
let mut writer = Writer::new(&memory, chain).expect("failed to create Writer");
assert_eq!(writer.available_bytes(), 0);
assert_eq!(writer.bytes_written(), 0);
assert!(writer.write_obj(0u8).is_err());
assert_eq!(writer.available_bytes(), 0);
assert_eq!(writer.bytes_written(), 0);
}
#[test]
fn reader_writer_shared_chain() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 16),
(Readable, 16),
(Readable, 96),
(Writable, 64),
(Writable, 1),
(Writable, 3),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain.clone()).expect("failed to create Reader");
let mut writer = Writer::new(&memory, chain).expect("failed to create Writer");
assert_eq!(reader.bytes_read(), 0);
assert_eq!(writer.bytes_written(), 0);
let mut buffer = Vec::with_capacity(200);
assert_eq!(
reader
.read_to_end(&mut buffer)
.expect("read should not fail here"),
128
);
// The writable descriptors are only 68 bytes long.
writer
.write_all(&buffer[..68])
.expect("write should not fail here");
assert_eq!(reader.available_bytes(), 0);
assert_eq!(reader.bytes_read(), 128);
assert_eq!(writer.available_bytes(), 0);
assert_eq!(writer.bytes_written(), 68);
}
#[test]
fn reader_writer_shattered_object() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let secret: Le32 = 0x1234_5678.into();
// Create a descriptor chain with memory regions that are properly separated.
let chain_writer = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![(Writable, 1), (Writable, 1), (Writable, 1), (Writable, 1)],
123,
)
.expect("create_descriptor_chain failed");
let mut writer = Writer::new(&memory, chain_writer).expect("failed to create Writer");
if let Err(e) = writer.write_obj(secret) {
panic!("write_obj should not fail here: {:?}", e);
}
// Now create new descriptor chain pointing to the same memory and try to read it.
let chain_reader = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![(Readable, 1), (Readable, 1), (Readable, 1), (Readable, 1)],
123,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain_reader).expect("failed to create Reader");
match reader.read_obj::<Le32>() {
Err(e) => panic!("read_obj should not fail here: {:?}", e),
Ok(read_secret) => assert_eq!(read_secret, secret),
}
}
#[test]
fn reader_unexpected_eof() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![(Readable, 256), (Readable, 256)],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
let mut buf = vec![0; 1024];
assert_eq!(
reader
.read_exact(&mut buf[..])
.expect_err("read more bytes than available")
.kind(),
io::ErrorKind::UnexpectedEof
);
}
#[test]
fn split_border() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 16),
(Readable, 16),
(Readable, 96),
(Writable, 64),
(Writable, 1),
(Writable, 3),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain.clone()).expect("failed to create Reader");
let other = reader.split_at(32).expect("failed to split Reader");
assert_eq!(reader.available_bytes(), 32);
assert_eq!(other.available_bytes(), 96);
let mut writer = Writer::new(&memory, chain.clone()).expect("failed to create Writer");
let other = writer.split_at(64).expect("failed to split Writer");
assert_eq!(writer.available_bytes(), 64);
assert_eq!(other.available_bytes(), 4);
}
#[test]
fn split_middle() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 16),
(Readable, 16),
(Readable, 96),
(Writable, 64),
(Writable, 1),
(Writable, 3),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
let other = reader.split_at(24).expect("failed to split Reader");
assert_eq!(reader.available_bytes(), 24);
assert_eq!(other.available_bytes(), 104);
}
#[test]
fn split_end() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 16),
(Readable, 16),
(Readable, 96),
(Writable, 64),
(Writable, 1),
(Writable, 3),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
let other = reader.split_at(128).expect("failed to split Reader");
assert_eq!(reader.available_bytes(), 128);
assert_eq!(other.available_bytes(), 0);
}
#[test]
fn split_beginning() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 16),
(Readable, 16),
(Readable, 96),
(Writable, 64),
(Writable, 1),
(Writable, 3),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
let other = reader.split_at(0).expect("failed to split Reader");
assert_eq!(reader.available_bytes(), 0);
assert_eq!(other.available_bytes(), 128);
}
#[test]
fn split_outofbounds() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![
(Readable, 16),
(Readable, 16),
(Readable, 96),
(Writable, 64),
(Writable, 1),
(Writable, 3),
],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
if reader.split_at(256).is_ok() {
panic!("successfully split Reader with out of bounds offset");
}
}
#[test]
fn read_full() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![(Readable, 16), (Readable, 16), (Readable, 16)],
0,
)
.expect("create_descriptor_chain failed");
let mut reader = Reader::new(&memory, chain).expect("failed to create Reader");
let mut buf = [0u8; 64];
assert_eq!(
reader.read(&mut buf[..]).expect("failed to read to buffer"),
48
);
}
#[test]
fn write_full() {
use DescriptorType::*;
let memory_start_addr = GuestAddress(0x0);
let memory = GuestMemoryMmap::from_ranges(&[(memory_start_addr, 0x10000)]).unwrap();
let chain = create_descriptor_chain(
&memory,
GuestAddress(0x0),
vec![(Writable, 16), (Writable, 16), (Writable, 16)],
0,
)
.expect("create_descriptor_chain failed");
let mut writer = Writer::new(&memory, chain).expect("failed to create Writer");
let buf = [0xdeu8; 64];
assert_eq!(
writer.write(&buf[..]).expect("failed to write from buffer"),
48
);
assert!(writer.flush().is_ok());
}
}