1use std::borrow::Borrow;
16use std::ops::Deref;
17use std::result;
18use std::sync::Arc;
19
20use crate::address::Address;
21use crate::bitmap::{Bitmap, BS};
22use crate::guest_memory::{self, FileOffset, GuestAddress, GuestUsize, MemoryRegionAddress};
23use crate::region::{
24 GuestMemoryRegion, GuestMemoryRegionBytes, GuestRegionCollection, GuestRegionCollectionError,
25};
26use crate::volatile_memory::{VolatileMemory, VolatileSlice};
27
28pub use crate::bitmap::NewBitmap;
30
31#[cfg(all(not(feature = "xen"), target_family = "unix"))]
32mod unix;
33
34#[cfg(all(feature = "xen", target_family = "unix"))]
35pub(crate) mod xen;
36
37#[cfg(target_family = "windows")]
38mod windows;
39
40#[cfg(all(not(feature = "xen"), target_family = "unix"))]
41pub use unix::{Error as MmapRegionError, MmapRegion, MmapRegionBuilder};
42
43#[cfg(all(feature = "xen", target_family = "unix"))]
44pub use xen::{Error as MmapRegionError, MmapRange, MmapRegion, MmapXenFlags};
45
46#[cfg(target_family = "windows")]
47pub use std::io::Error as MmapRegionError;
48#[cfg(target_family = "windows")]
49pub use windows::MmapRegion;
50
51#[derive(Debug)]
57pub struct GuestRegionMmap<B = ()> {
58 mapping: Arc<MmapRegion<B>>,
59 guest_base: GuestAddress,
60}
61
62impl<B> Deref for GuestRegionMmap<B> {
63 type Target = MmapRegion<B>;
64
65 fn deref(&self) -> &MmapRegion<B> {
66 self.mapping.as_ref()
67 }
68}
69
70impl<B: Bitmap> GuestRegionMmap<B> {
71 pub fn new(mapping: MmapRegion<B>, guest_base: GuestAddress) -> Option<Self> {
75 Self::with_arc(Arc::new(mapping), guest_base)
76 }
77
78 pub fn with_arc(mapping: Arc<MmapRegion<B>>, guest_base: GuestAddress) -> Option<Self> {
80 guest_base
81 .0
82 .checked_add(mapping.size() as u64)
83 .map(|_| Self {
84 mapping,
85 guest_base,
86 })
87 }
88
89 pub fn get_mmap(&self) -> Arc<MmapRegion<B>> {
96 Arc::clone(&self.mapping)
97 }
98}
99
100#[cfg(not(feature = "xen"))]
101impl<B: NewBitmap> GuestRegionMmap<B> {
102 pub fn from_range(
104 addr: GuestAddress,
105 size: usize,
106 file: Option<FileOffset>,
107 ) -> result::Result<Self, FromRangesError> {
108 let region = if let Some(ref f_off) = file {
109 MmapRegion::from_file(f_off.clone(), size)?
110 } else {
111 MmapRegion::new(size)?
112 };
113
114 Self::new(region, addr).ok_or(FromRangesError::InvalidGuestRegion)
115 }
116}
117
118#[cfg(feature = "xen")]
119impl<B: NewBitmap> GuestRegionMmap<B> {
120 pub fn from_range(
123 addr: GuestAddress,
124 size: usize,
125 file: Option<FileOffset>,
126 ) -> result::Result<Self, FromRangesError> {
127 let range = MmapRange::new_unix(size, file, addr);
128
129 let region = MmapRegion::from_range(range)?;
130 Self::new(region, addr).ok_or(FromRangesError::InvalidGuestRegion)
131 }
132}
133
134impl<B: Bitmap> GuestMemoryRegion for GuestRegionMmap<B> {
135 type B = B;
136
137 fn len(&self) -> GuestUsize {
138 self.mapping.size() as GuestUsize
139 }
140
141 fn start_addr(&self) -> GuestAddress {
142 self.guest_base
143 }
144
145 fn bitmap(&self) -> BS<'_, Self::B> {
146 self.mapping.bitmap().slice_at(0)
147 }
148
149 fn get_host_address(&self, addr: MemoryRegionAddress) -> guest_memory::Result<*mut u8> {
150 self.check_address(addr)
153 .ok_or(guest_memory::Error::InvalidBackendAddress)
154 .map(|addr| {
155 self.mapping
156 .as_ptr()
157 .wrapping_offset(addr.raw_value() as isize)
158 })
159 }
160
161 fn file_offset(&self) -> Option<&FileOffset> {
162 self.mapping.file_offset()
163 }
164
165 fn get_slice(
166 &self,
167 offset: MemoryRegionAddress,
168 count: usize,
169 ) -> guest_memory::Result<VolatileSlice<'_, BS<'_, B>>> {
170 let slice = self.mapping.get_slice(offset.raw_value() as usize, count)?;
171 Ok(slice)
172 }
173
174 #[cfg(target_os = "linux")]
175 fn is_hugetlbfs(&self) -> Option<bool> {
176 self.mapping.is_hugetlbfs()
177 }
178}
179
180impl<B: Bitmap> GuestMemoryRegionBytes for GuestRegionMmap<B> {}
181
182pub type GuestMemoryMmap<B = ()> = GuestRegionCollection<GuestRegionMmap<B>>;
189
190#[derive(Debug, thiserror::Error)]
192pub enum FromRangesError {
193 #[error("Error constructing guest region collection: {0}")]
195 Collection(#[from] GuestRegionCollectionError),
196 #[error("Error setting up raw memory for guest region: {0}")]
198 MmapRegion(#[from] MmapRegionError),
199 #[error("Combination of guest address and region length invalid (would overflow)")]
201 InvalidGuestRegion,
202}
203
204impl<B: NewBitmap> GuestMemoryMmap<B> {
205 pub fn from_ranges(ranges: &[(GuestAddress, usize)]) -> result::Result<Self, FromRangesError> {
209 Self::from_ranges_with_files(ranges.iter().map(|r| (r.0, r.1, None)))
210 }
211
212 pub fn from_ranges_with_files<A, T>(ranges: T) -> result::Result<Self, FromRangesError>
217 where
218 A: Borrow<(GuestAddress, usize, Option<FileOffset>)>,
219 T: IntoIterator<Item = A>,
220 {
221 Self::from_regions(
222 ranges
223 .into_iter()
224 .map(|x| {
225 GuestRegionMmap::from_range(x.borrow().0, x.borrow().1, x.borrow().2.clone())
226 })
227 .collect::<Result<Vec<_>, _>>()?,
228 )
229 .map_err(Into::into)
230 }
231}
232
233#[cfg(test)]
234mod tests {
235 #![allow(clippy::undocumented_unsafe_blocks)]
236 extern crate vmm_sys_util;
237
238 use super::*;
239
240 #[cfg(feature = "backend-bitmap")]
241 use crate::bitmap::AtomicBitmap;
242 use crate::{Bytes, GuestMemoryBackend, GuestMemoryError};
243
244 use std::io::Write;
245 #[cfg(feature = "rawfd")]
246 use std::{fs::File, path::Path};
247 use vmm_sys_util::tempfile::TempFile;
248
249 use matches::assert_matches;
250
251 type GuestRegionMmap = super::GuestRegionMmap<()>;
252 type GuestMemoryMmap = super::GuestRegionCollection<GuestRegionMmap>;
253 type MmapRegion = super::MmapRegion<()>;
254
255 #[test]
256 fn basic_map() {
257 let m = MmapRegion::new(1024).unwrap();
258 assert_eq!(1024, m.size());
259 }
260
261 #[test]
262 fn slice_addr() {
263 let m = GuestRegionMmap::from_range(GuestAddress(0), 5, None).unwrap();
264 let s = m.get_slice(MemoryRegionAddress(2), 3).unwrap();
265 let guard = s.ptr_guard();
266 assert_eq!(guard.as_ptr(), unsafe { m.as_ptr().offset(2) });
267 }
268
269 #[test]
270 #[cfg(not(miri))] fn mapped_file_read() {
272 let mut f = TempFile::new().unwrap().into_file();
273 let sample_buf = &[1, 2, 3, 4, 5];
274 f.write_all(sample_buf).unwrap();
275
276 let file = Some(FileOffset::new(f, 0));
277 let mem_map = GuestRegionMmap::from_range(GuestAddress(0), sample_buf.len(), file).unwrap();
278 let buf = &mut [0u8; 16];
279 assert_eq!(
280 mem_map.as_volatile_slice().unwrap().read(buf, 0).unwrap(),
281 sample_buf.len()
282 );
283 assert_eq!(buf[0..sample_buf.len()], sample_buf[..]);
284 }
285
286 #[test]
287 fn test_to_region_addr() {
288 let f1 = TempFile::new().unwrap().into_file();
289 f1.set_len(0x400).unwrap();
290 let f2 = TempFile::new().unwrap().into_file();
291 f2.set_len(0x400).unwrap();
292
293 let start_addr1 = GuestAddress(0x0);
294 let start_addr2 = GuestAddress(0x800);
295 let guest_mem =
296 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
297 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
298 (start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
299 (start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
300 ])
301 .unwrap();
302
303 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
304 for guest_mem in guest_mem_list.iter() {
305 assert!(guest_mem.to_region_addr(GuestAddress(0x600)).is_none());
306 let (r0, addr0) = guest_mem.to_region_addr(GuestAddress(0x800)).unwrap();
307 let (r1, addr1) = guest_mem.to_region_addr(GuestAddress(0xa00)).unwrap();
308 assert!(r0.as_ptr() == r1.as_ptr());
309 assert_eq!(addr0, MemoryRegionAddress(0));
310 assert_eq!(addr1, MemoryRegionAddress(0x200));
311 }
312 }
313
314 #[test]
315 fn test_get_host_address() {
316 let f1 = TempFile::new().unwrap().into_file();
317 f1.set_len(0x400).unwrap();
318 let f2 = TempFile::new().unwrap().into_file();
319 f2.set_len(0x400).unwrap();
320
321 let start_addr1 = GuestAddress(0x0);
322 let start_addr2 = GuestAddress(0x800);
323 let guest_mem =
324 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
325 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
326 (start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
327 (start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
328 ])
329 .unwrap();
330
331 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
332 for guest_mem in guest_mem_list.iter() {
333 assert_matches!(
334 guest_mem.get_host_address(GuestAddress(0x600)).unwrap_err(),
335 GuestMemoryError::InvalidGuestAddress(GuestAddress(0x600))
336 );
337 let ptr0 = guest_mem.get_host_address(GuestAddress(0x800)).unwrap();
338 let ptr1 = guest_mem.get_host_address(GuestAddress(0xa00)).unwrap();
339 assert_eq!(
340 ptr0,
341 guest_mem.find_region(GuestAddress(0x800)).unwrap().as_ptr()
342 );
343 assert_eq!(unsafe { ptr0.offset(0x200) }, ptr1);
344 }
345 }
346
347 #[test]
348 fn test_check_range() {
349 let start_addr1 = GuestAddress(0);
350 let start_addr2 = GuestAddress(0x800);
351 let start_addr3 = GuestAddress(0xc00);
352 let guest_mem = GuestMemoryMmap::from_ranges(&[
353 (start_addr1, 0x400),
354 (start_addr2, 0x400),
355 (start_addr3, 0x400),
356 ])
357 .unwrap();
358
359 assert!(guest_mem.check_range(start_addr1, 0x0));
360 assert!(guest_mem.check_range(start_addr1, 0x200));
361 assert!(guest_mem.check_range(start_addr1, 0x400));
362 assert!(!guest_mem.check_range(start_addr1, 0xa00));
363 assert!(guest_mem.check_range(start_addr2, 0x7ff));
364 assert!(guest_mem.check_range(start_addr2, 0x800));
365 assert!(!guest_mem.check_range(start_addr2, 0x801));
366 assert!(!guest_mem.check_range(start_addr2, 0xc00));
367 assert!(!guest_mem.check_range(start_addr1, usize::MAX));
368 }
369
370 #[test]
371 fn test_deref() {
372 let f = TempFile::new().unwrap().into_file();
373 f.set_len(0x400).unwrap();
374
375 let start_addr = GuestAddress(0x0);
376 let guest_mem = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
377 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[(
378 start_addr,
379 0x400,
380 Some(FileOffset::new(f, 0)),
381 )])
382 .unwrap();
383
384 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
385 for guest_mem in guest_mem_list.iter() {
386 let sample_buf = &[1, 2, 3, 4, 5];
387
388 assert_eq!(guest_mem.write(sample_buf, start_addr).unwrap(), 5);
389 let slice = guest_mem
390 .find_region(GuestAddress(0))
391 .unwrap()
392 .as_volatile_slice()
393 .unwrap();
394
395 let buf = &mut [0, 0, 0, 0, 0];
396 assert_eq!(slice.read(buf, 0).unwrap(), 5);
397 assert_eq!(buf, sample_buf);
398 }
399 }
400
401 #[test]
402 fn test_read_u64() {
403 let f1 = TempFile::new().unwrap().into_file();
404 f1.set_len(0x1000).unwrap();
405 let f2 = TempFile::new().unwrap().into_file();
406 f2.set_len(0x1000).unwrap();
407
408 let start_addr1 = GuestAddress(0x0);
409 let start_addr2 = GuestAddress(0x1000);
410 let bad_addr = GuestAddress(0x2001);
411 let bad_addr2 = GuestAddress(0x1ffc);
412 let max_addr = GuestAddress(0x2000);
413
414 let gm =
415 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
416 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
417 (start_addr1, 0x1000, Some(FileOffset::new(f1, 0))),
418 (start_addr2, 0x1000, Some(FileOffset::new(f2, 0))),
419 ])
420 .unwrap();
421
422 let gm_list = [gm, gm_backed_by_file];
423 for gm in gm_list.iter() {
424 let val1: u64 = 0xaa55_aa55_aa55_aa55;
425 let val2: u64 = 0x55aa_55aa_55aa_55aa;
426 assert_matches!(
427 gm.write_obj(val1, bad_addr).unwrap_err(),
428 GuestMemoryError::InvalidGuestAddress(addr) if addr == bad_addr
429 );
430 assert_matches!(
431 gm.write_obj(val1, bad_addr2).unwrap_err(),
432 GuestMemoryError::PartialBuffer { expected, completed } if expected == size_of::<u64>() && completed == max_addr.checked_offset_from(bad_addr2).unwrap() as usize);
433
434 gm.write_obj(val1, GuestAddress(0x500)).unwrap();
435 gm.write_obj(val2, GuestAddress(0x1000 + 32)).unwrap();
436 let num1: u64 = gm.read_obj(GuestAddress(0x500)).unwrap();
437 let num2: u64 = gm.read_obj(GuestAddress(0x1000 + 32)).unwrap();
438 assert_eq!(val1, num1);
439 assert_eq!(val2, num2);
440 }
441 }
442
443 #[test]
444 fn write_and_read() {
445 let f = TempFile::new().unwrap().into_file();
446 f.set_len(0x400).unwrap();
447
448 let mut start_addr = GuestAddress(0x1000);
449 let gm = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
450 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[(
451 start_addr,
452 0x400,
453 Some(FileOffset::new(f, 0)),
454 )])
455 .unwrap();
456
457 let gm_list = [gm, gm_backed_by_file];
458 for gm in gm_list.iter() {
459 let sample_buf = &[1, 2, 3, 4, 5];
460
461 assert_eq!(gm.write(sample_buf, start_addr).unwrap(), 5);
462
463 let buf = &mut [0u8; 5];
464 assert_eq!(gm.read(buf, start_addr).unwrap(), 5);
465 assert_eq!(buf, sample_buf);
466
467 start_addr = GuestAddress(0x13ff);
468 assert_eq!(gm.write(sample_buf, start_addr).unwrap(), 1);
469 assert_eq!(gm.read(buf, start_addr).unwrap(), 1);
470 assert_eq!(buf[0], sample_buf[0]);
471 start_addr = GuestAddress(0x1000);
472 }
473 }
474
475 #[test]
476 #[cfg(feature = "rawfd")]
477 #[cfg(not(miri))]
478 fn read_to_and_write_from_mem() {
479 use std::mem;
480
481 let f = TempFile::new().unwrap().into_file();
482 f.set_len(0x400).unwrap();
483
484 let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0x1000), 0x400)]).unwrap();
485 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[(
486 GuestAddress(0x1000),
487 0x400,
488 Some(FileOffset::new(f, 0)),
489 )])
490 .unwrap();
491
492 let gm_list = [gm, gm_backed_by_file];
493 for gm in gm_list.iter() {
494 let addr = GuestAddress(0x1010);
495 let mut file = if cfg!(target_family = "unix") {
496 File::open(Path::new("/dev/zero")).unwrap()
497 } else {
498 File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe")).unwrap()
499 };
500 gm.write_obj(!0u32, addr).unwrap();
501 gm.read_exact_volatile_from(addr, &mut file, mem::size_of::<u32>())
502 .unwrap();
503 let value: u32 = gm.read_obj(addr).unwrap();
504 if cfg!(target_family = "unix") {
505 assert_eq!(value, 0);
506 } else {
507 assert_eq!(value, 0x0090_5a4d);
508 }
509
510 let mut sink = vec![0; mem::size_of::<u32>()];
511 gm.write_all_volatile_to(addr, &mut sink.as_mut_slice(), mem::size_of::<u32>())
512 .unwrap();
513 if cfg!(target_family = "unix") {
514 assert_eq!(sink, vec![0; mem::size_of::<u32>()]);
515 } else {
516 assert_eq!(sink, vec![0x4d, 0x5a, 0x90, 0x00]);
517 };
518 }
519 }
520
521 #[test]
522 fn test_access_cross_boundary() {
523 let f1 = TempFile::new().unwrap().into_file();
524 f1.set_len(0x1000).unwrap();
525 let f2 = TempFile::new().unwrap().into_file();
526 f2.set_len(0x1000).unwrap();
527
528 let start_addr1 = GuestAddress(0x0);
529 let start_addr2 = GuestAddress(0x1000);
530 let gm =
531 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
532 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
533 (start_addr1, 0x1000, Some(FileOffset::new(f1, 0))),
534 (start_addr2, 0x1000, Some(FileOffset::new(f2, 0))),
535 ])
536 .unwrap();
537
538 let gm_list = [gm, gm_backed_by_file];
539 for gm in gm_list.iter() {
540 let sample_buf = &[1, 2, 3, 4, 5];
541 assert_eq!(gm.write(sample_buf, GuestAddress(0xffc)).unwrap(), 5);
542 let buf = &mut [0u8; 5];
543 assert_eq!(gm.read(buf, GuestAddress(0xffc)).unwrap(), 5);
544 assert_eq!(buf, sample_buf);
545 }
546 }
547
548 #[test]
549 fn test_retrieve_fd_backing_memory_region() {
550 let f = TempFile::new().unwrap().into_file();
551 f.set_len(0x400).unwrap();
552
553 let start_addr = GuestAddress(0x0);
554 let gm = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
555 assert!(gm.find_region(start_addr).is_some());
556 let region = gm.find_region(start_addr).unwrap();
557 assert!(region.file_offset().is_none());
558
559 let gm = GuestMemoryMmap::from_ranges_with_files(&[(
560 start_addr,
561 0x400,
562 Some(FileOffset::new(f, 0)),
563 )])
564 .unwrap();
565 assert!(gm.find_region(start_addr).is_some());
566 let region = gm.find_region(start_addr).unwrap();
567 assert!(region.file_offset().is_some());
568 }
569
570 #[test]
575 #[cfg(target_family = "unix")]
576 fn test_retrieve_offset_from_fd_backing_memory_region() {
577 let f = TempFile::new().unwrap().into_file();
578 f.set_len(0x1400).unwrap();
579 let offset = 0x1000;
581
582 let start_addr = GuestAddress(0x0);
583 let gm = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
584 assert!(gm.find_region(start_addr).is_some());
585 let region = gm.find_region(start_addr).unwrap();
586 assert!(region.file_offset().is_none());
587
588 let gm = GuestMemoryMmap::from_ranges_with_files(&[(
589 start_addr,
590 0x400,
591 Some(FileOffset::new(f, offset)),
592 )])
593 .unwrap();
594 assert!(gm.find_region(start_addr).is_some());
595 let region = gm.find_region(start_addr).unwrap();
596 assert!(region.file_offset().is_some());
597 assert_eq!(region.file_offset().unwrap().start(), offset);
598 }
599
600 #[test]
601 fn test_guest_memory_mmap_get_slice() {
602 let region = GuestRegionMmap::from_range(GuestAddress(0), 0x400, None).unwrap();
603
604 let slice_addr = MemoryRegionAddress(0x100);
606 let slice_size = 0x200;
607 let slice = region.get_slice(slice_addr, slice_size).unwrap();
608 assert_eq!(slice.len(), slice_size);
609
610 let slice_addr = MemoryRegionAddress(0x200);
612 let slice_size = 0x0;
613 let slice = region.get_slice(slice_addr, slice_size).unwrap();
614 assert!(slice.is_empty());
615
616 let slice_addr = MemoryRegionAddress(0x300);
618 let slice_size = 0x200;
619 assert_matches!(
620 region.get_slice(slice_addr, slice_size).unwrap_err(),
621 GuestMemoryError::InvalidBackendAddress
622 );
623 }
624
625 #[test]
626 fn test_guest_memory_mmap_as_volatile_slice() {
627 let region_size = 0x400;
628 let region = GuestRegionMmap::from_range(GuestAddress(0), region_size, None).unwrap();
629
630 let slice = region.as_volatile_slice().unwrap();
632 assert_eq!(slice.len(), region_size);
633
634 let v = 0x1234_5678u32;
636 let r = slice.get_ref::<u32>(0x200).unwrap();
637 r.store(v);
638 assert_eq!(r.load(), v);
639 }
640
641 #[test]
642 fn test_guest_memory_get_slice() {
643 let start_addr1 = GuestAddress(0);
644 let start_addr2 = GuestAddress(0x800);
645 let guest_mem =
646 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
647
648 let slice_size = 0x200;
650 let slice = guest_mem
651 .get_slice(GuestAddress(0x100), slice_size)
652 .unwrap();
653 assert_eq!(slice.len(), slice_size);
654
655 let slice_size = 0x400;
656 let slice = guest_mem
657 .get_slice(GuestAddress(0x800), slice_size)
658 .unwrap();
659 assert_eq!(slice.len(), slice_size);
660
661 assert!(guest_mem
663 .get_slice(GuestAddress(0x900), 0)
664 .unwrap()
665 .is_empty());
666
667 assert_matches!(
669 guest_mem.get_slice(GuestAddress(0), 0x500).unwrap_err(),
670 GuestMemoryError::InvalidBackendAddress
671 );
672 assert_matches!(
673 guest_mem.get_slice(GuestAddress(0x600), 0x100).unwrap_err(),
674 GuestMemoryError::InvalidGuestAddress(GuestAddress(0x600))
675 );
676 assert_matches!(
677 guest_mem.get_slice(GuestAddress(0xc00), 0x100).unwrap_err(),
678 GuestMemoryError::InvalidGuestAddress(GuestAddress(0xc00))
679 );
680 }
681
682 #[test]
683 fn test_guest_memory_get_slices() {
684 let start_addr1 = GuestAddress(0);
685 let start_addr2 = GuestAddress(0x800);
686 let start_addr3 = GuestAddress(0xc00);
687 let guest_mem = GuestMemoryMmap::from_ranges(&[
688 (start_addr1, 0x400),
689 (start_addr2, 0x400),
690 (start_addr3, 0x400),
691 ])
692 .unwrap();
693
694 let slice_size = 0x200;
696 let mut slices = guest_mem.get_slices(GuestAddress(0x100), slice_size);
697 let slice = slices.next().unwrap().unwrap();
698 assert!(slices.next().is_none());
699 assert_eq!(slice.len(), slice_size);
700
701 let slice_size = 0x400;
702 let mut slices = guest_mem.get_slices(GuestAddress(0x800), slice_size);
703 let slice = slices.next().unwrap().unwrap();
704 assert!(slices.next().is_none());
705 assert_eq!(slice.len(), slice_size);
706
707 assert!(guest_mem
709 .get_slices(GuestAddress(0x900), 0)
710 .next()
711 .is_none());
712
713 let mut slices = guest_mem.get_slices(GuestAddress(0), 0x500);
715 assert_eq!(slices.next().unwrap().unwrap().len(), 0x400);
716 assert_matches!(
717 slices.next().unwrap().unwrap_err(),
718 GuestMemoryError::InvalidGuestAddress(GuestAddress(0x400))
719 );
720 assert!(slices.next().is_none());
721 let mut slices = guest_mem.get_slices(GuestAddress(0x600), 0x100);
722 assert_matches!(
723 slices.next().unwrap().unwrap_err(),
724 GuestMemoryError::InvalidGuestAddress(GuestAddress(0x600))
725 );
726 assert!(slices.next().is_none());
727 let mut slices = guest_mem.get_slices(GuestAddress(0x1000), 0x100);
728 assert_matches!(
729 slices.next().unwrap().unwrap_err(),
730 GuestMemoryError::InvalidGuestAddress(GuestAddress(0x1000))
731 );
732 assert!(slices.next().is_none());
733
734 let mut slices = guest_mem.get_slices(GuestAddress(0xa00), 0x400);
736 assert_eq!(slices.next().unwrap().unwrap().len(), 0x200);
737 assert_eq!(slices.next().unwrap().unwrap().len(), 0x200);
738 assert!(slices.next().is_none());
739 }
740
741 #[test]
742 fn test_atomic_accesses() {
743 let region = GuestRegionMmap::from_range(GuestAddress(0), 0x1000, None).unwrap();
744
745 crate::bytes::tests::check_atomic_accesses(
746 region,
747 MemoryRegionAddress(0),
748 MemoryRegionAddress(0x1000),
749 );
750 }
751
752 #[test]
753 #[cfg(feature = "backend-bitmap")]
754 fn test_dirty_tracking() {
755 crate::bitmap::tests::test_guest_memory_and_region(|| {
756 crate::GuestMemoryMmap::<AtomicBitmap>::from_ranges(&[(GuestAddress(0), 0x1_0000)])
757 .unwrap()
758 });
759 }
760
761 #[test]
762 fn test_change_region_addr() {
763 let addr1 = GuestAddress(0x1000);
764 let addr2 = GuestAddress(0x2000);
765 let gm = GuestMemoryMmap::from_ranges(&[(addr1, 0x1000)]).unwrap();
766
767 assert!(gm.find_region(addr1).is_some());
768 assert!(gm.find_region(addr2).is_none());
769
770 let (gm, region) = gm.remove_region(addr1, 0x1000).unwrap();
771
772 assert!(gm.find_region(addr1).is_none());
773 assert!(gm.find_region(addr2).is_none());
774
775 let region = GuestRegionMmap::with_arc(region.get_mmap(), addr2).unwrap();
779
780 let gm = gm.insert_region(Arc::new(region)).unwrap();
781
782 assert!(gm.find_region(addr1).is_none());
783 assert!(gm.find_region(addr2).is_some());
784 }
785}