Skip to content

Commit 8128bb1

Browse files
michael2012zandreeaflorescu
authored andcommitted
Add "get_slice" and "as_volatile_slice" methods to GuestMemoryRegion.
Fixes #76. "get_slice" and "as_volatile_slice" provide better way to access guest memory than "get_host_address" does. They both build ranged-checked "VolatileSlice". Difference is, "get_ slice" takes "offset" and "size" parameters, while "as_volatile_ slice" makes slice for the whole region. Signed-off-by: Michael Zhao <michael.zhao@arm.com>
1 parent 2dc770c commit 8128bb1

File tree

3 files changed

+147
-3
lines changed

3 files changed

+147
-3
lines changed

coverage_config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 84.8,
2+
"coverage_score": 85.6,
33
"exclude_path": "mmap_windows.rs",
44
"crate_features": "backend-mmap,backend-atomic"
55
}

src/guest_memory.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,45 @@ pub trait GuestMemoryRegion: Bytes<MemoryRegionAddress, E = Error> {
246246
unsafe fn as_mut_slice(&self) -> Option<&mut [u8]> {
247247
None
248248
}
249+
250+
/// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
251+
/// `offset`.
252+
#[allow(unused_variables)]
253+
fn get_slice(
254+
&self,
255+
offset: MemoryRegionAddress,
256+
count: usize,
257+
) -> Result<volatile_memory::VolatileSlice> {
258+
Err(Error::HostAddressNotAvailable)
259+
}
260+
261+
/// Gets a slice of memory for the entire region that supports volatile access.
262+
///
263+
/// # Examples
264+
///
265+
/// ```
266+
/// # #[cfg(feature = "backend-mmap")]
267+
/// # use vm_memory::{GuestAddress, MmapRegion, GuestRegionMmap, GuestMemoryRegion};
268+
/// # #[cfg(feature = "backend-mmap")]
269+
/// # use vm_memory::volatile_memory::{VolatileMemory, VolatileSlice, VolatileRef};
270+
///
271+
/// # #[cfg(feature = "backend-mmap")]
272+
/// # fn test_as_volatile_slice() {
273+
/// let region =
274+
/// GuestRegionMmap::new(MmapRegion::new(0x400).unwrap(), GuestAddress(0x0))
275+
/// .unwrap();
276+
/// let slice = region.as_volatile_slice().unwrap();
277+
/// let v = 42u32;
278+
/// let r = slice.get_ref::<u32>(0x200).unwrap();
279+
/// r.store(v);
280+
/// assert_eq!(r.load(), v);
281+
/// # }
282+
/// # #[cfg(feature = "backend-mmap")]
283+
/// # test_as_volatile_slice();
284+
/// ```
285+
fn as_volatile_slice(&self) -> Result<volatile_memory::VolatileSlice> {
286+
self.get_slice(MemoryRegionAddress(0), self.len() as usize)
287+
}
249288
}
250289

251290
/// GuestAddressSpace provides a way to retrieve a GuestMemory object.
@@ -563,6 +602,18 @@ pub trait GuestMemory {
563602
.ok_or_else(|| Error::InvalidGuestAddress(addr))
564603
.and_then(|(r, addr)| r.get_host_address(addr))
565604
}
605+
606+
/// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
607+
/// `addr`.
608+
fn get_slice(
609+
&self,
610+
addr: GuestAddress,
611+
count: usize,
612+
) -> Result<volatile_memory::VolatileSlice> {
613+
self.to_region_addr(addr)
614+
.ok_or_else(|| Error::InvalidGuestAddress(addr))
615+
.and_then(|(r, addr)| r.get_slice(addr, count))
616+
}
566617
}
567618

