Skip to content

Commit 69e5ef0

Browse files
committed
introduce region module
This modules is intended for all functionality that relates to contiguous regions of guest memory. This differentiates it from `guest_memory`, as that is about a holistic view of guest memory, and from `mmap`, which is specifically about guest memory regions backed by mmap VMAs. Signed-off-by: Patrick Roy <[email protected]>
1 parent e097575 commit 69e5ef0

File tree

4 files changed

+151
-137
lines changed

4 files changed

+151
-137
lines changed

src/guest_memory.rs

Lines changed: 4 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ use std::sync::atomic::Ordering;
5050
use std::sync::Arc;
5151

5252
use crate::address::{Address, AddressValue};
53-
use crate::bitmap::{Bitmap, BS, MS};
53+
use crate::bitmap::MS;
5454
use crate::bytes::{AtomicAccess, Bytes};
5555
use crate::io::{ReadVolatile, WriteVolatile};
5656
use crate::volatile_memory::{self, VolatileSlice};
57+
use crate::GuestMemoryRegion;
5758

5859
/// Errors associated with handling guest memory accesses.
5960
#[allow(missing_docs)]
@@ -158,139 +159,6 @@ impl FileOffset {
158159
}
159160
}
160161

161-
/// Represents a continuous region of guest physical memory.
162-
#[allow(clippy::len_without_is_empty)]
163-
pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
164-
/// Type used for dirty memory tracking.
165-
type B: Bitmap;
166-
167-
/// Returns the size of the region.
168-
fn len(&self) -> GuestUsize;
169-
170-
/// Returns the minimum (inclusive) address managed by the region.
171-
fn start_addr(&self) -> GuestAddress;
172-
173-
/// Returns the maximum (inclusive) address managed by the region.
174-
fn last_addr(&self) -> GuestAddress {
175-
// unchecked_add is safe as the region bounds were checked when it was created.
176-
self.start_addr().unchecked_add(self.len() - 1)
177-
}
178-
179-
/// Borrow the associated `Bitmap` object.
180-
fn bitmap(&self) -> BS<'_, Self::B>;
181-
182-
/// Returns the given address if it is within this region.
183-
fn check_address(&self, addr: MemoryRegionAddress) -> Option<MemoryRegionAddress> {
184-
if self.address_in_range(addr) {
185-
Some(addr)
186-
} else {
187-
None
188-
}
189-
}
190-
191-
/// Returns `true` if the given address is within this region.
192-
fn address_in_range(&self, addr: MemoryRegionAddress) -> bool {
193-
addr.raw_value() < self.len()
194-
}
195-
196-
/// Returns the address plus the offset if it is in this region.
197-
fn checked_offset(
198-
&self,
199-
base: MemoryRegionAddress,
200-
offset: usize,
201-
) -> Option<MemoryRegionAddress> {
202-
base.checked_add(offset as u64)
203-
.and_then(|addr| self.check_address(addr))
204-
}
205-
206-
/// Tries to convert an absolute address to a relative address within this region.
207-
///
208-
/// Returns `None` if `addr` is out of the bounds of this region.
209-
fn to_region_addr(&self, addr: GuestAddress) -> Option<MemoryRegionAddress> {
210-
addr.checked_offset_from(self.start_addr())
211-
.and_then(|offset| self.check_address(MemoryRegionAddress(offset)))
212-
}
213-
214-
/// Returns the host virtual address corresponding to the region address.
215-
///
216-
/// Some [`GuestMemory`](trait.GuestMemory.html) implementations, like `GuestMemoryMmap`,
217-
/// have the capability to mmap guest address range into host virtual address space for
218-
/// direct access, so the corresponding host virtual address may be passed to other subsystems.
219-
///
220-
/// # Note
221-
/// The underlying guest memory is not protected from memory aliasing, which breaks the
222-
/// Rust memory safety model. It's the caller's responsibility to ensure that there's no
223-
/// concurrent accesses to the underlying guest memory.
224-
fn get_host_address(&self, _addr: MemoryRegionAddress) -> Result<*mut u8> {
225-
Err(Error::HostAddressNotAvailable)
226-
}
227-
228-
/// Returns information regarding the file and offset backing this memory region.
229-
fn file_offset(&self) -> Option<&FileOffset> {
230-
None
231-
}
232-
233-
/// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
234-
/// `offset`.
235-
#[allow(unused_variables)]
236-
fn get_slice(
237-
&self,
238-
offset: MemoryRegionAddress,
239-
count: usize,
240-
) -> Result<VolatileSlice<BS<Self::B>>> {
241-
Err(Error::HostAddressNotAvailable)
242-
}
243-
244-
/// Gets a slice of memory for the entire region that supports volatile access.
245-
///
246-
/// # Examples (uses the `backend-mmap` feature)
247-
///
248-
/// ```
249-
/// # #[cfg(feature = "backend-mmap")]
250-
/// # {
251-
/// # use vm_memory::{GuestAddress, MmapRegion, GuestRegionMmap, GuestMemoryRegion};
252-
/// # use vm_memory::volatile_memory::{VolatileMemory, VolatileSlice, VolatileRef};
253-
/// #
254-
/// let region = GuestRegionMmap::<()>::from_range(GuestAddress(0x0), 0x400, None)
255-
/// .expect("Could not create guest memory");
256-
/// let slice = region
257-
/// .as_volatile_slice()
258-
/// .expect("Could not get volatile slice");
259-
///
260-
/// let v = 42u32;
261-
/// let r = slice
262-
/// .get_ref::<u32>(0x200)
263-
/// .expect("Could not get reference");
264-
/// r.store(v);
265-
/// assert_eq!(r.load(), v);
266-
/// # }
267-
/// ```
268-
fn as_volatile_slice(&self) -> Result<VolatileSlice<BS<Self::B>>> {
269-
self.get_slice(MemoryRegionAddress(0), self.len() as usize)
270-
}
271-
272-
/// Show if the region is based on the `HugeTLBFS`.
273-
/// Returns Some(true) if the region is backed by hugetlbfs.
274-
/// None represents that no information is available.
275-
///
276-
/// # Examples (uses the `backend-mmap` feature)
277-
///
278-
/// ```
279-
/// # #[cfg(feature = "backend-mmap")]
280-
/// # {
281-
/// # use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, GuestRegionMmap};
282-
/// let addr = GuestAddress(0x1000);
283-
/// let mem = GuestMemoryMmap::<()>::from_ranges(&[(addr, 0x1000)]).unwrap();
284-
/// let r = mem.find_region(addr).unwrap();
285-
/// assert_eq!(r.is_hugetlbfs(), None);
286-
/// # }
287-
/// ```
288-
#[cfg(target_os = "linux")]
289-
fn is_hugetlbfs(&self) -> Option<bool> {
290-
None
291-
}
292-
}
293-
294162
/// `GuestAddressSpace` provides a way to retrieve a `GuestMemory` object.
295163
/// The vm-memory crate already provides trivial implementation for
296164
/// references to `GuestMemory` or reference-counted `GuestMemory` objects,
@@ -411,7 +279,8 @@ pub trait GuestMemory {
411279

412280
/// Returns the region containing the specified address or `None`.
413281
fn find_region(&self, addr: GuestAddress) -> Option<&Self::R> {
414-
self.iter().find(|region| addr >= region.start_addr() && addr <= region.last_addr())
282+
self.iter()
283+
.find(|region| addr >= region.start_addr() && addr <= region.last_addr())
415284
}
416285

417286
/// Gets an iterator over the entries in the collection.

src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ pub use endian::{Be16, Be32, Be64, BeSize, Le16, Le32, Le64, LeSize};
4747
pub mod guest_memory;
4848
pub use guest_memory::{
4949
Error as GuestMemoryError, FileOffset, GuestAddress, GuestAddressSpace, GuestMemory,
50-
GuestMemoryRegion, GuestUsize, MemoryRegionAddress, Result as GuestMemoryResult,
50+
GuestUsize, MemoryRegionAddress, Result as GuestMemoryResult,
5151
};
5252

53+
pub mod region;
54+
pub use region::GuestMemoryRegion;
55+
5356
pub mod io;
5457
pub use io::{ReadVolatile, WriteVolatile};
5558

src/mmap/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ use std::sync::Arc;
2121
use crate::address::Address;
2222
use crate::bitmap::{Bitmap, BS};
2323
use crate::guest_memory::{
24-
self, FileOffset, GuestAddress, GuestMemory, GuestMemoryRegion, GuestUsize, MemoryRegionAddress,
24+
self, FileOffset, GuestAddress, GuestMemory, GuestUsize, MemoryRegionAddress,
2525
};
26+
use crate::region::GuestMemoryRegion;
2627
use crate::volatile_memory::{VolatileMemory, VolatileSlice};
2728
use crate::{AtomicAccess, Bytes, ReadVolatile, WriteVolatile};
2829

src/region.rs

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
//! Module containing abstracts for dealing with contiguous regions of guest memory
2+
3+
use crate::bitmap::{Bitmap, BS};
4+
use crate::guest_memory::Error;
5+
use crate::guest_memory::Result;
6+
use crate::{
7+
Address, Bytes, FileOffset, GuestAddress, GuestUsize, MemoryRegionAddress, VolatileSlice,
8+
};
9+
10+
/// Represents a continuous region of guest physical memory.
11+
#[allow(clippy::len_without_is_empty)]
12+
pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
13+
/// Type used for dirty memory tracking.
14+
type B: Bitmap;
15+
16+
/// Returns the size of the region.
17+
fn len(&self) -> GuestUsize;
18+
19+
/// Returns the minimum (inclusive) address managed by the region.
20+
fn start_addr(&self) -> GuestAddress;
21+
22+
/// Returns the maximum (inclusive) address managed by the region.
23+
fn last_addr(&self) -> GuestAddress {
24+
// unchecked_add is safe as the region bounds were checked when it was created.
25+
self.start_addr().unchecked_add(self.len() - 1)
26+
}
27+
28+
/// Borrow the associated `Bitmap` object.
29+
fn bitmap(&self) -> BS<'_, Self::B>;
30+
31+
/// Returns the given address if it is within this region.
32+
fn check_address(&self, addr: MemoryRegionAddress) -> Option<MemoryRegionAddress> {
33+
if self.address_in_range(addr) {
34+
Some(addr)
35+
} else {
36+
None
37+
}
38+
}
39+
40+
/// Returns `true` if the given address is within this region.
41+
fn address_in_range(&self, addr: MemoryRegionAddress) -> bool {
42+
addr.raw_value() < self.len()
43+
}
44+
45+
/// Returns the address plus the offset if it is in this region.
46+
fn checked_offset(
47+
&self,
48+
base: MemoryRegionAddress,
49+
offset: usize,
50+
) -> Option<MemoryRegionAddress> {
51+
base.checked_add(offset as u64)
52+
.and_then(|addr| self.check_address(addr))
53+
}
54+
55+
/// Tries to convert an absolute address to a relative address within this region.
56+
///
57+
/// Returns `None` if `addr` is out of the bounds of this region.
58+
fn to_region_addr(&self, addr: GuestAddress) -> Option<MemoryRegionAddress> {
59+
addr.checked_offset_from(self.start_addr())
60+
.and_then(|offset| self.check_address(MemoryRegionAddress(offset)))
61+
}
62+
63+
/// Returns the host virtual address corresponding to the region address.
64+
///
65+
/// Some [`GuestMemory`](trait.GuestMemory.html) implementations, like `GuestMemoryMmap`,
66+
/// have the capability to mmap guest address range into host virtual address space for
67+
/// direct access, so the corresponding host virtual address may be passed to other subsystems.
68+
///
69+
/// # Note
70+
/// The underlying guest memory is not protected from memory aliasing, which breaks the
71+
/// Rust memory safety model. It's the caller's responsibility to ensure that there's no
72+
/// concurrent accesses to the underlying guest memory.
73+
fn get_host_address(&self, _addr: MemoryRegionAddress) -> Result<*mut u8> {
74+
Err(Error::HostAddressNotAvailable)
75+
}
76+
77+
/// Returns information regarding the file and offset backing this memory region.
78+
fn file_offset(&self) -> Option<&FileOffset> {
79+
None
80+
}
81+
82+
/// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
83+
/// `offset`.
84+
#[allow(unused_variables)]
85+
fn get_slice(
86+
&self,
87+
offset: MemoryRegionAddress,
88+
count: usize,
89+
) -> Result<VolatileSlice<BS<Self::B>>> {
90+
Err(Error::HostAddressNotAvailable)
91+
}
92+
93+
/// Gets a slice of memory for the entire region that supports volatile access.
94+
///
95+
/// # Examples (uses the `backend-mmap` feature)
96+
///
97+
/// ```
98+
/// # #[cfg(feature = "backend-mmap")]
99+
/// # {
100+
/// # use vm_memory::{GuestAddress, MmapRegion, GuestRegionMmap, GuestMemoryRegion};
101+
/// # use vm_memory::volatile_memory::{VolatileMemory, VolatileSlice, VolatileRef};
102+
/// #
103+
/// let region = GuestRegionMmap::<()>::from_range(GuestAddress(0x0), 0x400, None)
104+
/// .expect("Could not create guest memory");
105+
/// let slice = region
106+
/// .as_volatile_slice()
107+
/// .expect("Could not get volatile slice");
108+
///
109+
/// let v = 42u32;
110+
/// let r = slice
111+
/// .get_ref::<u32>(0x200)
112+
/// .expect("Could not get reference");
113+
/// r.store(v);
114+
/// assert_eq!(r.load(), v);
115+
/// # }
116+
/// ```
117+
fn as_volatile_slice(&self) -> Result<VolatileSlice<BS<Self::B>>> {
118+
self.get_slice(MemoryRegionAddress(0), self.len() as usize)
119+
}
120+
121+
/// Show if the region is based on the `HugeTLBFS`.
122+
/// Returns Some(true) if the region is backed by hugetlbfs.
123+
/// None represents that no information is available.
124+
///
125+
/// # Examples (uses the `backend-mmap` feature)
126+
///
127+
/// ```
128+
/// # #[cfg(feature = "backend-mmap")]
129+
/// # {
130+
/// # use vm_memory::{GuestAddress, GuestMemory, GuestMemoryMmap, GuestRegionMmap};
131+
/// let addr = GuestAddress(0x1000);
132+
/// let mem = GuestMemoryMmap::<()>::from_ranges(&[(addr, 0x1000)]).unwrap();
133+
/// let r = mem.find_region(addr).unwrap();
134+
/// assert_eq!(r.is_hugetlbfs(), None);
135+
/// # }
136+
/// ```
137+
#[cfg(target_os = "linux")]
138+
fn is_hugetlbfs(&self) -> Option<bool> {
139+
None
140+
}
141+
}

0 commit comments

Comments
 (0)