vm_memory/
mmap.rs

1// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved.
2//
3// Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4//
5// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
6// Use of this source code is governed by a BSD-style license that can be
7// found in the LICENSE-BSD-3-Clause file.
8//
9// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
10
11//! The default implementation for the [`GuestMemory`](trait.GuestMemory.html) trait.
12//!
13//! This implementation is mmap-ing the memory of the guest into the current process.
14
15use 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
43/// A `Bitmap` that can be created starting from an initial size.
44pub trait NewBitmap: Bitmap + Default {
45    /// Create a new object based on the specified length in bytes.
46    fn with_len(len: usize) -> Self;
47}
48
49impl NewBitmap for () {
50    fn with_len(_len: usize) -> Self {}
51}
52
53/// Errors that can occur when creating a memory map.
54#[derive(Debug, thiserror::Error)]
55pub enum Error {
56    /// Adding the guest base address to the length of the underlying mapping resulted
57    /// in an overflow.
58    #[error("Adding the guest base address to the length of the underlying mapping resulted in an overflow")]
59    InvalidGuestRegion,
60    /// Error creating a `MmapRegion` object.
61    #[error("{0}")]
62    MmapRegion(MmapRegionError),
63    /// No memory region found.
64    #[error("No memory region found")]
65    NoMemoryRegion,
66    /// Some of the memory regions intersect with each other.
67    #[error("Some of the memory regions intersect with each other")]
68    MemoryRegionOverlap,
69    /// The provided memory regions haven't been sorted.
70    #[error("The provided memory regions haven't been sorted")]
71    UnsortedMemoryRegions,
72}
73
74// TODO: use this for Windows as well after we redefine the Error type there.
75#[cfg(unix)]
76/// Checks if a mapping of `size` bytes fits at the provided `file_offset`.
77///
78/// For a borrowed `FileOffset` and size, this function checks whether the mapping does not
79/// extend past EOF, and that adding the size to the file offset does not lead to overflow.
80pub 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/// [`GuestMemoryRegion`](trait.GuestMemoryRegion.html) implementation that mmaps the guest's
103/// memory region in the current process.
104///
105/// Represents a continuous region of the guest's physical memory that is backed by a mapping
106/// in the virtual address space of the calling process.
107#[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    /// Create a new memory-mapped memory region for the guest's physical memory.
123    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    /// Create a new memory-mapped memory region from guest's physical memory, size and file.
138    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    /// Create a new Unix memory-mapped memory region from guest's physical memory, size and file.
157    /// This must only be used for tests, doctests, benches and is not designed for end consumers.
158    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    /// # Examples
174    /// * Write a slice at guest address 0x1200.
175    ///
176    /// ```
177    /// # use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
178    /// #
179    /// # let start_addr = GuestAddress(0x1000);
180    /// # let mut gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
181    /// #    .expect("Could not create guest memory");
182    /// #
183    /// let res = gm
184    ///     .write(&[1, 2, 3, 4, 5], GuestAddress(0x1200))
185    ///     .expect("Could not write to guest memory");
186    /// assert_eq!(5, res);
187    /// ```
188    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    /// # Examples
197    /// * Read a slice of length 16 at guestaddress 0x1200.
198    ///
199    /// ```
200    /// # use vm_memory::{Bytes, GuestAddress, GuestMemoryMmap};
201    /// #
202    /// # let start_addr = GuestAddress(0x1000);
203    /// # let mut gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
204    /// #    .expect("Could not create guest memory");
205    /// #
206    /// let buf = &mut [0u8; 16];
207    /// let res = gm
208    ///     .read(buf, GuestAddress(0x1200))
209    ///     .expect("Could not read from guest memory");
210    /// assert_eq!(16, res);
211    /// ```
212    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    /// # Examples
237    ///
238    /// * Read bytes from /dev/urandom
239    ///
240    /// ```
241    /// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
242    /// # use std::fs::File;
243    /// # use std::path::Path;
244    /// #
245    /// # let start_addr = GuestAddress(0x1000);
246    /// # let gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
247    /// #    .expect("Could not create guest memory");
248    /// # let addr = GuestAddress(0x1010);
249    /// # let mut file = if cfg!(unix) {
250    /// let mut file = File::open(Path::new("/dev/urandom")).expect("Could not open /dev/urandom");
251    /// #   file
252    /// # } else {
253    /// #   File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe"))
254    /// #       .expect("Could not open c:\\Windows\\system32\\ntoskrnl.exe")
255    /// # };
256    ///
257    /// gm.read_from(addr, &mut file, 128)
258    ///     .expect("Could not read from /dev/urandom into guest memory");
259    ///
260    /// let read_addr = addr.checked_add(8).expect("Could not compute read address");
261    /// let rand_val: u32 = gm
262    ///     .read_obj(read_addr)
263    ///     .expect("Could not read u32 val from /dev/urandom");
264    /// ```
265    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)] // function itself is deprecated
276        self.as_volatile_slice()
277            .unwrap()
278            .read_from::<F>(maddr, src, count)
279            .map_err(Into::into)
280    }
281
282    /// # Examples
283    ///
284    /// * Read bytes from /dev/urandom
285    ///
286    /// ```
287    /// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
288    /// # use std::fs::File;
289    /// # use std::path::Path;
290    /// #
291    /// # let start_addr = GuestAddress(0x1000);
292    /// # let gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
293    /// #    .expect("Could not create guest memory");
294    /// # let addr = GuestAddress(0x1010);
295    /// # let mut file = if cfg!(unix) {
296    /// let mut file = File::open(Path::new("/dev/urandom")).expect("Could not open /dev/urandom");
297    /// #   file
298    /// # } else {
299    /// #   File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe"))
300    /// #       .expect("Could not open c:\\Windows\\system32\\ntoskrnl.exe")
301    /// # };
302    ///
303    /// gm.read_exact_from(addr, &mut file, 128)
304    ///     .expect("Could not read from /dev/urandom into guest memory");
305    ///
306    /// let read_addr = addr.checked_add(8).expect("Could not compute read address");
307    /// let rand_val: u32 = gm
308    ///     .read_obj(read_addr)
309    ///     .expect("Could not read u32 val from /dev/urandom");
310    /// ```
311    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)] // function itself is deprecated
322        self.as_volatile_slice()
323            .unwrap()
324            .read_exact_from::<F>(maddr, src, count)
325            .map_err(Into::into)
326    }
327
328    /// Writes data from the region to a writable object.
329    ///
330    /// # Examples
331    ///
332    /// * Write 128 bytes to a /dev/null file
333    ///
334    /// ```
335    /// # #[cfg(not(unix))]
336    /// # extern crate vmm_sys_util;
337    /// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
338    /// #
339    /// # let start_addr = GuestAddress(0x1000);
340    /// # let gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
341    /// #    .expect("Could not create guest memory");
342    /// # let mut file = if cfg!(unix) {
343    /// # use std::fs::OpenOptions;
344    /// let mut file = OpenOptions::new()
345    ///     .write(true)
346    ///     .open("/dev/null")
347    ///     .expect("Could not open /dev/null");
348    /// #   file
349    /// # } else {
350    /// #   use vmm_sys_util::tempfile::TempFile;
351    /// #   TempFile::new().unwrap().into_file()
352    /// # };
353    ///
354    /// gm.write_to(start_addr, &mut file, 128)
355    ///     .expect("Could not write to file from guest memory");
356    /// ```
357    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)] // function itself is deprecated
368        self.as_volatile_slice()
369            .unwrap()
370            .write_to::<F>(maddr, dst, count)
371            .map_err(Into::into)
372    }
373
374    /// Writes data from the region to a writable object.
375    ///
376    /// # Examples
377    ///
378    /// * Write 128 bytes to a /dev/null file
379    ///
380    /// ```
381    /// # #[cfg(not(unix))]
382    /// # extern crate vmm_sys_util;
383    /// # use vm_memory::{Address, Bytes, GuestAddress, GuestMemoryMmap};
384    /// #
385    /// # let start_addr = GuestAddress(0x1000);
386    /// # let gm = GuestMemoryMmap::<()>::from_ranges(&vec![(start_addr, 0x400)])
387    /// #    .expect("Could not create guest memory");
388    /// # let mut file = if cfg!(unix) {
389    /// # use std::fs::OpenOptions;
390    /// let mut file = OpenOptions::new()
391    ///     .write(true)
392    ///     .open("/dev/null")
393    ///     .expect("Could not open /dev/null");
394    /// #   file
395    /// # } else {
396    /// #   use vmm_sys_util::tempfile::TempFile;
397    /// #   TempFile::new().unwrap().into_file()
398    /// # };
399    ///
400    /// gm.write_all_to(start_addr, &mut file, 128)
401    ///     .expect("Could not write to file from guest memory");
402    /// ```
403    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)] // function itself is deprecated
414        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        // Not sure why wrapping_offset is not unsafe.  Anyway this
459        // is safe because we've just range-checked addr using check_address.
460        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/// [`GuestMemory`](trait.GuestMemory.html) implementation that mmaps the guest's memory
489/// in the current process.
490///
491/// Represents the entire physical memory of the guest by tracking all its memory regions.
492/// Each region is an instance of `GuestRegionMmap`, being backed by a mapping in the
493/// virtual address space of the calling process.
494#[derive(Clone, Debug, Default)]
495pub struct GuestMemoryMmap<B = ()> {
496    regions: Vec<Arc<GuestRegionMmap<B>>>,
497}
498
499impl<B: NewBitmap> GuestMemoryMmap<B> {
500    /// Creates an empty `GuestMemoryMmap` instance.
501    pub fn new() -> Self {
502        Self::default()
503    }
504
505    /// Creates a container and allocates anonymous memory for guest memory regions.
506    ///
507    /// Valid memory regions are specified as a slice of (Address, Size) tuples sorted by Address.
508    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    /// Creates a container and allocates anonymous memory for guest memory regions.
513    ///
514    /// Valid memory regions are specified as a sequence of (Address, Size, [`Option<FileOffset>`])
515    /// tuples sorted by Address.
516    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    /// Creates a new `GuestMemoryMmap` from a vector of regions.
534    ///
535    /// # Arguments
536    ///
537    /// * `regions` - The vector of regions.
538    ///               The regions shouldn't overlap and they should be sorted
539    ///               by the starting address.
540    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    /// Creates a new `GuestMemoryMmap` from a vector of Arc regions.
545    ///
546    /// Similar to the constructor `from_regions()` as it returns a
547    /// `GuestMemoryMmap`. The need for this constructor is to provide a way for
548    /// consumer of this API to create a new `GuestMemoryMmap` based on existing
549    /// regions coming from an existing `GuestMemoryMmap` instance.
550    ///
551    /// # Arguments
552    ///
553    /// * `regions` - The vector of `Arc` regions.
554    ///               The regions shouldn't overlap and they should be sorted
555    ///               by the starting address.
556    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    /// Insert a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`.
578    ///
579    /// # Arguments
580    /// * `region`: the memory region to insert into the guest memory object.
581    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    /// Remove a region into the `GuestMemoryMmap` object and return a new `GuestMemoryMmap`
593    /// on success, together with the removed region.
594    ///
595    /// # Arguments
596    /// * `base`: base address of the region to be removed
597    /// * `size`: size of the region to be removed
598    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            // Within the closest region with starting address < addr
626            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(&regions)
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(&regions_summary).err().unwrap()
746            ),
747            format!("{:?}", Error::NoMemoryRegion)
748        );
749
750        assert_eq!(
751            format!(
752                "{:?}",
753                new_guest_memory_mmap_with_files(&regions_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(&regions_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(&regions_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(&regions_summary).err().unwrap()
789            ),
790            format!("{:?}", Error::MemoryRegionOverlap)
791        );
792
793        assert_eq!(
794            format!(
795                "{:?}",
796                new_guest_memory_mmap_with_files(&regions_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(&regions_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(&regions_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(&regions_summary).err().unwrap()
832            ),
833            format!("{:?}", Error::UnsortedMemoryRegions)
834        );
835
836        assert_eq!(
837            format!(
838                "{:?}",
839                new_guest_memory_mmap_with_files(&regions_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(&regions_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(&regions_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(&regions_summary), &regions_summary);
875
876        check_guest_memory_mmap(
877            new_guest_memory_mmap_with_files(&regions_summary),
878            &regions_summary,
879        );
880
881        check_guest_memory_mmap(
882            new_guest_memory_mmap_from_regions(&regions_summary),
883            &regions_summary,
884        );
885
886        check_guest_memory_mmap(
887            new_guest_memory_mmap_from_arc_regions(&regions_summary),
888            &regions_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))] // Miri cannot mmap files
902    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(&regions).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(&regions).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    // Windows needs a dedicated test where it will retrieve the allocation
1292    // granularity to determine a proper offset (other than 0) that can be
1293    // used for the backing file. Refer to Microsoft docs here:
1294    // https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-mapviewoffile
1295    #[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        // Needs to be aligned on 4k, otherwise mmap will fail.
1301        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(&regions).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(&regions).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        // Normal case.
1382        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        // Empty slice.
1388        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        // Error case when slice_size is beyond the boundary.
1394        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        // Test slice length.
1405        let slice = region.as_volatile_slice().unwrap();
1406        assert_eq!(slice.len(), region_size);
1407
1408        // Test slice data.
1409        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        // Normal cases.
1423        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        // Empty slice.
1436        assert!(guest_mem
1437            .get_slice(GuestAddress(0x900), 0)
1438            .unwrap()
1439            .is_empty());
1440
1441        // Error cases, wrong size or base address.
1442        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}