Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions src/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the THIRD-PARTY file.

//! Define the ByteValued trait to mark that it is safe to instantiate the struct with random data.
//! Traits to initialize and access a range of byte-addressable content.

use std::io::{Read, Write};
use std::mem::size_of;
Expand Down Expand Up @@ -101,7 +101,7 @@ pub unsafe trait ByteValued: Copy + Default + Send + Sync {
}
}

/// A container to host a range of bytes and access its content.
/// Trait to access a range of byte-addressable content.
///
/// Candidates which may implement this trait include:
/// - anonymous memory areas
Expand Down Expand Up @@ -192,17 +192,17 @@ pub trait Bytes<A> {
}

// All intrinsic types and arrays of intrinsic types are ByteValued. They are just numbers.
macro_rules! array_data_init {
macro_rules! array_byte_valued {
($T:ty, $($N:expr)+) => {
$(
unsafe impl ByteValued for [$T; $N] {}
)+
}
}
macro_rules! data_init_type {
macro_rules! byte_valued_type {
($T:ty) => {
unsafe impl ByteValued for $T {}
array_data_init! {
array_byte_valued! {
$T,
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
Expand All @@ -211,16 +211,16 @@ macro_rules! data_init_type {
}
};
}
data_init_type!(u8);
data_init_type!(u16);
data_init_type!(u32);
data_init_type!(u64);
data_init_type!(usize);
data_init_type!(i8);
data_init_type!(i16);
data_init_type!(i32);
data_init_type!(i64);
data_init_type!(isize);
byte_valued_type!(u8);
byte_valued_type!(u16);
byte_valued_type!(u32);
byte_valued_type!(u64);
byte_valued_type!(usize);
byte_valued_type!(i8);
byte_valued_type!(i16);
byte_valued_type!(i32);
byte_valued_type!(i64);
byte_valued_type!(isize);

#[cfg(test)]
mod tests {
Expand Down
85 changes: 26 additions & 59 deletions src/guest_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ pub type GuestUsize = <GuestAddress as AddressValue>::V;
/// Represents a continuous region of guest physical memory.
#[allow(clippy::len_without_is_empty)]
pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
/// True if the guest memory is mapped into the current process and supports direct access.
const DIRECT_ACCESS: bool;

/// Get the size of the region.
fn len(&self) -> GuestUsize;

Expand Down Expand Up @@ -175,6 +178,11 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
unsafe fn as_mut_slice(&self) -> Option<&mut [u8]> {
None
}

/// Convert an absolute address in an address space (GuestMemory) to a host pointer,
/// or return None if it is out of bounds. It always returns None when `DIRECT_ACCESS` is false.
/// The returned pointer may be used for ioctls etc.
fn get_host_address(&self, addr: MemoryRegionAddress) -> Option<*mut u8>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be implemented in terms of as_mut_slice(). Also please make the result Option<NonNull<u8>>.

}

/// Represents a container for a collection of GuestMemoryRegion objects.
Expand All @@ -185,73 +193,27 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
/// - handle cases where an access request spanning two or more GuestMemoryRegion objects.
///
/// Note: all regions in a GuestMemory object must not intersect with each other.
pub trait GuestMemory {
/// Type of objects hosted by the address space.
type R: GuestMemoryRegion;
pub trait GuestMemory<'a>: Clone {
/// True if the guest memory is mapped into the current process and supports direct access.
const DIRECT_ACCESS: bool = Self::R::DIRECT_ACCESS;

/// Type of objects hosted by the collection.
type R: 'a + GuestMemoryRegion;

/// Type of the iter() method's return value.
type I: Iterator<Item = &'a Self::R>;

/// Returns the number of regions in the collection.
fn num_regions(&self) -> usize;

/// Return the region containing the specified address or None.
fn find_region(&self, addr: GuestAddress) -> Option<&Self::R>;

/// Perform the specified action on each region.
/// It only walks children of current region and do not step into sub regions.
fn with_regions<F, E>(&self, cb: F) -> std::result::Result<(), E>
where
F: Fn(usize, &Self::R) -> std::result::Result<(), E>;

/// Perform the specified action on each region mutably.
/// It only walks children of current region and do not step into sub regions.
fn with_regions_mut<F, E>(&self, cb: F) -> std::result::Result<(), E>
where
F: FnMut(usize, &Self::R) -> std::result::Result<(), E>;

/// Applies two functions, specified as callbacks, on the inner memory regions.
///
/// # Arguments
/// * `init` - Starting value of the accumulator for the `foldf` function.
/// * `mapf` - "Map" function, applied to all the inner memory regions. It returns an array of
/// the same size as the memory regions array, containing the function's results
/// for each region.
/// * `foldf` - "Fold" function, applied to the array returned by `mapf`. It acts as an
/// operator, applying itself to the `init` value and to each subsequent elemnent
/// in the array returned by `mapf`.
///
/// # Examples
///
/// * Compute the total size of all memory mappings in KB by iterating over the memory regions
/// and dividing their sizes to 1024, then summing up the values in an accumulator.
///
/// ```
/// # #[cfg(feature = "backend-mmap")]
/// # fn test_map_fold() -> Result<(), ()> {
/// # use vm_memory::{GuestAddress, GuestMemory, GuestMemoryRegion, mmap::GuestMemoryMmap};
/// let start_addr1 = GuestAddress(0x0);
/// let start_addr2 = GuestAddress(0x400);
/// let mem = GuestMemoryMmap::new(&vec![(start_addr1, 1024), (start_addr2, 2048)]).unwrap();
/// let total_size = mem.map_and_fold(
/// 0,
/// |(_, region)| region.len() / 1024,
/// |acc, size| acc + size
/// );
/// println!("Total memory size = {} KB", total_size);
/// Ok(())
/// # }
/// ```
fn map_and_fold<F, G, T>(&self, init: T, mapf: F, foldf: G) -> T
where
F: Fn((usize, &Self::R)) -> T,
G: Fn(T, T) -> T;
/// Gets an iterator over the entries in the collection.
fn iter(&'a self) -> Self::I;

/// Get maximum (inclusive) address managed by the region.
fn end_addr(&self) -> GuestAddress {
self.map_and_fold(
GuestAddress(0),
|(_, region)| region.end_addr(),
std::cmp::max,
)
}
fn end_addr(&self) -> GuestAddress;

/// Convert an absolute address into an address space (GuestMemory)
/// to a relative address within this region, or return None if
Expand Down Expand Up @@ -320,9 +282,14 @@ pub trait GuestMemory {
Ok(total)
}
}

/// Convert an absolute address in an address space (GuestMemory) to a host pointer,
/// or return None if it is out of bounds. It always returns None when `DIRECT_ACCESS` is false.
/// The returned pointer may be used for ioctls etc.
fn get_host_address(&self, addr: GuestAddress) -> Option<*mut u8>;
}

impl<T: GuestMemory> Bytes<GuestAddress> for T {
impl<'a, T: GuestMemory<'a>> Bytes<GuestAddress> for T {
type E = Error;

fn write(&self, buf: &[u8], addr: GuestAddress) -> Result<usize> {
Expand Down
Loading