568619
impl<T: GuestMemory> Bytes<GuestAddress> for T {

src/mmap.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::address::Address;
2424
use crate::guest_memory::{
2525
self, FileOffset, GuestAddress, GuestMemory, GuestMemoryRegion, GuestUsize, MemoryRegionAddress,
2626
};
27-
use crate::volatile_memory::VolatileMemory;
27+
use crate::volatile_memory::{VolatileMemory, VolatileSlice};
2828
use crate::Bytes;
2929

3030
#[cfg(unix)]
@@ -165,6 +165,7 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
165165
fn write(&self, buf: &[u8], addr: MemoryRegionAddress) -> guest_memory::Result<usize> {
166166
let maddr = addr.raw_value() as usize;
167167
self.as_volatile_slice()
168+
.unwrap()
168169
.write(buf, maddr)
169170
.map_err(Into::into)
170171
}
@@ -183,20 +184,23 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
183184
fn read(&self, buf: &mut [u8], addr: MemoryRegionAddress) -> guest_memory::Result<usize> {
184185
let maddr = addr.raw_value() as usize;
185186
self.as_volatile_slice()
187+
.unwrap()
186188
.read(buf, maddr)
187189
.map_err(Into::into)
188190
}
189191

190192
fn write_slice(&self, buf: &[u8], addr: MemoryRegionAddress) -> guest_memory::Result<()> {
191193
let maddr = addr.raw_value() as usize;
192194
self.as_volatile_slice()
195+
.unwrap()
193196
.write_slice(buf, maddr)
194197
.map_err(Into::into)
195198
}
196199

197200
fn read_slice(&self, buf: &mut [u8], addr: MemoryRegionAddress) -> guest_memory::Result<()> {
198201
let maddr = addr.raw_value() as usize;
199202
self.as_volatile_slice()
203+
.unwrap()
200204
.read_slice(buf, maddr)
201205
.map_err(Into::into)
202206
}
@@ -232,6 +236,7 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
232236
{
233237
let maddr = addr.raw_value() as usize;
234238
self.as_volatile_slice()
239+
.unwrap()
235240
.read_from::<F>(maddr, src, count)
236241
.map_err(Into::into)
237242
}
@@ -267,6 +272,7 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
267272
{
268273
let maddr = addr.raw_value() as usize;
269274
self.as_volatile_slice()
275+
.unwrap()
270276
.read_exact_from::<F>(maddr, src, count)
271277
.map_err(Into::into)
272278
}
@@ -299,6 +305,7 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
299305
{
300306
let maddr = addr.raw_value() as usize;
301307
self.as_volatile_slice()
308+
.unwrap()
302309
.write_to::<F>(maddr, dst, count)
303310
.map_err(Into::into)
304311
}
@@ -331,6 +338,7 @@ impl Bytes<MemoryRegionAddress> for GuestRegionMmap {
331338
{
332339
let maddr = addr.raw_value() as usize;
333340
self.as_volatile_slice()
341+
.unwrap()
334342
.write_all_to::<F>(maddr, dst, count)
335343
.map_err(Into::into)
336344
}
@@ -364,6 +372,15 @@ impl GuestMemoryRegion for GuestRegionMmap {
364372
.ok_or(guest_memory::Error::InvalidBackendAddress)
365373
.map(|addr| self.as_ptr().wrapping_offset(addr.raw_value() as isize))
366374
}
375+
376+
fn get_slice(
377+
&self,
378+
offset: MemoryRegionAddress,
379+
count: usize,
380+
) -> guest_memory::Result<VolatileSlice> {
381+
let slice = self.mapping.get_slice(offset.raw_value() as usize, count)?;
382+
Ok(slice)
383+
}
367384
}
368385

369386
/// [`GuestMemory`](trait.GuestMemory.html) implementation that mmaps the guest's memory
@@ -972,7 +989,8 @@ mod tests {
972989
let slice = guest_mem
973990
.find_region(GuestAddress(0))
974991
.unwrap()
975-
.as_volatile_slice();
992+
.as_volatile_slice()
993+
.unwrap();
976994

977995
let buf = &mut [0, 0, 0, 0, 0];
978996
assert_eq!(slice.read(buf, 0).unwrap(), 5);
@@ -1301,4 +1319,79 @@ mod tests {
13011319
assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
13021320
assert_eq!(region.start_addr(), GuestAddress(0x10_0000));
13031321
}
1322+
1323+
#[test]
1324+
fn test_guest_memory_mmap_get_slice() {
1325+
let region_addr = GuestAddress(0);
1326+
let region_size = 0x400;
1327+
let region =
1328+
GuestRegionMmap::new(MmapRegion::new(region_size).unwrap(), region_addr).unwrap();
1329+
1330+
// Normal case.
1331+
let slice_addr = MemoryRegionAddress(0x100);
1332+
let slice_size = 0x200;
1333+
let slice = region.get_slice(slice_addr, slice_size).unwrap();
1334+
assert_eq!(slice.len(), slice_size);
1335+
1336+
// Empty slice.
1337+
let slice_addr = MemoryRegionAddress(0x200);
1338+
let slice_size = 0x0;
1339+
let slice = region.get_slice(slice_addr, slice_size).unwrap();
1340+
assert!(slice.is_empty());
1341+
1342+
// Error case when slice_size is beyond the boundary.
1343+
let slice_addr = MemoryRegionAddress(0x300);
1344+
let slice_size = 0x200;
1345+
assert!(region.get_slice(slice_addr, slice_size).is_err());
1346+
}
1347+
1348+
#[test]
1349+
fn test_guest_memory_mmap_as_volatile_slice() {
1350+
let region_addr = GuestAddress(0);
1351+
let region_size = 0x400;
1352+
let region =
1353+
GuestRegionMmap::new(MmapRegion::new(region_size).unwrap(), region_addr).unwrap();
1354+
1355+
// Test slice length.
1356+
let slice = region.as_volatile_slice().unwrap();
1357+
assert_eq!(slice.len(), region_size);
1358+
1359+
// Test slice data.
1360+
let v = 0x1234_5678u32;
1361+
let r = slice.get_ref::<u32>(0x200).unwrap();
1362+
r.store(v);
1363+
assert_eq!(r.load(), v);
1364+
}
1365+
1366+
#[test]
1367+
fn test_guest_memory_get_slice() {
1368+
let start_addr1 = GuestAddress(0);
1369+
let start_addr2 = GuestAddress(0x800);
1370+
let guest_mem =
1371+
GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
1372+
1373+
// Normal cases.
1374+
let slice_size = 0x200;
1375+
let slice = guest_mem
1376+
.get_slice(GuestAddress(0x100), slice_size)
1377+
.unwrap();
1378+
assert_eq!(slice.len(), slice_size);
1379+
1380+
let slice_size = 0x400;
1381+
let slice = guest_mem
1382+
.get_slice(GuestAddress(0x800), slice_size)
1383+
.unwrap();
1384+
assert_eq!(slice.len(), slice_size);
1385+
1386+
// Empty slice.
1387+
assert!(guest_mem
1388+
.get_slice(GuestAddress(0x900), 0)
1389+
.unwrap()
1390+
.is_empty());
1391+
1392+
// Error cases, wrong size or base address.
1393+
assert!(guest_mem.get_slice(GuestAddress(0), 0x500).is_err());
1394+
assert!(guest_mem.get_slice(GuestAddress(0x600), 0x100).is_err());
1395+
assert!(guest_mem.get_slice(GuestAddress(0xc00), 0x100).is_err());
1396+
}
13041397
}

0 commit comments

Comments
 (0)