1use std::borrow::Borrow;
16use std::io::{Read, Write};
17#[cfg(unix)]
18use std::io::{Seek, SeekFrom};
19use std::ops::Deref;
20use std::result;
21use std::sync::atomic::Ordering;
22use std::sync::Arc;
23
24use crate::address::Address;
25use crate::bitmap::{Bitmap, BS};
26use crate::guest_memory::{
27 self, FileOffset, GuestAddress, GuestMemory, GuestMemoryRegion, GuestUsize, MemoryRegionAddress,
28};
29use crate::volatile_memory::{VolatileMemory, VolatileSlice};
30use crate::{AtomicAccess, Bytes};
31
32#[cfg(all(not(feature = "xen"), unix))]
33pub use crate::mmap_unix::{Error as MmapRegionError, MmapRegion, MmapRegionBuilder};
34
35#[cfg(all(feature = "xen", unix))]
36pub use crate::mmap_xen::{Error as MmapRegionError, MmapRange, MmapRegion, MmapXenFlags};
37
38#[cfg(windows)]
39pub use crate::mmap_windows::MmapRegion;
40#[cfg(windows)]
41pub use std::io::Error as MmapRegionError;
42
43pub trait NewBitmap: Bitmap + Default {
45 fn with_len(len: usize) -> Self;
47}
48
49impl NewBitmap for () {
50 fn with_len(_len: usize) -> Self {}
51}
52
53#[derive(Debug, thiserror::Error)]
55pub enum Error {
56 #[error("Adding the guest base address to the length of the underlying mapping resulted in an overflow")]
59 InvalidGuestRegion,
60 #[error("{0}")]
62 MmapRegion(MmapRegionError),
63 #[error("No memory region found")]
65 NoMemoryRegion,
66 #[error("Some of the memory regions intersect with each other")]
68 MemoryRegionOverlap,
69 #[error("The provided memory regions haven't been sorted")]
71 UnsortedMemoryRegions,
72}
73
74#[cfg(unix)]
76pub fn check_file_offset(
81 file_offset: &FileOffset,
82 size: usize,
83) -> result::Result<(), MmapRegionError> {
84 let mut file = file_offset.file();
85 let start = file_offset.start();
86
87 if let Some(end) = start.checked_add(size as u64) {
88 let filesize = file
89 .seek(SeekFrom::End(0))
90 .map_err(MmapRegionError::SeekEnd)?;
91 file.rewind().map_err(MmapRegionError::SeekStart)?;
92 if filesize < end {
93 return Err(MmapRegionError::MappingPastEof);
94 }
95 } else {
96 return Err(MmapRegionError::InvalidOffsetLength);
97 }
98
99 Ok(())
100}
101
102#[derive(Debug)]
108pub struct GuestRegionMmap<B = ()> {
109 mapping: MmapRegion<B>,
110 guest_base: GuestAddress,
111}
112
113impl<B> Deref for GuestRegionMmap<B> {
114 type Target = MmapRegion<B>;
115
116 fn deref(&self) -> &MmapRegion<B> {
117 &self.mapping
118 }
119}
120
121impl<B: Bitmap> GuestRegionMmap<B> {
122 pub fn new(mapping: MmapRegion<B>, guest_base: GuestAddress) -> result::Result<Self, Error> {
124 if guest_base.0.checked_add(mapping.size() as u64).is_none() {
125 return Err(Error::InvalidGuestRegion);
126 }
127
128 Ok(GuestRegionMmap {
129 mapping,
130 guest_base,
131 })
132 }
133}
134
135#[cfg(not(feature = "xen"))]
136impl<B: NewBitmap> GuestRegionMmap<B> {
137 pub fn from_range(
139 addr: GuestAddress,
140 size: usize,
141 file: Option<FileOffset>,
142 ) -> result::Result<Self, Error> {
143 let region = if let Some(ref f_off) = file {
144 MmapRegion::from_file(f_off.clone(), size)
145 } else {
146 MmapRegion::new(size)
147 }
148 .map_err(Error::MmapRegion)?;
149
150 Self::new(region, addr)
151 }
152}
153
154#[cfg(feature = "xen")]
155impl<B: NewBitmap> GuestRegionMmap<B> {
156 pub fn from_range(
159 addr: GuestAddress,
160 size: usize,
161 file: Option<FileOffset>,
162 ) -> result::Result<Self, Error> {
163 let range = MmapRange::new_unix(size, file, addr);
164
165 let region = MmapRegion::from_range(range).map_err(Error::MmapRegion)?;
166 Self::new(region, addr)
167 }
168}
169
170impl<B: Bitmap> Bytes<MemoryRegionAddress> for GuestRegionMmap<B> {
171 type E = guest_memory::Error;
172
173 fn write(&self, buf: &[u8], addr: MemoryRegionAddress) -> guest_memory::Result<usize> {
189 let maddr = addr.raw_value() as usize;
190 self.as_volatile_slice()
191 .unwrap()
192 .write(buf, maddr)
193 .map_err(Into::into)
194 }
195
196 fn read(&self, buf: &mut [u8], addr: MemoryRegionAddress) -> guest_memory::Result<usize> {
213 let maddr = addr.raw_value() as usize;
214 self.as_volatile_slice()
215 .unwrap()
216 .read(buf, maddr)
217 .map_err(Into::into)
218 }
219
220 fn write_slice(&self, buf: &[u8], addr: MemoryRegionAddress) -> guest_memory::Result<()> {
221 let maddr = addr.raw_value() as usize;
222 self.as_volatile_slice()
223 .unwrap()
224 .write_slice(buf, maddr)
225 .map_err(Into::into)
226 }
227
228 fn read_slice(&self, buf: &mut [u8], addr: MemoryRegionAddress) -> guest_memory::Result<()> {
229 let maddr = addr.raw_value() as usize;
230 self.as_volatile_slice()
231 .unwrap()
232 .read_slice(buf, maddr)
233 .map_err(Into::into)
234 }
235
236 fn read_from<F>(
266 &self,
267 addr: MemoryRegionAddress,
268 src: &mut F,
269 count: usize,
270 ) -> guest_memory::Result<usize>
271 where
272 F: Read,
273 {
274 let maddr = addr.raw_value() as usize;
275 #[allow(deprecated)] self.as_volatile_slice()
277 .unwrap()
278 .read_from::<F>(maddr, src, count)
279 .map_err(Into::into)
280 }
281
282 fn read_exact_from<F>(
312 &self,
313 addr: MemoryRegionAddress,
314 src: &mut F,
315 count: usize,
316 ) -> guest_memory::Result<()>
317 where
318 F: Read,
319 {
320 let maddr = addr.raw_value() as usize;
321 #[allow(deprecated)] self.as_volatile_slice()
323 .unwrap()
324 .read_exact_from::<F>(maddr, src, count)
325 .map_err(Into::into)
326 }
327
328 fn write_to<F>(
358 &self,
359 addr: MemoryRegionAddress,
360 dst: &mut F,
361 count: usize,
362 ) -> guest_memory::Result<usize>
363 where
364 F: Write,
365 {
366 let maddr = addr.raw_value() as usize;
367 #[allow(deprecated)] self.as_volatile_slice()
369 .unwrap()
370 .write_to::<F>(maddr, dst, count)
371 .map_err(Into::into)
372 }
373
374 fn write_all_to<F>(
404 &self,
405 addr: MemoryRegionAddress,
406 dst: &mut F,
407 count: usize,
408 ) -> guest_memory::Result<()>
409 where
410 F: Write,
411 {
412 let maddr = addr.raw_value() as usize;
413 #[allow(deprecated)] self.as_volatile_slice()
415 .unwrap()
416 .write_all_to::<F>(maddr, dst, count)
417 .map_err(Into::into)
418 }
419
420 fn store<T: AtomicAccess>(
421 &self,
422 val: T,
423 addr: MemoryRegionAddress,
424 order: Ordering,
425 ) -> guest_memory::Result<()> {
426 self.as_volatile_slice().and_then(|s| {
427 s.store(val, addr.raw_value() as usize, order)
428 .map_err(Into::into)
429 })
430 }
431
432 fn load<T: AtomicAccess>(
433 &self,
434 addr: MemoryRegionAddress,
435 order: Ordering,
436 ) -> guest_memory::Result<T> {
437 self.as_volatile_slice()
438 .and_then(|s| s.load(addr.raw_value() as usize, order).map_err(Into::into))
439 }
440}
441
442impl<B: Bitmap> GuestMemoryRegion for GuestRegionMmap<B> {
443 type B = B;
444
445 fn len(&self) -> GuestUsize {
446 self.mapping.size() as GuestUsize
447 }
448
449 fn start_addr(&self) -> GuestAddress {
450 self.guest_base
451 }
452
453 fn bitmap(&self) -> &Self::B {
454 self.mapping.bitmap()
455 }
456
457 fn get_host_address(&self, addr: MemoryRegionAddress) -> guest_memory::Result<*mut u8> {
458 self.check_address(addr)
461 .ok_or(guest_memory::Error::InvalidBackendAddress)
462 .map(|addr| {
463 self.mapping
464 .as_ptr()
465 .wrapping_offset(addr.raw_value() as isize)
466 })
467 }
468
469 fn file_offset(&self) -> Option<&FileOffset> {
470 self.mapping.file_offset()
471 }
472
473 fn get_slice(
474 &self,
475 offset: MemoryRegionAddress,
476 count: usize,
477 ) -> guest_memory::Result<VolatileSlice<BS<B>>> {
478 let slice = self.mapping.get_slice(offset.raw_value() as usize, count)?;
479 Ok(slice)
480 }
481
482 #[cfg(target_os = "linux")]
483 fn is_hugetlbfs(&self) -> Option<bool> {
484 self.mapping.is_hugetlbfs()
485 }
486}
487
488#[derive(Clone, Debug, Default)]
495pub struct GuestMemoryMmap<B = ()> {
496 regions: Vec<Arc<GuestRegionMmap<B>>>,
497}
498
499impl<B: NewBitmap> GuestMemoryMmap<B> {
500 pub fn new() -> Self {
502 Self::default()
503 }
504
505 pub fn from_ranges(ranges: &[(GuestAddress, usize)]) -> result::Result<Self, Error> {
509 Self::from_ranges_with_files(ranges.iter().map(|r| (r.0, r.1, None)))
510 }
511
512 pub fn from_ranges_with_files<A, T>(ranges: T) -> result::Result<Self, Error>
517 where
518 A: Borrow<(GuestAddress, usize, Option<FileOffset>)>,
519 T: IntoIterator<Item = A>,
520 {
521 Self::from_regions(
522 ranges
523 .into_iter()
524 .map(|x| {
525 GuestRegionMmap::from_range(x.borrow().0, x.borrow().1, x.borrow().2.clone())
526 })
527 .collect::<result::Result<Vec<_>, Error>>()?,
528 )
529 }
530}
531
532impl<B: Bitmap> GuestMemoryMmap<B> {
533 pub fn from_regions(mut regions: Vec<GuestRegionMmap<B>>) -> result::Result<Self, Error> {
541 Self::from_arc_regions(regions.drain(..).map(Arc::new).collect())
542 }
543
544 pub fn from_arc_regions(regions: Vec<Arc<GuestRegionMmap<B>>>) -> result::Result<Self, Error> {
557 if regions.is_empty() {
558 return Err(Error::NoMemoryRegion);
559 }
560
561 for window in regions.windows(2) {
562 let prev = &window[0];
563 let next = &window[1];
564
565 if prev.start_addr() > next.start_addr() {
566 return Err(Error::UnsortedMemoryRegions);
567 }
568
569 if prev.last_addr() >= next.start_addr() {
570 return Err(Error::MemoryRegionOverlap);
571 }
572 }
573
574 Ok(Self { regions })
575 }
576
577 pub fn insert_region(
582 &self,
583 region: Arc<GuestRegionMmap<B>>,
584 ) -> result::Result<GuestMemoryMmap<B>, Error> {
585 let mut regions = self.regions.clone();
586 regions.push(region);
587 regions.sort_by_key(|x| x.start_addr());
588
589 Self::from_arc_regions(regions)
590 }
591
592 pub fn remove_region(
599 &self,
600 base: GuestAddress,
601 size: GuestUsize,
602 ) -> result::Result<(GuestMemoryMmap<B>, Arc<GuestRegionMmap<B>>), Error> {
603 if let Ok(region_index) = self.regions.binary_search_by_key(&base, |x| x.start_addr()) {
604 if self.regions.get(region_index).unwrap().mapping.size() as GuestUsize == size {
605 let mut regions = self.regions.clone();
606 let region = regions.remove(region_index);
607 return Ok((Self { regions }, region));
608 }
609 }
610
611 Err(Error::InvalidGuestRegion)
612 }
613}
614
615impl<B: Bitmap + 'static> GuestMemory for GuestMemoryMmap<B> {
616 type R = GuestRegionMmap<B>;
617
618 fn num_regions(&self) -> usize {
619 self.regions.len()
620 }
621
622 fn find_region(&self, addr: GuestAddress) -> Option<&GuestRegionMmap<B>> {
623 let index = match self.regions.binary_search_by_key(&addr, |x| x.start_addr()) {
624 Ok(x) => Some(x),
625 Err(x) if (x > 0 && addr <= self.regions[x - 1].last_addr()) => Some(x - 1),
627 _ => None,
628 };
629 index.map(|x| self.regions[x].as_ref())
630 }
631
632 fn iter(&self) -> impl Iterator<Item = &Self::R> {
633 self.regions.iter().map(AsRef::as_ref)
634 }
635}
636
637#[cfg(test)]
638mod tests {
639 #![allow(clippy::undocumented_unsafe_blocks)]
640 extern crate vmm_sys_util;
641
642 use super::*;
643
644 use crate::bitmap::tests::test_guest_memory_and_region;
645 use crate::bitmap::AtomicBitmap;
646 use crate::GuestAddressSpace;
647
648 use std::fs::File;
649 use std::mem;
650 use std::path::Path;
651 use vmm_sys_util::tempfile::TempFile;
652
653 type GuestMemoryMmap = super::GuestMemoryMmap<()>;
654 type GuestRegionMmap = super::GuestRegionMmap<()>;
655 type MmapRegion = super::MmapRegion<()>;
656
657 #[test]
658 fn basic_map() {
659 let m = MmapRegion::new(1024).unwrap();
660 assert_eq!(1024, m.size());
661 }
662
663 fn check_guest_memory_mmap(
664 maybe_guest_mem: Result<GuestMemoryMmap, Error>,
665 expected_regions_summary: &[(GuestAddress, usize)],
666 ) {
667 assert!(maybe_guest_mem.is_ok());
668
669 let guest_mem = maybe_guest_mem.unwrap();
670 assert_eq!(guest_mem.num_regions(), expected_regions_summary.len());
671 let maybe_last_mem_reg = expected_regions_summary.last();
672 if let Some((region_addr, region_size)) = maybe_last_mem_reg {
673 let mut last_addr = region_addr.unchecked_add(*region_size as u64);
674 if last_addr.raw_value() != 0 {
675 last_addr = last_addr.unchecked_sub(1);
676 }
677 assert_eq!(guest_mem.last_addr(), last_addr);
678 }
679 for ((region_addr, region_size), mmap) in expected_regions_summary
680 .iter()
681 .zip(guest_mem.regions.iter())
682 {
683 assert_eq!(region_addr, &mmap.guest_base);
684 assert_eq!(region_size, &mmap.mapping.size());
685
686 assert!(guest_mem.find_region(*region_addr).is_some());
687 }
688 }
689
690 fn new_guest_memory_mmap(
691 regions_summary: &[(GuestAddress, usize)],
692 ) -> Result<GuestMemoryMmap, Error> {
693 GuestMemoryMmap::from_ranges(regions_summary)
694 }
695
696 fn new_guest_memory_mmap_from_regions(
697 regions_summary: &[(GuestAddress, usize)],
698 ) -> Result<GuestMemoryMmap, Error> {
699 GuestMemoryMmap::from_regions(
700 regions_summary
701 .iter()
702 .map(|(region_addr, region_size)| {
703 GuestRegionMmap::from_range(*region_addr, *region_size, None).unwrap()
704 })
705 .collect(),
706 )
707 }
708
709 fn new_guest_memory_mmap_from_arc_regions(
710 regions_summary: &[(GuestAddress, usize)],
711 ) -> Result<GuestMemoryMmap, Error> {
712 GuestMemoryMmap::from_arc_regions(
713 regions_summary
714 .iter()
715 .map(|(region_addr, region_size)| {
716 Arc::new(GuestRegionMmap::from_range(*region_addr, *region_size, None).unwrap())
717 })
718 .collect(),
719 )
720 }
721
722 fn new_guest_memory_mmap_with_files(
723 regions_summary: &[(GuestAddress, usize)],
724 ) -> Result<GuestMemoryMmap, Error> {
725 let regions: Vec<(GuestAddress, usize, Option<FileOffset>)> = regions_summary
726 .iter()
727 .map(|(region_addr, region_size)| {
728 let f = TempFile::new().unwrap().into_file();
729 f.set_len(*region_size as u64).unwrap();
730
731 (*region_addr, *region_size, Some(FileOffset::new(f, 0)))
732 })
733 .collect();
734
735 GuestMemoryMmap::from_ranges_with_files(®ions)
736 }
737
738 #[test]
739 fn test_no_memory_region() {
740 let regions_summary = [];
741
742 assert_eq!(
743 format!(
744 "{:?}",
745 new_guest_memory_mmap(®ions_summary).err().unwrap()
746 ),
747 format!("{:?}", Error::NoMemoryRegion)
748 );
749
750 assert_eq!(
751 format!(
752 "{:?}",
753 new_guest_memory_mmap_with_files(®ions_summary)
754 .err()
755 .unwrap()
756 ),
757 format!("{:?}", Error::NoMemoryRegion)
758 );
759
760 assert_eq!(
761 format!(
762 "{:?}",
763 new_guest_memory_mmap_from_regions(®ions_summary)
764 .err()
765 .unwrap()
766 ),
767 format!("{:?}", Error::NoMemoryRegion)
768 );
769
770 assert_eq!(
771 format!(
772 "{:?}",
773 new_guest_memory_mmap_from_arc_regions(®ions_summary)
774 .err()
775 .unwrap()
776 ),
777 format!("{:?}", Error::NoMemoryRegion)
778 );
779 }
780
781 #[test]
782 fn test_overlapping_memory_regions() {
783 let regions_summary = [(GuestAddress(0), 100_usize), (GuestAddress(99), 100_usize)];
784
785 assert_eq!(
786 format!(
787 "{:?}",
788 new_guest_memory_mmap(®ions_summary).err().unwrap()
789 ),
790 format!("{:?}", Error::MemoryRegionOverlap)
791 );
792
793 assert_eq!(
794 format!(
795 "{:?}",
796 new_guest_memory_mmap_with_files(®ions_summary)
797 .err()
798 .unwrap()
799 ),
800 format!("{:?}", Error::MemoryRegionOverlap)
801 );
802
803 assert_eq!(
804 format!(
805 "{:?}",
806 new_guest_memory_mmap_from_regions(®ions_summary)
807 .err()
808 .unwrap()
809 ),
810 format!("{:?}", Error::MemoryRegionOverlap)
811 );
812
813 assert_eq!(
814 format!(
815 "{:?}",
816 new_guest_memory_mmap_from_arc_regions(®ions_summary)
817 .err()
818 .unwrap()
819 ),
820 format!("{:?}", Error::MemoryRegionOverlap)
821 );
822 }
823
824 #[test]
825 fn test_unsorted_memory_regions() {
826 let regions_summary = [(GuestAddress(100), 100_usize), (GuestAddress(0), 100_usize)];
827
828 assert_eq!(
829 format!(
830 "{:?}",
831 new_guest_memory_mmap(®ions_summary).err().unwrap()
832 ),
833 format!("{:?}", Error::UnsortedMemoryRegions)
834 );
835
836 assert_eq!(
837 format!(
838 "{:?}",
839 new_guest_memory_mmap_with_files(®ions_summary)
840 .err()
841 .unwrap()
842 ),
843 format!("{:?}", Error::UnsortedMemoryRegions)
844 );
845
846 assert_eq!(
847 format!(
848 "{:?}",
849 new_guest_memory_mmap_from_regions(®ions_summary)
850 .err()
851 .unwrap()
852 ),
853 format!("{:?}", Error::UnsortedMemoryRegions)
854 );
855
856 assert_eq!(
857 format!(
858 "{:?}",
859 new_guest_memory_mmap_from_arc_regions(®ions_summary)
860 .err()
861 .unwrap()
862 ),
863 format!("{:?}", Error::UnsortedMemoryRegions)
864 );
865 }
866
867 #[test]
868 fn test_valid_memory_regions() {
869 let regions_summary = [(GuestAddress(0), 100_usize), (GuestAddress(100), 100_usize)];
870
871 let guest_mem = GuestMemoryMmap::new();
872 assert_eq!(guest_mem.regions.len(), 0);
873
874 check_guest_memory_mmap(new_guest_memory_mmap(®ions_summary), ®ions_summary);
875
876 check_guest_memory_mmap(
877 new_guest_memory_mmap_with_files(®ions_summary),
878 ®ions_summary,
879 );
880
881 check_guest_memory_mmap(
882 new_guest_memory_mmap_from_regions(®ions_summary),
883 ®ions_summary,
884 );
885
886 check_guest_memory_mmap(
887 new_guest_memory_mmap_from_arc_regions(®ions_summary),
888 ®ions_summary,
889 );
890 }
891
892 #[test]
893 fn slice_addr() {
894 let m = GuestRegionMmap::from_range(GuestAddress(0), 5, None).unwrap();
895 let s = m.get_slice(MemoryRegionAddress(2), 3).unwrap();
896 let guard = s.ptr_guard();
897 assert_eq!(guard.as_ptr(), unsafe { m.as_ptr().offset(2) });
898 }
899
900 #[test]
901 #[cfg(not(miri))] fn mapped_file_read() {
903 let mut f = TempFile::new().unwrap().into_file();
904 let sample_buf = &[1, 2, 3, 4, 5];
905 assert!(f.write_all(sample_buf).is_ok());
906
907 let file = Some(FileOffset::new(f, 0));
908 let mem_map = GuestRegionMmap::from_range(GuestAddress(0), sample_buf.len(), file).unwrap();
909 let buf = &mut [0u8; 16];
910 assert_eq!(
911 mem_map.as_volatile_slice().unwrap().read(buf, 0).unwrap(),
912 sample_buf.len()
913 );
914 assert_eq!(buf[0..sample_buf.len()], sample_buf[..]);
915 }
916
917 #[test]
918 fn test_address_in_range() {
919 let f1 = TempFile::new().unwrap().into_file();
920 f1.set_len(0x400).unwrap();
921 let f2 = TempFile::new().unwrap().into_file();
922 f2.set_len(0x400).unwrap();
923
924 let start_addr1 = GuestAddress(0x0);
925 let start_addr2 = GuestAddress(0x800);
926 let guest_mem =
927 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
928 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
929 (start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
930 (start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
931 ])
932 .unwrap();
933
934 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
935 for guest_mem in guest_mem_list.iter() {
936 assert!(guest_mem.address_in_range(GuestAddress(0x200)));
937 assert!(!guest_mem.address_in_range(GuestAddress(0x600)));
938 assert!(guest_mem.address_in_range(GuestAddress(0xa00)));
939 assert!(!guest_mem.address_in_range(GuestAddress(0xc00)));
940 }
941 }
942
943 #[test]
944 fn test_check_address() {
945 let f1 = TempFile::new().unwrap().into_file();
946 f1.set_len(0x400).unwrap();
947 let f2 = TempFile::new().unwrap().into_file();
948 f2.set_len(0x400).unwrap();
949
950 let start_addr1 = GuestAddress(0x0);
951 let start_addr2 = GuestAddress(0x800);
952 let guest_mem =
953 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
954 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
955 (start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
956 (start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
957 ])
958 .unwrap();
959
960 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
961 for guest_mem in guest_mem_list.iter() {
962 assert_eq!(
963 guest_mem.check_address(GuestAddress(0x200)),
964 Some(GuestAddress(0x200))
965 );
966 assert_eq!(guest_mem.check_address(GuestAddress(0x600)), None);
967 assert_eq!(
968 guest_mem.check_address(GuestAddress(0xa00)),
969 Some(GuestAddress(0xa00))
970 );
971 assert_eq!(guest_mem.check_address(GuestAddress(0xc00)), None);
972 }
973 }
974
975 #[test]
976 fn test_to_region_addr() {
977 let f1 = TempFile::new().unwrap().into_file();
978 f1.set_len(0x400).unwrap();
979 let f2 = TempFile::new().unwrap().into_file();
980 f2.set_len(0x400).unwrap();
981
982 let start_addr1 = GuestAddress(0x0);
983 let start_addr2 = GuestAddress(0x800);
984 let guest_mem =
985 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
986 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
987 (start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
988 (start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
989 ])
990 .unwrap();
991
992 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
993 for guest_mem in guest_mem_list.iter() {
994 assert!(guest_mem.to_region_addr(GuestAddress(0x600)).is_none());
995 let (r0, addr0) = guest_mem.to_region_addr(GuestAddress(0x800)).unwrap();
996 let (r1, addr1) = guest_mem.to_region_addr(GuestAddress(0xa00)).unwrap();
997 assert!(r0.as_ptr() == r1.as_ptr());
998 assert_eq!(addr0, MemoryRegionAddress(0));
999 assert_eq!(addr1, MemoryRegionAddress(0x200));
1000 }
1001 }
1002
1003 #[test]
1004 fn test_get_host_address() {
1005 let f1 = TempFile::new().unwrap().into_file();
1006 f1.set_len(0x400).unwrap();
1007 let f2 = TempFile::new().unwrap().into_file();
1008 f2.set_len(0x400).unwrap();
1009
1010 let start_addr1 = GuestAddress(0x0);
1011 let start_addr2 = GuestAddress(0x800);
1012 let guest_mem =
1013 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
1014 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
1015 (start_addr1, 0x400, Some(FileOffset::new(f1, 0))),
1016 (start_addr2, 0x400, Some(FileOffset::new(f2, 0))),
1017 ])
1018 .unwrap();
1019
1020 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
1021 for guest_mem in guest_mem_list.iter() {
1022 assert!(guest_mem.get_host_address(GuestAddress(0x600)).is_err());
1023 let ptr0 = guest_mem.get_host_address(GuestAddress(0x800)).unwrap();
1024 let ptr1 = guest_mem.get_host_address(GuestAddress(0xa00)).unwrap();
1025 assert_eq!(
1026 ptr0,
1027 guest_mem.find_region(GuestAddress(0x800)).unwrap().as_ptr()
1028 );
1029 assert_eq!(unsafe { ptr0.offset(0x200) }, ptr1);
1030 }
1031 }
1032
1033 #[test]
1034 fn test_deref() {
1035 let f = TempFile::new().unwrap().into_file();
1036 f.set_len(0x400).unwrap();
1037
1038 let start_addr = GuestAddress(0x0);
1039 let guest_mem = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
1040 let guest_mem_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[(
1041 start_addr,
1042 0x400,
1043 Some(FileOffset::new(f, 0)),
1044 )])
1045 .unwrap();
1046
1047 let guest_mem_list = [guest_mem, guest_mem_backed_by_file];
1048 for guest_mem in guest_mem_list.iter() {
1049 let sample_buf = &[1, 2, 3, 4, 5];
1050
1051 assert_eq!(guest_mem.write(sample_buf, start_addr).unwrap(), 5);
1052 let slice = guest_mem
1053 .find_region(GuestAddress(0))
1054 .unwrap()
1055 .as_volatile_slice()
1056 .unwrap();
1057
1058 let buf = &mut [0, 0, 0, 0, 0];
1059 assert_eq!(slice.read(buf, 0).unwrap(), 5);
1060 assert_eq!(buf, sample_buf);
1061 }
1062 }
1063
1064 #[test]
1065 fn test_read_u64() {
1066 let f1 = TempFile::new().unwrap().into_file();
1067 f1.set_len(0x1000).unwrap();
1068 let f2 = TempFile::new().unwrap().into_file();
1069 f2.set_len(0x1000).unwrap();
1070
1071 let start_addr1 = GuestAddress(0x0);
1072 let start_addr2 = GuestAddress(0x1000);
1073 let bad_addr = GuestAddress(0x2001);
1074 let bad_addr2 = GuestAddress(0x1ffc);
1075 let max_addr = GuestAddress(0x2000);
1076
1077 let gm =
1078 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
1079 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
1080 (start_addr1, 0x1000, Some(FileOffset::new(f1, 0))),
1081 (start_addr2, 0x1000, Some(FileOffset::new(f2, 0))),
1082 ])
1083 .unwrap();
1084
1085 let gm_list = [gm, gm_backed_by_file];
1086 for gm in gm_list.iter() {
1087 let val1: u64 = 0xaa55_aa55_aa55_aa55;
1088 let val2: u64 = 0x55aa_55aa_55aa_55aa;
1089 assert_eq!(
1090 format!("{:?}", gm.write_obj(val1, bad_addr).err().unwrap()),
1091 format!("InvalidGuestAddress({:?})", bad_addr,)
1092 );
1093 assert_eq!(
1094 format!("{:?}", gm.write_obj(val1, bad_addr2).err().unwrap()),
1095 format!(
1096 "PartialBuffer {{ expected: {:?}, completed: {:?} }}",
1097 mem::size_of::<u64>(),
1098 max_addr.checked_offset_from(bad_addr2).unwrap()
1099 )
1100 );
1101
1102 gm.write_obj(val1, GuestAddress(0x500)).unwrap();
1103 gm.write_obj(val2, GuestAddress(0x1000 + 32)).unwrap();
1104 let num1: u64 = gm.read_obj(GuestAddress(0x500)).unwrap();
1105 let num2: u64 = gm.read_obj(GuestAddress(0x1000 + 32)).unwrap();
1106 assert_eq!(val1, num1);
1107 assert_eq!(val2, num2);
1108 }
1109 }
1110
1111 #[test]
1112 fn write_and_read() {
1113 let f = TempFile::new().unwrap().into_file();
1114 f.set_len(0x400).unwrap();
1115
1116 let mut start_addr = GuestAddress(0x1000);
1117 let gm = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
1118 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[(
1119 start_addr,
1120 0x400,
1121 Some(FileOffset::new(f, 0)),
1122 )])
1123 .unwrap();
1124
1125 let gm_list = [gm, gm_backed_by_file];
1126 for gm in gm_list.iter() {
1127 let sample_buf = &[1, 2, 3, 4, 5];
1128
1129 assert_eq!(gm.write(sample_buf, start_addr).unwrap(), 5);
1130
1131 let buf = &mut [0u8; 5];
1132 assert_eq!(gm.read(buf, start_addr).unwrap(), 5);
1133 assert_eq!(buf, sample_buf);
1134
1135 start_addr = GuestAddress(0x13ff);
1136 assert_eq!(gm.write(sample_buf, start_addr).unwrap(), 1);
1137 assert_eq!(gm.read(buf, start_addr).unwrap(), 1);
1138 assert_eq!(buf[0], sample_buf[0]);
1139 start_addr = GuestAddress(0x1000);
1140 }
1141 }
1142
1143 #[test]
1144 fn read_to_and_write_from_mem() {
1145 let f = TempFile::new().unwrap().into_file();
1146 f.set_len(0x400).unwrap();
1147
1148 let gm = GuestMemoryMmap::from_ranges(&[(GuestAddress(0x1000), 0x400)]).unwrap();
1149 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[(
1150 GuestAddress(0x1000),
1151 0x400,
1152 Some(FileOffset::new(f, 0)),
1153 )])
1154 .unwrap();
1155
1156 let gm_list = [gm, gm_backed_by_file];
1157 for gm in gm_list.iter() {
1158 let addr = GuestAddress(0x1010);
1159 let mut file = if cfg!(unix) {
1160 File::open(Path::new("/dev/zero")).unwrap()
1161 } else {
1162 File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe")).unwrap()
1163 };
1164 gm.write_obj(!0u32, addr).unwrap();
1165 gm.read_exact_volatile_from(addr, &mut file, mem::size_of::<u32>())
1166 .unwrap();
1167 let value: u32 = gm.read_obj(addr).unwrap();
1168 if cfg!(unix) {
1169 assert_eq!(value, 0);
1170 } else {
1171 assert_eq!(value, 0x0090_5a4d);
1172 }
1173
1174 let mut sink = vec![0; mem::size_of::<u32>()];
1175 gm.write_all_volatile_to(addr, &mut sink.as_mut_slice(), mem::size_of::<u32>())
1176 .unwrap();
1177 if cfg!(unix) {
1178 assert_eq!(sink, vec![0; mem::size_of::<u32>()]);
1179 } else {
1180 assert_eq!(sink, vec![0x4d, 0x5a, 0x90, 0x00]);
1181 };
1182 }
1183 }
1184
1185 #[test]
1186 fn create_vec_with_regions() {
1187 let region_size = 0x400;
1188 let regions = vec![
1189 (GuestAddress(0x0), region_size),
1190 (GuestAddress(0x1000), region_size),
1191 ];
1192 let mut iterated_regions = Vec::new();
1193 let gm = GuestMemoryMmap::from_ranges(®ions).unwrap();
1194
1195 for region in gm.iter() {
1196 assert_eq!(region.len(), region_size as GuestUsize);
1197 }
1198
1199 for region in gm.iter() {
1200 iterated_regions.push((region.start_addr(), region.len() as usize));
1201 }
1202 assert_eq!(regions, iterated_regions);
1203
1204 assert!(regions
1205 .iter()
1206 .map(|x| (x.0, x.1))
1207 .eq(iterated_regions.iter().copied()));
1208
1209 assert_eq!(gm.regions[0].guest_base, regions[0].0);
1210 assert_eq!(gm.regions[1].guest_base, regions[1].0);
1211 }
1212
1213 #[test]
1214 fn test_memory() {
1215 let region_size = 0x400;
1216 let regions = vec![
1217 (GuestAddress(0x0), region_size),
1218 (GuestAddress(0x1000), region_size),
1219 ];
1220 let mut iterated_regions = Vec::new();
1221 let gm = Arc::new(GuestMemoryMmap::from_ranges(®ions).unwrap());
1222 let mem = gm.memory();
1223
1224 for region in mem.iter() {
1225 assert_eq!(region.len(), region_size as GuestUsize);
1226 }
1227
1228 for region in mem.iter() {
1229 iterated_regions.push((region.start_addr(), region.len() as usize));
1230 }
1231 assert_eq!(regions, iterated_regions);
1232
1233 assert!(regions
1234 .iter()
1235 .map(|x| (x.0, x.1))
1236 .eq(iterated_regions.iter().copied()));
1237
1238 assert_eq!(gm.regions[0].guest_base, regions[0].0);
1239 assert_eq!(gm.regions[1].guest_base, regions[1].0);
1240 }
1241
1242 #[test]
1243 fn test_access_cross_boundary() {
1244 let f1 = TempFile::new().unwrap().into_file();
1245 f1.set_len(0x1000).unwrap();
1246 let f2 = TempFile::new().unwrap().into_file();
1247 f2.set_len(0x1000).unwrap();
1248
1249 let start_addr1 = GuestAddress(0x0);
1250 let start_addr2 = GuestAddress(0x1000);
1251 let gm =
1252 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x1000), (start_addr2, 0x1000)]).unwrap();
1253 let gm_backed_by_file = GuestMemoryMmap::from_ranges_with_files(&[
1254 (start_addr1, 0x1000, Some(FileOffset::new(f1, 0))),
1255 (start_addr2, 0x1000, Some(FileOffset::new(f2, 0))),
1256 ])
1257 .unwrap();
1258
1259 let gm_list = [gm, gm_backed_by_file];
1260 for gm in gm_list.iter() {
1261 let sample_buf = &[1, 2, 3, 4, 5];
1262 assert_eq!(gm.write(sample_buf, GuestAddress(0xffc)).unwrap(), 5);
1263 let buf = &mut [0u8; 5];
1264 assert_eq!(gm.read(buf, GuestAddress(0xffc)).unwrap(), 5);
1265 assert_eq!(buf, sample_buf);
1266 }
1267 }
1268
1269 #[test]
1270 fn test_retrieve_fd_backing_memory_region() {
1271 let f = TempFile::new().unwrap().into_file();
1272 f.set_len(0x400).unwrap();
1273
1274 let start_addr = GuestAddress(0x0);
1275 let gm = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
1276 assert!(gm.find_region(start_addr).is_some());
1277 let region = gm.find_region(start_addr).unwrap();
1278 assert!(region.file_offset().is_none());
1279
1280 let gm = GuestMemoryMmap::from_ranges_with_files(&[(
1281 start_addr,
1282 0x400,
1283 Some(FileOffset::new(f, 0)),
1284 )])
1285 .unwrap();
1286 assert!(gm.find_region(start_addr).is_some());
1287 let region = gm.find_region(start_addr).unwrap();
1288 assert!(region.file_offset().is_some());
1289 }
1290
1291 #[test]
1296 #[cfg(unix)]
1297 fn test_retrieve_offset_from_fd_backing_memory_region() {
1298 let f = TempFile::new().unwrap().into_file();
1299 f.set_len(0x1400).unwrap();
1300 let offset = 0x1000;
1302
1303 let start_addr = GuestAddress(0x0);
1304 let gm = GuestMemoryMmap::from_ranges(&[(start_addr, 0x400)]).unwrap();
1305 assert!(gm.find_region(start_addr).is_some());
1306 let region = gm.find_region(start_addr).unwrap();
1307 assert!(region.file_offset().is_none());
1308
1309 let gm = GuestMemoryMmap::from_ranges_with_files(&[(
1310 start_addr,
1311 0x400,
1312 Some(FileOffset::new(f, offset)),
1313 )])
1314 .unwrap();
1315 assert!(gm.find_region(start_addr).is_some());
1316 let region = gm.find_region(start_addr).unwrap();
1317 assert!(region.file_offset().is_some());
1318 assert_eq!(region.file_offset().unwrap().start(), offset);
1319 }
1320
1321 #[test]
1322 fn test_mmap_insert_region() {
1323 let region_size = 0x1000;
1324 let regions = vec![
1325 (GuestAddress(0x0), region_size),
1326 (GuestAddress(0x10_0000), region_size),
1327 ];
1328 let gm = Arc::new(GuestMemoryMmap::from_ranges(®ions).unwrap());
1329 let mem_orig = gm.memory();
1330 assert_eq!(mem_orig.num_regions(), 2);
1331
1332 let mmap =
1333 Arc::new(GuestRegionMmap::from_range(GuestAddress(0x8000), 0x1000, None).unwrap());
1334 let gm = gm.insert_region(mmap).unwrap();
1335 let mmap =
1336 Arc::new(GuestRegionMmap::from_range(GuestAddress(0x4000), 0x1000, None).unwrap());
1337 let gm = gm.insert_region(mmap).unwrap();
1338 let mmap =
1339 Arc::new(GuestRegionMmap::from_range(GuestAddress(0xc000), 0x1000, None).unwrap());
1340 let gm = gm.insert_region(mmap).unwrap();
1341 let mmap =
1342 Arc::new(GuestRegionMmap::from_range(GuestAddress(0xc000), 0x1000, None).unwrap());
1343 gm.insert_region(mmap).unwrap_err();
1344
1345 assert_eq!(mem_orig.num_regions(), 2);
1346 assert_eq!(gm.num_regions(), 5);
1347
1348 assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1349 assert_eq!(gm.regions[1].start_addr(), GuestAddress(0x4000));
1350 assert_eq!(gm.regions[2].start_addr(), GuestAddress(0x8000));
1351 assert_eq!(gm.regions[3].start_addr(), GuestAddress(0xc000));
1352 assert_eq!(gm.regions[4].start_addr(), GuestAddress(0x10_0000));
1353 }
1354
1355 #[test]
1356 fn test_mmap_remove_region() {
1357 let region_size = 0x1000;
1358 let regions = vec![
1359 (GuestAddress(0x0), region_size),
1360 (GuestAddress(0x10_0000), region_size),
1361 ];
1362 let gm = Arc::new(GuestMemoryMmap::from_ranges(®ions).unwrap());
1363 let mem_orig = gm.memory();
1364 assert_eq!(mem_orig.num_regions(), 2);
1365
1366 gm.remove_region(GuestAddress(0), 128).unwrap_err();
1367 gm.remove_region(GuestAddress(0x4000), 128).unwrap_err();
1368 let (gm, region) = gm.remove_region(GuestAddress(0x10_0000), 0x1000).unwrap();
1369
1370 assert_eq!(mem_orig.num_regions(), 2);
1371 assert_eq!(gm.num_regions(), 1);
1372
1373 assert_eq!(gm.regions[0].start_addr(), GuestAddress(0x0000));
1374 assert_eq!(region.start_addr(), GuestAddress(0x10_0000));
1375 }
1376
1377 #[test]
1378 fn test_guest_memory_mmap_get_slice() {
1379 let region = GuestRegionMmap::from_range(GuestAddress(0), 0x400, None).unwrap();
1380
1381 let slice_addr = MemoryRegionAddress(0x100);
1383 let slice_size = 0x200;
1384 let slice = region.get_slice(slice_addr, slice_size).unwrap();
1385 assert_eq!(slice.len(), slice_size);
1386
1387 let slice_addr = MemoryRegionAddress(0x200);
1389 let slice_size = 0x0;
1390 let slice = region.get_slice(slice_addr, slice_size).unwrap();
1391 assert!(slice.is_empty());
1392
1393 let slice_addr = MemoryRegionAddress(0x300);
1395 let slice_size = 0x200;
1396 assert!(region.get_slice(slice_addr, slice_size).is_err());
1397 }
1398
1399 #[test]
1400 fn test_guest_memory_mmap_as_volatile_slice() {
1401 let region_size = 0x400;
1402 let region = GuestRegionMmap::from_range(GuestAddress(0), region_size, None).unwrap();
1403
1404 let slice = region.as_volatile_slice().unwrap();
1406 assert_eq!(slice.len(), region_size);
1407
1408 let v = 0x1234_5678u32;
1410 let r = slice.get_ref::<u32>(0x200).unwrap();
1411 r.store(v);
1412 assert_eq!(r.load(), v);
1413 }
1414
1415 #[test]
1416 fn test_guest_memory_get_slice() {
1417 let start_addr1 = GuestAddress(0);
1418 let start_addr2 = GuestAddress(0x800);
1419 let guest_mem =
1420 GuestMemoryMmap::from_ranges(&[(start_addr1, 0x400), (start_addr2, 0x400)]).unwrap();
1421
1422 let slice_size = 0x200;
1424 let slice = guest_mem
1425 .get_slice(GuestAddress(0x100), slice_size)
1426 .unwrap();
1427 assert_eq!(slice.len(), slice_size);
1428
1429 let slice_size = 0x400;
1430 let slice = guest_mem
1431 .get_slice(GuestAddress(0x800), slice_size)
1432 .unwrap();
1433 assert_eq!(slice.len(), slice_size);
1434
1435 assert!(guest_mem
1437 .get_slice(GuestAddress(0x900), 0)
1438 .unwrap()
1439 .is_empty());
1440
1441 assert!(guest_mem.get_slice(GuestAddress(0), 0x500).is_err());
1443 assert!(guest_mem.get_slice(GuestAddress(0x600), 0x100).is_err());
1444 assert!(guest_mem.get_slice(GuestAddress(0xc00), 0x100).is_err());
1445 }
1446
1447 #[test]
1448 fn test_checked_offset() {
1449 let start_addr1 = GuestAddress(0);
1450 let start_addr2 = GuestAddress(0x800);
1451 let start_addr3 = GuestAddress(0xc00);
1452 let guest_mem = GuestMemoryMmap::from_ranges(&[
1453 (start_addr1, 0x400),
1454 (start_addr2, 0x400),
1455 (start_addr3, 0x400),
1456 ])
1457 .unwrap();
1458
1459 assert_eq!(
1460 guest_mem.checked_offset(start_addr1, 0x200),
1461 Some(GuestAddress(0x200))
1462 );
1463 assert_eq!(
1464 guest_mem.checked_offset(start_addr1, 0xa00),
1465 Some(GuestAddress(0xa00))
1466 );
1467 assert_eq!(
1468 guest_mem.checked_offset(start_addr2, 0x7ff),
1469 Some(GuestAddress(0xfff))
1470 );
1471 assert_eq!(guest_mem.checked_offset(start_addr2, 0xc00), None);
1472 assert_eq!(guest_mem.checked_offset(start_addr1, usize::MAX), None);
1473
1474 assert_eq!(guest_mem.checked_offset(start_addr1, 0x400), None);
1475 assert_eq!(
1476 guest_mem.checked_offset(start_addr1, 0x400 - 1),
1477 Some(GuestAddress(0x400 - 1))
1478 );
1479 }
1480
1481 #[test]
1482 fn test_check_range() {
1483 let start_addr1 = GuestAddress(0);
1484 let start_addr2 = GuestAddress(0x800);
1485 let start_addr3 = GuestAddress(0xc00);
1486 let guest_mem = GuestMemoryMmap::from_ranges(&[
1487 (start_addr1, 0x400),
1488 (start_addr2, 0x400),
1489 (start_addr3, 0x400),
1490 ])
1491 .unwrap();
1492
1493 assert!(guest_mem.check_range(start_addr1, 0x0));
1494 assert!(guest_mem.check_range(start_addr1, 0x200));
1495 assert!(guest_mem.check_range(start_addr1, 0x400));
1496 assert!(!guest_mem.check_range(start_addr1, 0xa00));
1497 assert!(guest_mem.check_range(start_addr2, 0x7ff));
1498 assert!(guest_mem.check_range(start_addr2, 0x800));
1499 assert!(!guest_mem.check_range(start_addr2, 0x801));
1500 assert!(!guest_mem.check_range(start_addr2, 0xc00));
1501 assert!(!guest_mem.check_range(start_addr1, usize::MAX));
1502 }
1503
1504 #[test]
1505 fn test_atomic_accesses() {
1506 let region = GuestRegionMmap::from_range(GuestAddress(0), 0x1000, None).unwrap();
1507
1508 crate::bytes::tests::check_atomic_accesses(
1509 region,
1510 MemoryRegionAddress(0),
1511 MemoryRegionAddress(0x1000),
1512 );
1513 }
1514
1515 #[test]
1516 fn test_dirty_tracking() {
1517 test_guest_memory_and_region(|| {
1518 crate::GuestMemoryMmap::<AtomicBitmap>::from_ranges(&[(GuestAddress(0), 0x1_0000)])
1519 .unwrap()
1520 });
1521 }
1522}