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