use std::io::{Read, Write};
use std::sync::atomic::Ordering;
use std::sync::Arc;
use vm_memory::bitmap::{Bitmap, BS};
use vm_memory::guest_memory::GuestMemoryIterator;
use vm_memory::mmap::{Error, NewBitmap};
use vm_memory::{
guest_memory, AtomicAccess, Bytes, FileOffset, GuestAddress, GuestMemory, GuestMemoryRegion,
GuestRegionMmap, GuestUsize, MemoryRegionAddress, VolatileSlice,
};
use crate::GuestRegionRaw;
#[derive(Debug)]
pub enum GuestRegionHybrid<B = ()> {
Mmap(GuestRegionMmap<B>),
Raw(GuestRegionRaw<B>),
}
impl<B: Bitmap> GuestRegionHybrid<B> {
pub fn from_mmap_region(region: GuestRegionMmap<B>) -> Self {
GuestRegionHybrid::Mmap(region)
}
pub fn from_raw_region(region: GuestRegionRaw<B>) -> Self {
GuestRegionHybrid::Raw(region)
}
}
impl<B: Bitmap> Bytes<MemoryRegionAddress> for GuestRegionHybrid<B> {
type E = guest_memory::Error;
fn write(&self, buf: &[u8], addr: MemoryRegionAddress) -> guest_memory::Result<usize> {
match self {
GuestRegionHybrid::Mmap(region) => region.write(buf, addr),
GuestRegionHybrid::Raw(region) => region.write(buf, addr),
}
}
fn read(&self, buf: &mut [u8], addr: MemoryRegionAddress) -> guest_memory::Result<usize> {
match self {
GuestRegionHybrid::Mmap(region) => region.read(buf, addr),
GuestRegionHybrid::Raw(region) => region.read(buf, addr),
}
}
fn write_slice(&self, buf: &[u8], addr: MemoryRegionAddress) -> guest_memory::Result<()> {
match self {
GuestRegionHybrid::Mmap(region) => region.write_slice(buf, addr),
GuestRegionHybrid::Raw(region) => region.write_slice(buf, addr),
}
}
fn read_slice(&self, buf: &mut [u8], addr: MemoryRegionAddress) -> guest_memory::Result<()> {
match self {
GuestRegionHybrid::Mmap(region) => region.read_slice(buf, addr),
GuestRegionHybrid::Raw(region) => region.read_slice(buf, addr),
}
}
fn read_from<F>(
&self,
addr: MemoryRegionAddress,
src: &mut F,
count: usize,
) -> guest_memory::Result<usize>
where
F: Read,
{
match self {
GuestRegionHybrid::Mmap(region) => region.read_from(addr, src, count),
GuestRegionHybrid::Raw(region) => region.read_from(addr, src, count),
}
}
fn read_exact_from<F>(
&self,
addr: MemoryRegionAddress,
src: &mut F,
count: usize,
) -> guest_memory::Result<()>
where
F: Read,
{
match self {
GuestRegionHybrid::Mmap(region) => region.read_exact_from(addr, src, count),
GuestRegionHybrid::Raw(region) => region.read_exact_from(addr, src, count),
}
}
fn write_to<F>(
&self,
addr: MemoryRegionAddress,
dst: &mut F,
count: usize,
) -> guest_memory::Result<usize>
where
F: Write,
{
match self {
GuestRegionHybrid::Mmap(region) => region.write_to(addr, dst, count),
GuestRegionHybrid::Raw(region) => region.write_to(addr, dst, count),
}
}
fn write_all_to<F>(
&self,
addr: MemoryRegionAddress,
dst: &mut F,
count: usize,
) -> guest_memory::Result<()>
where
F: Write,
{
match self {
GuestRegionHybrid::Mmap(region) => region.write_all_to(addr, dst, count),
GuestRegionHybrid::Raw(region) => region.write_all_to(addr, dst, count),
}
}
fn store<T: AtomicAccess>(
&self,
val: T,
addr: MemoryRegionAddress,
order: Ordering,
) -> guest_memory::Result<()> {
match self {
GuestRegionHybrid::Mmap(region) => region.store(val, addr, order),
GuestRegionHybrid::Raw(region) => region.store(val, addr, order),
}
}
fn load<T: AtomicAccess>(
&self,
addr: MemoryRegionAddress,
order: Ordering,
) -> guest_memory::Result<T> {
match self {
GuestRegionHybrid::Mmap(region) => region.load(addr, order),
GuestRegionHybrid::Raw(region) => region.load(addr, order),
}
}
}
impl<B: Bitmap> GuestMemoryRegion for GuestRegionHybrid<B> {
type B = B;
fn len(&self) -> GuestUsize {
match self {
GuestRegionHybrid::Mmap(region) => region.len(),
GuestRegionHybrid::Raw(region) => region.len(),
}
}
fn start_addr(&self) -> GuestAddress {
match self {
GuestRegionHybrid::Mmap(region) => region.start_addr(),
GuestRegionHybrid::Raw(region) => region.start_addr(),
}
}
fn bitmap(&self) -> &Self::B {
match self {
GuestRegionHybrid::Mmap(region) => region.bitmap(),
GuestRegionHybrid::Raw(region) => region.bitmap(),
}
}
fn get_host_address(&self, addr: MemoryRegionAddress) -> guest_memory::Result<*mut u8> {
match self {
GuestRegionHybrid::Mmap(region) => region.get_host_address(addr),
GuestRegionHybrid::Raw(region) => region.get_host_address(addr),
}
}
fn file_offset(&self) -> Option<&FileOffset> {
match self {
GuestRegionHybrid::Mmap(region) => region.file_offset(),
GuestRegionHybrid::Raw(region) => region.file_offset(),
}
}
unsafe fn as_slice(&self) -> Option<&[u8]> {
match self {
GuestRegionHybrid::Mmap(region) => region.as_slice(),
GuestRegionHybrid::Raw(region) => region.as_slice(),
}
}
unsafe fn as_mut_slice(&self) -> Option<&mut [u8]> {
match self {
GuestRegionHybrid::Mmap(region) => region.as_mut_slice(),
GuestRegionHybrid::Raw(region) => region.as_mut_slice(),
}
}
fn get_slice(
&self,
offset: MemoryRegionAddress,
count: usize,
) -> guest_memory::Result<VolatileSlice<BS<B>>> {
match self {
GuestRegionHybrid::Mmap(region) => region.get_slice(offset, count),
GuestRegionHybrid::Raw(region) => region.get_slice(offset, count),
}
}
#[cfg(target_os = "linux")]
fn is_hugetlbfs(&self) -> Option<bool> {
match self {
GuestRegionHybrid::Mmap(region) => region.is_hugetlbfs(),
GuestRegionHybrid::Raw(region) => region.is_hugetlbfs(),
}
}
}
#[derive(Clone, Debug, Default)]
pub struct GuestMemoryHybrid<B = ()> {
pub(crate) regions: Vec<Arc<GuestRegionHybrid<B>>>,
}
impl<B: NewBitmap> GuestMemoryHybrid<B> {
pub fn new() -> Self {
Self::default()
}
}
impl<B: Bitmap> GuestMemoryHybrid<B> {
pub fn from_regions(mut regions: Vec<GuestRegionHybrid<B>>) -> Result<Self, Error> {
Self::from_arc_regions(regions.drain(..).map(Arc::new).collect())
}
pub fn from_arc_regions(regions: Vec<Arc<GuestRegionHybrid<B>>>) -> Result<Self, Error> {
if regions.is_empty() {
return Err(Error::NoMemoryRegion);
}
for window in regions.windows(2) {
let prev = &window[0];
let next = &window[1];
if prev.start_addr() > next.start_addr() {
return Err(Error::UnsortedMemoryRegions);
}
if prev.last_addr() >= next.start_addr() {
return Err(Error::MemoryRegionOverlap);
}
}
Ok(Self { regions })
}
pub fn insert_region(
&self,
region: Arc<GuestRegionHybrid<B>>,
) -> Result<GuestMemoryHybrid<B>, Error> {
let mut regions = self.regions.clone();
regions.push(region);
regions.sort_by_key(|x| x.start_addr());
Self::from_arc_regions(regions)
}
pub fn remove_region(
&self,
base: GuestAddress,
size: GuestUsize,
) -> Result<(GuestMemoryHybrid<B>, Arc<GuestRegionHybrid<B>>), Error> {
if let Ok(region_index) = self.regions.binary_search_by_key(&base, |x| x.start_addr()) {
if self.regions.get(region_index).unwrap().len() as GuestUsize == size {
let mut regions = self.regions.clone();
let region = regions.remove(region_index);
return Ok((Self { regions }, region));
}
}
Err(Error::InvalidGuestRegion)
}
}
pub struct Iter<'a, B>(std::slice::Iter<'a, Arc<GuestRegionHybrid<B>>>);
impl<'a, B> Iterator for Iter<'a, B> {
type Item = &'a GuestRegionHybrid<B>;
fn next(&mut self) -> Option<Self::Item> {
self.0.next().map(AsRef::as_ref)
}
}
impl<'a, B: 'a> GuestMemoryIterator<'a, GuestRegionHybrid<B>> for GuestMemoryHybrid<B> {
type Iter = Iter<'a, B>;
}
impl<B: Bitmap + 'static> GuestMemory for GuestMemoryHybrid<B> {
type R = GuestRegionHybrid<B>;
type I = Self;
fn num_regions(&self) -> usize {
self.regions.len()
}
fn find_region(&self, addr: GuestAddress) -> Option<&GuestRegionHybrid<B>> {
let index = match self.regions.binary_search_by_key(&addr, |x| x.start_addr()) {
Ok(x) => Some(x),
Err(x) if (x > 0 && addr <= self.regions[x - 1].last_addr()) => Some(x - 1),
_ => None,
};
index.map(|x| self.regions[x].as_ref())
}
fn iter(&self) -> Iter<B> {
Iter(self.regions.iter())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::io::Seek;
use vm_memory::{GuestMemoryError, MmapRegion};
use vmm_sys_util::tempfile::TempFile;
#[test]
fn test_region_new() {
let start_addr = GuestAddress(0x0);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x400).unwrap(), start_addr).unwrap();
let guest_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
assert_eq!(guest_region.start_addr(), start_addr);
assert_eq!(guest_region.len(), 0x400);
let mut buf = [0u8; 1024];
let raw_region =
unsafe { GuestRegionRaw::<()>::new(start_addr, &mut buf as *mut _, 0x800) };
let guest_region = GuestRegionHybrid::from_raw_region(raw_region);
assert_eq!(guest_region.start_addr(), start_addr);
assert_eq!(guest_region.len(), 0x800);
}
#[test]
fn test_write_and_read_on_mmap_region() {
let start_addr = GuestAddress(0x0);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let buf_to_write = [0xF0u8; 0x400];
let write_addr = MemoryRegionAddress(0x400);
let number_of_bytes_write = guest_region.write(&buf_to_write, write_addr).unwrap();
assert_eq!(number_of_bytes_write, 0x400);
let mut buf_read = [0u8; 0x400];
let number_of_bytes_read = guest_region.read(&mut buf_read, write_addr).unwrap();
assert_eq!(number_of_bytes_read, 0x400);
assert_eq!(buf_read, [0xF0u8; 0x400]);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.write(&buf_to_write, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
assert!(matches!(
guest_region
.read(&mut buf_read, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_write_and_read_on_raw_region() {
let start_addr = GuestAddress(0x0);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_region = GuestRegionHybrid::from_raw_region(raw_region);
let buf_to_write = [0xF0u8; 0x400];
let write_addr = MemoryRegionAddress(0x400);
let number_of_bytes_write = guest_region.write(&buf_to_write, write_addr).unwrap();
assert_eq!(number_of_bytes_write, 0x400);
let mut buf_read = [0u8; 0x400];
let number_of_bytes_read = guest_region.read(&mut buf_read, write_addr).unwrap();
assert_eq!(number_of_bytes_read, 0x400);
assert_eq!(buf_read, [0xF0u8; 0x400]);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.write(&buf_to_write, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
assert!(matches!(
guest_region
.read(&mut buf_read, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_write_slice_and_read_slice_on_mmap_region() {
let start_addr = GuestAddress(0x0);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let buf_to_write = [0xF0u8; 0x400];
let write_addr = MemoryRegionAddress(0x400);
guest_region.write_slice(&buf_to_write, write_addr).unwrap();
let mut buf_read = [0x0u8; 0x400];
guest_region.read_slice(&mut buf_read, write_addr).unwrap();
assert_eq!(buf_read, [0xF0u8; 0x400]);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.write_slice(&buf_to_write, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let insufficient_addr = MemoryRegionAddress(0x600);
assert_eq!(
format!(
"{:?}",
guest_region
.write_slice(&buf_to_write, insufficient_addr)
.err()
.unwrap()
),
format!(
"PartialBuffer {{ expected: {:?}, completed: {:?} }}",
buf_to_write.len(),
guest_region.len() as usize - 0x600_usize
)
);
let invalid_addr = MemoryRegionAddress(0x900);
let mut buf_read = [0x0u8; 0x400];
assert!(matches!(
guest_region
.read_slice(&mut buf_read, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let insufficient_addr = MemoryRegionAddress(0x600);
let mut buf_read = [0x0u8; 0x400];
assert_eq!(
format!(
"{:?}",
guest_region
.read_slice(&mut buf_read, insufficient_addr)
.err()
.unwrap()
),
format!(
"PartialBuffer {{ expected: {:?}, completed: {:?} }}",
buf_to_write.len(),
guest_region.len() as usize - 0x600_usize
)
);
assert_eq!(
{
let mut buf = [0x0u8; 0x400];
for cell in buf.iter_mut().take(0x200) {
*cell = 0xF0;
}
buf
},
buf_read
);
}
#[test]
fn test_write_and_read_slice_on_raw_region() {
let start_addr = GuestAddress(0x0);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_region = GuestRegionHybrid::from_raw_region(raw_region);
let buf_to_write = [0xF0u8; 0x400];
let write_addr = MemoryRegionAddress(0x400);
guest_region.write_slice(&buf_to_write, write_addr).unwrap();
let mut buf_read = [0x0u8; 0x400];
guest_region.read_slice(&mut buf_read, write_addr).unwrap();
assert_eq!(buf_read, [0xF0u8; 0x400]);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.write_slice(&buf_to_write, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let insufficient_addr = MemoryRegionAddress(0x600);
assert_eq!(
format!(
"{:?}",
guest_region
.write_slice(&buf_to_write, insufficient_addr)
.err()
.unwrap()
),
format!(
"PartialBuffer {{ expected: {:?}, completed: {:?} }}",
buf_to_write.len(),
guest_region.len() as usize - 0x600_usize
)
);
let invalid_addr = MemoryRegionAddress(0x900);
let mut buf_read = [0x0u8; 0x400];
assert!(matches!(
guest_region
.read_slice(&mut buf_read, invalid_addr)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let insufficient_addr = MemoryRegionAddress(0x600);
let mut buf_read = [0x0u8; 0x400];
assert_eq!(
format!(
"{:?}",
guest_region
.read_slice(&mut buf_read, insufficient_addr)
.err()
.unwrap()
),
format!(
"PartialBuffer {{ expected: {:?}, completed: {:?} }}",
buf_to_write.len(),
guest_region.len() as usize - 0x600_usize
)
);
assert_eq!(
{
let mut buf = [0x0u8; 0x400];
for cell in buf.iter_mut().take(0x200) {
*cell = 0xF0;
}
buf
},
buf_read
);
}
#[test]
fn test_read_from_and_write_to_on_mmap_region() {
let start_addr = GuestAddress(0x0);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let write_addr = MemoryRegionAddress(0x400);
let original_content = b"hello world";
let size_of_file = original_content.len();
let mut file_to_write_mmap_region = TempFile::new().unwrap().into_file();
file_to_write_mmap_region
.set_len(size_of_file as u64)
.unwrap();
file_to_write_mmap_region
.write_all(original_content)
.unwrap();
file_to_write_mmap_region.rewind().unwrap();
guest_region
.read_from(write_addr, &mut file_to_write_mmap_region, size_of_file)
.unwrap();
let mut file_read_from_mmap_region = TempFile::new().unwrap().into_file();
file_read_from_mmap_region
.set_len(size_of_file as u64)
.unwrap();
guest_region
.write_all_to(write_addr, &mut file_read_from_mmap_region, size_of_file)
.unwrap();
file_read_from_mmap_region.rewind().unwrap();
let mut content = String::new();
file_read_from_mmap_region
.read_to_string(&mut content)
.unwrap();
assert_eq!(content.as_bytes(), original_content);
assert_eq!(
file_read_from_mmap_region.metadata().unwrap().len(),
size_of_file as u64
);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.read_from(invalid_addr, &mut file_to_write_mmap_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.write_to(invalid_addr, &mut file_read_from_mmap_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_read_from_and_write_to_on_raw_region() {
let start_addr = GuestAddress(0x0);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_region = GuestRegionHybrid::from_raw_region(raw_region);
let write_addr = MemoryRegionAddress(0x400);
let original_content = b"hello world";
let size_of_file = original_content.len();
let mut file_to_write_mmap_region = TempFile::new().unwrap().into_file();
file_to_write_mmap_region
.set_len(size_of_file as u64)
.unwrap();
file_to_write_mmap_region
.write_all(original_content)
.unwrap();
file_to_write_mmap_region.rewind().unwrap();
guest_region
.read_from(write_addr, &mut file_to_write_mmap_region, size_of_file)
.unwrap();
let mut file_read_from_mmap_region = TempFile::new().unwrap().into_file();
file_read_from_mmap_region
.set_len(size_of_file as u64)
.unwrap();
guest_region
.write_all_to(write_addr, &mut file_read_from_mmap_region, size_of_file)
.unwrap();
file_read_from_mmap_region.rewind().unwrap();
let mut content = String::new();
file_read_from_mmap_region
.read_to_string(&mut content)
.unwrap();
assert_eq!(content.as_bytes(), original_content);
assert_eq!(
file_read_from_mmap_region.metadata().unwrap().len(),
size_of_file as u64
);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.read_from(invalid_addr, &mut file_to_write_mmap_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region
.write_to(invalid_addr, &mut file_read_from_mmap_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_write_all_to_and_read_exact_from() {
let start_addr = GuestAddress(0x0);
let write_addr = MemoryRegionAddress(0x400);
let original_content = b"hello world";
let size_of_file = original_content.len();
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_mmap_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_raw_region = GuestRegionHybrid::from_raw_region(raw_region);
let mut file_to_write_mmap_region = TempFile::new().unwrap().into_file();
file_to_write_mmap_region
.set_len(size_of_file as u64)
.unwrap();
file_to_write_mmap_region
.write_all(original_content)
.unwrap();
file_to_write_mmap_region.rewind().unwrap();
guest_mmap_region
.read_exact_from(write_addr, &mut file_to_write_mmap_region, size_of_file)
.unwrap();
let mut file_read_from_mmap_region = TempFile::new().unwrap().into_file();
file_read_from_mmap_region
.set_len(size_of_file as u64)
.unwrap();
guest_mmap_region
.write_all_to(write_addr, &mut file_read_from_mmap_region, size_of_file)
.unwrap();
file_read_from_mmap_region.rewind().unwrap();
let mut content = String::new();
file_read_from_mmap_region
.read_to_string(&mut content)
.unwrap();
assert_eq!(content.as_bytes(), original_content);
assert_eq!(
file_read_from_mmap_region.metadata().unwrap().len(),
size_of_file as u64
);
let mut file_to_write_raw_region = TempFile::new().unwrap().into_file();
file_to_write_raw_region
.set_len(size_of_file as u64)
.unwrap();
file_to_write_raw_region
.write_all(original_content)
.unwrap();
file_to_write_raw_region.rewind().unwrap();
guest_raw_region
.read_exact_from(write_addr, &mut file_to_write_raw_region, size_of_file)
.unwrap();
let mut file_read_from_raw_region = TempFile::new().unwrap().into_file();
file_read_from_raw_region
.set_len(size_of_file as u64)
.unwrap();
guest_raw_region
.write_all_to(write_addr, &mut file_read_from_raw_region, size_of_file)
.unwrap();
file_read_from_raw_region.rewind().unwrap();
let mut content = String::new();
file_read_from_raw_region
.read_to_string(&mut content)
.unwrap();
assert_eq!(content.as_bytes(), original_content);
assert_eq!(
file_read_from_raw_region.metadata().unwrap().len(),
size_of_file as u64
);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_mmap_region
.read_exact_from(invalid_addr, &mut file_to_write_mmap_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_mmap_region
.write_all_to(invalid_addr, &mut file_read_from_mmap_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_raw_region
.read_exact_from(invalid_addr, &mut file_to_write_raw_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_raw_region
.write_all_to(invalid_addr, &mut file_read_from_raw_region, size_of_file)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_store_and_load() {
let test_val = 0xFF;
let start_addr = GuestAddress(0x0);
let write_addr = MemoryRegionAddress(0x400);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_mmap_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_raw_region = GuestRegionHybrid::from_raw_region(raw_region);
guest_mmap_region
.store(test_val, write_addr, Ordering::Relaxed)
.unwrap();
let val_read_from_mmap_region: u64 = guest_mmap_region
.load(write_addr, Ordering::Relaxed)
.unwrap();
assert_eq!(val_read_from_mmap_region, test_val);
guest_raw_region
.store(test_val, write_addr, Ordering::Relaxed)
.unwrap();
let val_read_from_raw_region: u64 = guest_raw_region
.load(write_addr, Ordering::Relaxed)
.unwrap();
assert_eq!(val_read_from_raw_region, test_val);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_mmap_region
.store(test_val, invalid_addr, Ordering::Relaxed)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_raw_region
.store(test_val, invalid_addr, Ordering::Relaxed)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
assert!(matches!(
guest_mmap_region
.load::<u64>(invalid_addr, Ordering::Relaxed)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
assert!(matches!(
guest_raw_region
.load::<u64>(invalid_addr, Ordering::Relaxed)
.err()
.unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_bitmap() {
let start_addr = GuestAddress(0x0);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_mmap_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_raw_region = GuestRegionHybrid::from_raw_region(raw_region);
assert_eq!(guest_mmap_region.bitmap(), guest_raw_region.bitmap());
}
#[test]
fn test_get_host_address_on_mmap_region() {
let start_addr = GuestAddress(0x0);
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x800).unwrap(), start_addr).unwrap();
let guest_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let addr_1 = guest_region
.get_host_address(MemoryRegionAddress(0x0))
.unwrap();
let addr_2 = guest_region
.get_host_address(MemoryRegionAddress(0x400))
.unwrap();
assert_eq!(addr_1 as u64 + 0x400, addr_2 as u64);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region.get_host_address(invalid_addr).err().unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_get_host_address_on_raw_region() {
let start_addr = GuestAddress(0x0);
let mut buf_of_raw_region = [0u8; 0x800];
let raw_region = unsafe {
GuestRegionRaw::<()>::new(start_addr, &mut buf_of_raw_region as *mut _, 0x800)
};
let guest_region = GuestRegionHybrid::from_raw_region(raw_region);
let addr_1 = guest_region
.get_host_address(MemoryRegionAddress(0x0))
.unwrap();
let addr_2 = guest_region
.get_host_address(MemoryRegionAddress(0x400))
.unwrap();
assert_eq!(addr_1 as u64 + 0x400, addr_2 as u64);
let invalid_addr = MemoryRegionAddress(0x900);
assert!(matches!(
guest_region.get_host_address(invalid_addr).err().unwrap(),
GuestMemoryError::InvalidBackendAddress
));
}
#[test]
fn test_guest_memory_mmap_get_slice() {
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x400).unwrap(), GuestAddress(0)).unwrap();
let guest_mmap_region = GuestRegionHybrid::from_mmap_region(mmap_reg);
let slice_addr = MemoryRegionAddress(0x100);
let slice_size = 0x200;
let slice = guest_mmap_region.get_slice(slice_addr, slice_size).unwrap();
assert_eq!(slice.len(), slice_size);
let slice_addr = MemoryRegionAddress(0x200);
let slice_size = 0x0;
let slice = guest_mmap_region.get_slice(slice_addr, slice_size).unwrap();
assert!(slice.is_empty());
let slice_addr = MemoryRegionAddress(0x300);
let slice_size = 0x200;
assert!(guest_mmap_region.get_slice(slice_addr, slice_size).is_err());
}
#[test]
fn test_from_regions_on_guest_memory_hybrid() {
let mut regions = Vec::<GuestRegionHybrid<()>>::new();
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x100).unwrap(), GuestAddress(0x100))
.unwrap();
regions.push(GuestRegionHybrid::Mmap(mmap_reg));
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x100).unwrap(), GuestAddress(0x200))
.unwrap();
regions.push(GuestRegionHybrid::Mmap(mmap_reg));
let guest_region = GuestMemoryHybrid::<()>::from_regions(regions).unwrap();
assert_eq!(guest_region.regions[0].start_addr(), GuestAddress(0x100));
assert_eq!(guest_region.regions[1].start_addr(), GuestAddress(0x200));
let mut regions = Vec::<GuestRegionHybrid<()>>::new();
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x400).unwrap(), GuestAddress(0x200))
.unwrap();
regions.push(GuestRegionHybrid::Mmap(mmap_reg));
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x400).unwrap(), GuestAddress(0x100))
.unwrap();
regions.push(GuestRegionHybrid::Mmap(mmap_reg));
let guest_region = GuestMemoryHybrid::<()>::from_regions(regions);
assert!(matches!(
guest_region.err().unwrap(),
Error::UnsortedMemoryRegions
));
let regions = Vec::<GuestRegionHybrid<()>>::new();
let guest_region = GuestMemoryHybrid::<()>::from_regions(regions);
assert!(matches!(guest_region.err().unwrap(), Error::NoMemoryRegion));
}
#[test]
fn test_iterator_on_guest_region_hybrid() {
let mut regions = Vec::<GuestRegionHybrid<()>>::new();
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x100).unwrap(), GuestAddress(0x100))
.unwrap();
regions.push(GuestRegionHybrid::Mmap(mmap_reg));
let mmap_reg =
GuestRegionMmap::new(MmapRegion::<()>::new(0x100).unwrap(), GuestAddress(0x200))
.unwrap();
regions.push(GuestRegionHybrid::Mmap(mmap_reg));
let guest_region = GuestMemoryHybrid::<()>::from_regions(regions).unwrap();
let mut region = guest_region.iter();
assert_eq!(region.next().unwrap().start_addr(), GuestAddress(0x100));
assert_eq!(region.next().unwrap().start_addr(), GuestAddress(0x200));
}
}