Skip to main content

vm_memory/
volatile_memory.rs

1// Portions Copyright 2019 Red Hat, Inc.
2//
3// Copyright 2017 The Chromium OS Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the THIRT-PARTY file.
6//
7// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
8
9//! Types for volatile access to memory.
10//!
11//! Two of the core rules for safe rust is no data races and no aliased mutable references.
12//! `VolatileRef` and `VolatileSlice`, along with types that produce those which implement
13//! `VolatileMemory`, allow us to sidestep that rule by wrapping pointers that absolutely have to be
14//! accessed volatile. Some systems really do need to operate on shared memory and can't have the
15//! compiler reordering or eliding access because it has no visibility into what other systems are
16//! doing with that hunk of memory.
17//!
18//! For the purposes of maintaining safety, volatile memory has some rules of its own:
19//!
20//! 1. No references or slices to volatile memory (`&` or `&mut`).
21//!
22//! 2. Access should always been done with a volatile read or write.
23//!
24//! The First rule is because having references of any kind to memory considered volatile would
25//! violate pointer aliasing. The second is because unvolatile accesses are inherently undefined if
26//! done concurrently without synchronization. With volatile access we know that the compiler has
27//! not reordered or elided the access.
28
29use std::cmp::min;
30use std::io;
31use std::marker::PhantomData;
32use std::mem::{align_of, size_of};
33use std::ptr::copy;
34use std::ptr::{read_volatile, write_volatile};
35use std::result;
36use std::sync::atomic::Ordering;
37
38use crate::atomic_integer::AtomicInteger;
39use crate::bitmap::{Bitmap, BitmapSlice, BS};
40use crate::{AtomicAccess, ByteValued, Bytes};
41
42#[cfg(all(feature = "backend-mmap", feature = "xen", target_family = "unix"))]
43use crate::mmap::xen::{MmapXen as MmapInfo, MmapXenSlice};
44
45#[cfg(not(feature = "xen"))]
46type MmapInfo = std::marker::PhantomData<()>;
47
48use crate::io::{retry_eintr, ReadVolatile, WriteVolatile};
49use copy_slice_impl::{copy_from_volatile_slice, copy_to_volatile_slice};
50
51/// `VolatileMemory` related errors.
52#[allow(missing_docs)]
53#[derive(Debug, thiserror::Error)]
54pub enum Error {
55    /// `addr` is out of bounds of the volatile memory slice.
56    #[error("address 0x{addr:x} is out of bounds")]
57    OutOfBounds { addr: usize },
58    /// Taking a slice at `base` with `offset` would overflow `usize`.
59    #[error("address 0x{base:x} offset by 0x{offset:x} would overflow")]
60    Overflow { base: usize, offset: usize },
61    /// Taking a slice whose size overflows `usize`.
62    #[error("{nelements:?} elements of size {size:?} would overflow a usize")]
63    TooBig { nelements: usize, size: usize },
64    /// Trying to obtain a misaligned reference.
65    #[error("address 0x{addr:x} is not aligned to {alignment:?}")]
66    Misaligned { addr: usize, alignment: usize },
67    /// Writing to memory failed
68    #[error("{0}")]
69    IOError(io::Error),
70    /// Incomplete read or write
71    #[error("only used {completed} bytes in {expected} long buffer")]
72    PartialBuffer { expected: usize, completed: usize },
73}
74
75/// Result of volatile memory operations.
76pub type Result<T> = result::Result<T, Error>;
77
78/// Convenience function for computing `base + offset`.
79///
80/// # Errors
81///
82/// Returns [`Err(Error::Overflow)`](enum.Error.html#variant.Overflow) in case `base + offset`
83/// exceeds `usize::MAX`.
84///
85/// # Examples
86///
87/// ```
88/// # use matches::assert_matches;
89/// # use vm_memory::volatile_memory::{compute_offset, Error};
90/// #
91/// assert_eq!(108, compute_offset(100, 8).unwrap());
92/// assert_matches!(
93///     compute_offset(usize::MAX, 6).unwrap_err(),
94///     Error::Overflow {
95///         base: usize::MAX,
96///         offset: 6
97///     }
98/// );
99/// ```
100pub fn compute_offset(base: usize, offset: usize) -> Result<usize> {
101    match base.checked_add(offset) {
102        None => Err(Error::Overflow { base, offset }),
103        Some(m) => Ok(m),
104    }
105}
106
107/// Types that support raw volatile access to their data.
108pub trait VolatileMemory {
109    /// Type used for dirty memory tracking.
110    type B: Bitmap;
111
112    /// Gets the size of this slice.
113    fn len(&self) -> usize;
114
115    /// Check whether the region is empty.
116    fn is_empty(&self) -> bool {
117        self.len() == 0
118    }
119
120    /// Returns a [`VolatileSlice`](struct.VolatileSlice.html) of `count` bytes starting at
121    /// `offset`.
122    ///
123    /// Note that the property `get_slice(offset, count).len() == count` MUST NOT be
124    /// relied on for the correctness of unsafe code. This is a safe function inside of a
125    /// safe trait, and implementors are under no obligation to follow its documentation.
126    fn get_slice(&self, offset: usize, count: usize) -> Result<VolatileSlice<'_, BS<'_, Self::B>>>;
127
128    /// Gets a slice of memory for the entire region that supports volatile access.
129    fn as_volatile_slice(&self) -> VolatileSlice<'_, BS<'_, Self::B>> {
130        self.get_slice(0, self.len()).unwrap()
131    }
132
133    /// Gets a `VolatileRef` at `offset`.
134    fn get_ref<T: ByteValued>(&self, offset: usize) -> Result<VolatileRef<'_, T, BS<'_, Self::B>>> {
135        let slice = self.get_slice(offset, size_of::<T>())?;
136
137        assert_eq!(
138            slice.len(),
139            size_of::<T>(),
140            "VolatileMemory::get_slice(offset, count) returned slice of length != count."
141        );
142
143        // SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
144        // slice.addr is valid memory of size slice.len(). The assert above ensures that
145        // the length of the slice is exactly enough to hold one `T`. Lastly, the lifetime of the
146        // returned VolatileRef match that of the VolatileSlice returned by get_slice and thus the
147        // lifetime one `self`.
148        unsafe {
149            Ok(VolatileRef::with_bitmap(
150                slice.addr,
151                slice.bitmap,
152                slice.mmap,
153            ))
154        }
155    }
156
157    /// Returns a [`VolatileArrayRef`](struct.VolatileArrayRef.html) of `n` elements starting at
158    /// `offset`.
159    fn get_array_ref<T: ByteValued>(
160        &self,
161        offset: usize,
162        n: usize,
163    ) -> Result<VolatileArrayRef<'_, T, BS<'_, Self::B>>> {
164        // Use isize to avoid problems with ptr::offset and ptr::add down the line.
165        let nbytes = isize::try_from(n)
166            .ok()
167            .and_then(|n| n.checked_mul(size_of::<T>() as isize))
168            .ok_or(Error::TooBig {
169                nelements: n,
170                size: size_of::<T>(),
171            })?;
172        let slice = self.get_slice(offset, nbytes as usize)?;
173
174        assert_eq!(
175            slice.len(),
176            nbytes as usize,
177            "VolatileMemory::get_slice(offset, count) returned slice of length != count."
178        );
179
180        // SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
181        // slice.addr is valid memory of size slice.len(). The assert above ensures that
182        // the length of the slice is exactly enough to hold `n` instances of `T`. Lastly, the lifetime of the
183        // returned VolatileArrayRef match that of the VolatileSlice returned by get_slice and thus the
184        // lifetime one `self`.
185        unsafe {
186            Ok(VolatileArrayRef::with_bitmap(
187                slice.addr,
188                n,
189                slice.bitmap,
190                slice.mmap,
191            ))
192        }
193    }
194
195    /// Returns a reference to an instance of `T` at `offset`.
196    ///
197    /// # Safety
198    /// To use this safely, the caller must guarantee that there are no other
199    /// users of the given chunk of memory for the lifetime of the result.
200    ///
201    /// # Errors
202    ///
203    /// If the resulting pointer is not aligned, this method will return an
204    /// [`Error`](enum.Error.html).
205    unsafe fn aligned_as_ref<T: ByteValued>(&self, offset: usize) -> Result<&T> {
206        let slice = self.get_slice(offset, size_of::<T>())?;
207        slice.check_alignment(align_of::<T>())?;
208
209        assert_eq!(
210            slice.len(),
211            size_of::<T>(),
212            "VolatileMemory::get_slice(offset, count) returned slice of length != count."
213        );
214
215        // SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
216        // slice.addr is valid memory of size slice.len(). The assert above ensures that
217        // the length of the slice is exactly enough to hold one `T`.
218        // Dereferencing the pointer is safe because we check the alignment above, and the invariants
219        // of this function ensure that no aliasing pointers exist. Lastly, the lifetime of the
220        // returned VolatileArrayRef match that of the VolatileSlice returned by get_slice and thus the
221        // lifetime one `self`.
222        unsafe { Ok(&*(slice.addr as *const T)) }
223    }
224
225    /// Returns a mutable reference to an instance of `T` at `offset`. Mutable accesses performed
226    /// using the resulting reference are not automatically accounted for by the dirty bitmap
227    /// tracking functionality.
228    ///
229    /// # Safety
230    ///
231    /// To use this safely, the caller must guarantee that there are no other
232    /// users of the given chunk of memory for the lifetime of the result.
233    ///
234    /// # Errors
235    ///
236    /// If the resulting pointer is not aligned, this method will return an
237    /// [`Error`](enum.Error.html).
238    // the function is unsafe, and the conversion is safe if following the safety
239    // instrutions above
240    #[allow(clippy::mut_from_ref)]
241    unsafe fn aligned_as_mut<T: ByteValued>(&self, offset: usize) -> Result<&mut T> {
242        let slice = self.get_slice(offset, size_of::<T>())?;
243        slice.check_alignment(align_of::<T>())?;
244
245        assert_eq!(
246            slice.len(),
247            size_of::<T>(),
248            "VolatileMemory::get_slice(offset, count) returned slice of length != count."
249        );
250
251        // SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
252        // slice.addr is valid memory of size slice.len(). The assert above ensures that
253        // the length of the slice is exactly enough to hold one `T`.
254        // Dereferencing the pointer is safe because we check the alignment above, and the invariants
255        // of this function ensure that no aliasing pointers exist. Lastly, the lifetime of the
256        // returned VolatileArrayRef match that of the VolatileSlice returned by get_slice and thus the
257        // lifetime one `self`.
258
259        unsafe { Ok(&mut *(slice.addr as *mut T)) }
260    }
261
262    /// Returns a reference to an instance of `T` at `offset`. Mutable accesses performed
263    /// using the resulting reference are not automatically accounted for by the dirty bitmap
264    /// tracking functionality.
265    ///
266    /// # Errors
267    ///
268    /// If the resulting pointer is not aligned, this method will return an
269    /// [`Error`](enum.Error.html).
270    fn get_atomic_ref<T: AtomicInteger>(&self, offset: usize) -> Result<&T> {
271        let slice = self.get_slice(offset, size_of::<T>())?;
272        slice.check_alignment(align_of::<T>())?;
273
274        assert_eq!(
275            slice.len(),
276            size_of::<T>(),
277            "VolatileMemory::get_slice(offset, count) returned slice of length != count."
278        );
279
280        // SAFETY: This is safe because the invariants of the constructors of VolatileSlice ensure that
281        // slice.addr is valid memory of size slice.len(). The assert above ensures that
282        // the length of the slice is exactly enough to hold one `T`.
283        // Dereferencing the pointer is safe because we check the alignment above. Lastly, the lifetime of the
284        // returned VolatileArrayRef match that of the VolatileSlice returned by get_slice and thus the
285        // lifetime one `self`.
286        unsafe { Ok(&*(slice.addr as *const T)) }
287    }
288
289    /// Returns the sum of `base` and `offset` if it is valid to access a range of `offset`
290    /// bytes starting at `base`.
291    ///
292    /// Specifically, allows accesses of length 0 at the end of a slice:
293    ///
294    /// ```rust
295    /// # use vm_memory::{VolatileMemory, VolatileSlice};
296    /// let mut arr = [1, 2, 3];
297    /// let slice = VolatileSlice::from(arr.as_mut_slice());
298    ///
299    /// assert_eq!(slice.compute_end_offset(3, 0).unwrap(), 3);
300    /// ```
301    fn compute_end_offset(&self, base: usize, offset: usize) -> Result<usize> {
302        let mem_end = compute_offset(base, offset)?;
303        if mem_end > self.len() {
304            return Err(Error::OutOfBounds { addr: mem_end });
305        }
306        Ok(mem_end)
307    }
308}
309
310impl<'a> From<&'a mut [u8]> for VolatileSlice<'a, ()> {
311    fn from(value: &'a mut [u8]) -> Self {
312        // SAFETY: Since we construct the VolatileSlice from a rust slice, we know that
313        // the memory at addr `value as *mut u8` is valid for reads and writes (because mutable
314        // reference) of len `value.len()`. Since the `VolatileSlice` inherits the lifetime `'a`,
315        // it is not possible to access/mutate `value` while the VolatileSlice is alive.
316        //
317        // Note that it is possible for multiple aliasing sub slices of this `VolatileSlice`s to
318        // be created through `VolatileSlice::subslice`. This is OK, as pointers are allowed to
319        // alias, and it is impossible to get rust-style references from a `VolatileSlice`.
320        unsafe { VolatileSlice::new(value.as_mut_ptr(), value.len()) }
321    }
322}
323
324#[repr(C, packed)]
325struct Packed<T>(T);
326
327/// A guard to perform mapping and protect unmapping of the memory.
328#[derive(Debug)]
329pub struct PtrGuard {
330    addr: *mut u8,
331    len: usize,
332
333    // This isn't used anymore, but it protects the slice from getting unmapped while in use.
334    // Once this goes out of scope, the memory is unmapped automatically.
335    #[cfg(all(feature = "xen", target_family = "unix"))]
336    _slice: MmapXenSlice,
337}
338
339#[allow(clippy::len_without_is_empty)]
340impl PtrGuard {
341    #[allow(unused_variables)]
342    fn new(mmap: Option<&MmapInfo>, addr: *mut u8, write: bool, len: usize) -> Self {
343        #[cfg(all(feature = "xen", target_family = "unix"))]
344        let (addr, _slice) = {
345            let prot = if write {
346                libc::PROT_WRITE
347            } else {
348                libc::PROT_READ
349            };
350            let slice = MmapInfo::mmap(mmap, addr, prot, len);
351            (slice.addr(), slice)
352        };
353
354        Self {
355            addr,
356            len,
357
358            #[cfg(all(feature = "xen", target_family = "unix"))]
359            _slice,
360        }
361    }
362
363    fn read(mmap: Option<&MmapInfo>, addr: *mut u8, len: usize) -> Self {
364        Self::new(mmap, addr, false, len)
365    }
366
367    /// Returns a non-mutable pointer to the beginning of the slice.
368    pub fn as_ptr(&self) -> *const u8 {
369        self.addr
370    }
371
372    /// Gets the length of the mapped region.
373    pub fn len(&self) -> usize {
374        self.len
375    }
376}
377
378/// A mutable guard to perform mapping and protect unmapping of the memory.
379#[derive(Debug)]
380pub struct PtrGuardMut(PtrGuard);
381
382#[allow(clippy::len_without_is_empty)]
383impl PtrGuardMut {
384    fn write(mmap: Option<&MmapInfo>, addr: *mut u8, len: usize) -> Self {
385        Self(PtrGuard::new(mmap, addr, true, len))
386    }
387
388    /// Returns a mutable pointer to the beginning of the slice. Mutable accesses performed
389    /// using the resulting pointer are not automatically accounted for by the dirty bitmap
390    /// tracking functionality.
391    pub fn as_ptr(&self) -> *mut u8 {
392        self.0.addr
393    }
394
395    /// Gets the length of the mapped region.
396    pub fn len(&self) -> usize {
397        self.0.len
398    }
399}
400
401/// A slice of raw memory that supports volatile access.
402#[derive(Clone, Copy, Debug)]
403pub struct VolatileSlice<'a, B = ()> {
404    addr: *mut u8,
405    size: usize,
406    bitmap: B,
407    mmap: Option<&'a MmapInfo>,
408}
409
410impl<'a> VolatileSlice<'a, ()> {
411    /// Creates a slice of raw memory that must support volatile access.
412    ///
413    /// # Safety
414    ///
415    /// To use this safely, the caller must guarantee that the memory at `addr` is `size` bytes long
416    /// and is available for the duration of the lifetime of the new `VolatileSlice`. The caller
417    /// must also guarantee that all other users of the given chunk of memory are using volatile
418    /// accesses.
419    pub unsafe fn new(addr: *mut u8, size: usize) -> VolatileSlice<'a> {
420        Self::with_bitmap(addr, size, (), None)
421    }
422}
423
424impl<'a, B: BitmapSlice> VolatileSlice<'a, B> {
425    /// Creates a slice of raw memory that must support volatile access, and uses the provided
426    /// `bitmap` object for dirty page tracking.
427    ///
428    /// # Safety
429    ///
430    /// To use this safely, the caller must guarantee that the memory at `addr` is `size` bytes long
431    /// and is available for the duration of the lifetime of the new `VolatileSlice`. The caller
432    /// must also guarantee that all other users of the given chunk of memory are using volatile
433    /// accesses.
434    pub unsafe fn with_bitmap(
435        addr: *mut u8,
436        size: usize,
437        bitmap: B,
438        mmap: Option<&'a MmapInfo>,
439    ) -> VolatileSlice<'a, B> {
440        VolatileSlice {
441            addr,
442            size,
443            bitmap,
444            mmap,
445        }
446    }
447
448    /// Replaces the bitmap in `self` by `new_bitmap`.
449    #[cfg(feature = "iommu")]
450    pub(crate) fn replace_bitmap<NB: BitmapSlice>(self, new_bitmap: NB) -> VolatileSlice<'a, NB> {
451        VolatileSlice {
452            addr: self.addr,
453            size: self.size,
454            bitmap: new_bitmap,
455            mmap: self.mmap,
456        }
457    }
458
459    /// Returns a guard for the pointer to the underlying memory.
460    pub fn ptr_guard(&self) -> PtrGuard {
461        PtrGuard::read(self.mmap, self.addr, self.len())
462    }
463
464    /// Returns a mutable guard for the pointer to the underlying memory.
465    pub fn ptr_guard_mut(&self) -> PtrGuardMut {
466        PtrGuardMut::write(self.mmap, self.addr, self.len())
467    }
468
469    /// Gets the size of this slice.
470    pub fn len(&self) -> usize {
471        self.size
472    }
473
474    /// Checks if the slice is empty.
475    pub fn is_empty(&self) -> bool {
476        self.size == 0
477    }
478
479    /// Borrows the inner `BitmapSlice`.
480    pub fn bitmap(&self) -> &B {
481        &self.bitmap
482    }
483
484    /// Divides one slice into two at an index.
485    ///
486    /// # Example
487    ///
488    /// ```
489    /// # use vm_memory::{VolatileMemory, VolatileSlice};
490    /// #
491    /// # // Create a buffer
492    /// # let mut mem = [0u8; 32];
493    /// #
494    /// # // Get a `VolatileSlice` from the buffer
495    /// let vslice = VolatileSlice::from(&mut mem[..]);
496    ///
497    /// let (start, end) = vslice.split_at(8).expect("Could not split VolatileSlice");
498    /// assert_eq!(8, start.len());
499    /// assert_eq!(24, end.len());
500    /// ```
501    pub fn split_at(&self, mid: usize) -> Result<(Self, Self)> {
502        let end = self.offset(mid)?;
503        let start =
504            // SAFETY: safe because self.offset() already checked the bounds
505            unsafe { VolatileSlice::with_bitmap(self.addr, mid, self.bitmap.clone(), self.mmap) };
506
507        Ok((start, end))
508    }
509
510    /// Returns a subslice of this [`VolatileSlice`](struct.VolatileSlice.html) starting at
511    /// `offset` with `count` length.
512    ///
513    /// The returned subslice is a copy of this slice with the address increased by `offset` bytes
514    /// and the size set to `count` bytes.
515    pub fn subslice(&self, offset: usize, count: usize) -> Result<Self> {
516        let _ = self.compute_end_offset(offset, count)?;
517
518        // SAFETY: This is safe because the pointer is range-checked by compute_end_offset, and
519        // the lifetime is the same as the original slice.
520        unsafe {
521            Ok(VolatileSlice::with_bitmap(
522                self.addr.add(offset),
523                count,
524                self.bitmap.slice_at(offset),
525                self.mmap,
526            ))
527        }
528    }
529
530    /// Returns a subslice of this [`VolatileSlice`](struct.VolatileSlice.html) starting at
531    /// `offset`.
532    ///
533    /// The returned subslice is a copy of this slice with the address increased by `count` bytes
534    /// and the size reduced by `count` bytes.
535    pub fn offset(&self, count: usize) -> Result<VolatileSlice<'a, B>> {
536        let new_addr = (self.addr as usize)
537            .checked_add(count)
538            .ok_or(Error::Overflow {
539                base: self.addr as usize,
540                offset: count,
541            })?;
542        let new_size = self
543            .size
544            .checked_sub(count)
545            .ok_or(Error::OutOfBounds { addr: new_addr })?;
546        // SAFETY: Safe because the memory has the same lifetime and points to a subset of the
547        // memory of the original slice.
548        unsafe {
549            Ok(VolatileSlice::with_bitmap(
550                self.addr.add(count),
551                new_size,
552                self.bitmap.slice_at(count),
553                self.mmap,
554            ))
555        }
556    }
557
558    /// Copies as many elements of type `T` as possible from this slice to `buf`.
559    ///
560    /// Copies `self.len()` or `buf.len()` times the size of `T` bytes, whichever is smaller,
561    /// to `buf`. The copy happens from smallest to largest address in `T` sized chunks
562    /// using volatile reads.
563    ///
564    /// # Examples
565    ///
566    /// ```
567    /// # use vm_memory::{VolatileMemory, VolatileSlice};
568    /// #
569    /// let mut mem = [0u8; 32];
570    /// let vslice = VolatileSlice::from(&mut mem[..]);
571    /// let mut buf = [5u8; 16];
572    /// let res = vslice.copy_to(&mut buf[..]);
573    ///
574    /// assert_eq!(16, res);
575    /// for &v in &buf[..] {
576    ///     assert_eq!(v, 0);
577    /// }
578    /// ```
579    pub fn copy_to<T>(&self, buf: &mut [T]) -> usize
580    where
581        T: ByteValued,
582    {
583        // A fast path for u8/i8
584        if size_of::<T>() == 1 {
585            let total = buf.len().min(self.len());
586
587            // SAFETY:
588            // - dst is valid for writes of at least `total`, since total <= buf.len()
589            // - src is valid for reads of at least `total` as total <= self.len()
590            // - The regions are non-overlapping as `src` points to guest memory and `buf` is
591            //   a slice and thus has to live outside of guest memory (there can be more slices to
592            //   guest memory without violating rust's aliasing rules)
593            // - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
594            unsafe { copy_from_volatile_slice(buf.as_mut_ptr() as *mut u8, self, total) }
595        } else {
596            let count = self.size / size_of::<T>();
597            let source = self.get_array_ref::<T>(0, count).unwrap();
598            source.copy_to(buf)
599        }
600    }
601
602    /// Copies as many bytes as possible from this slice to the provided `slice`.
603    ///
604    /// The copies happen in an undefined order.
605    ///
606    /// # Examples
607    ///
608    /// ```
609    /// # use vm_memory::{VolatileMemory, VolatileSlice};
610    /// #
611    /// # // Create a buffer
612    /// # let mut mem = [0u8; 32];
613    /// #
614    /// # // Get a `VolatileSlice` from the buffer
615    /// # let vslice = VolatileSlice::from(&mut mem[..]);
616    /// #
617    /// vslice.copy_to_volatile_slice(
618    ///     vslice
619    ///         .get_slice(16, 16)
620    ///         .expect("Could not get VolatileSlice"),
621    /// );
622    /// ```
623    pub fn copy_to_volatile_slice<S: BitmapSlice>(&self, slice: VolatileSlice<S>) {
624        // SAFETY: Safe because the pointers are range-checked when the slices
625        // are created, and they never escape the VolatileSlices.
626        // FIXME: ... however, is it really okay to mix non-volatile
627        // operations such as copy with read_volatile and write_volatile?
628        unsafe {
629            let count = min(self.size, slice.size);
630            copy(self.addr, slice.addr, count);
631            slice.bitmap.mark_dirty(0, count);
632        }
633    }
634
635    /// Copies as many elements of type `T` as possible from `buf` to this slice.
636    ///
637    /// The copy happens from smallest to largest address in `T` sized chunks using volatile writes.
638    ///
639    /// # Examples
640    ///
641    /// ```
642    /// # use vm_memory::{VolatileMemory, VolatileSlice};
643    /// #
644    /// let mut mem = [0u8; 32];
645    /// let vslice = VolatileSlice::from(&mut mem[..]);
646    ///
647    /// let buf = [5u8; 64];
648    /// vslice.copy_from(&buf[..]);
649    ///
650    /// for i in 0..4 {
651    ///     let val = vslice
652    ///         .get_ref::<u32>(i * 4)
653    ///         .expect("Could not get value")
654    ///         .load();
655    ///     assert_eq!(val, 0x05050505);
656    /// }
657    /// ```
658    pub fn copy_from<T>(&self, buf: &[T])
659    where
660        T: ByteValued,
661    {
662        // A fast path for u8/i8
663        if size_of::<T>() == 1 {
664            let total = buf.len().min(self.len());
665            // SAFETY:
666            // - dst is valid for writes of at least `total`, since total <= self.len()
667            // - src is valid for reads of at least `total` as total <= buf.len()
668            // - The regions are non-overlapping as `dst` points to guest memory and `buf` is
669            //   a slice and thus has to live outside of guest memory (there can be more slices to
670            //   guest memory without violating rust's aliasing rules)
671            // - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
672            unsafe { copy_to_volatile_slice(self, buf.as_ptr() as *const u8, total) };
673        } else {
674            let count = self.size / size_of::<T>();
675            // It's ok to use unwrap here because `count` was computed based on the current
676            // length of `self`.
677            let dest = self.get_array_ref::<T>(0, count).unwrap();
678
679            // No need to explicitly call `mark_dirty` after this call because
680            // `VolatileArrayRef::copy_from` already takes care of that.
681            dest.copy_from(buf);
682        };
683    }
684
685    /// Checks if the current slice is aligned at `alignment` bytes.
686    fn check_alignment(&self, alignment: usize) -> Result<()> {
687        // Check that the desired alignment is a power of two.
688        debug_assert!((alignment & (alignment - 1)) == 0);
689        if ((self.addr as usize) & (alignment - 1)) != 0 {
690            return Err(Error::Misaligned {
691                addr: self.addr as usize,
692                alignment,
693            });
694        }
695        Ok(())
696    }
697}
698
699impl<B: BitmapSlice> Bytes<usize> for VolatileSlice<'_, B> {
700    type E = Error;
701
702    /// # Examples
703    /// * Write a slice of size 5 at offset 1020 of a 1024-byte `VolatileSlice`.
704    ///
705    /// ```
706    /// # use vm_memory::{Bytes, VolatileMemory, VolatileSlice};
707    /// #
708    /// let mut mem = [0u8; 1024];
709    /// let vslice = VolatileSlice::from(&mut mem[..]);
710    /// let res = vslice.write(&[1, 2, 3, 4, 5], 1020);
711    ///
712    /// assert!(res.is_ok());
713    /// assert_eq!(res.unwrap(), 4);
714    /// ```
715    fn write(&self, mut buf: &[u8], addr: usize) -> Result<usize> {
716        if buf.is_empty() {
717            return Ok(0);
718        }
719
720        if addr >= self.size {
721            return Err(Error::OutOfBounds { addr });
722        }
723
724        // NOTE: the duality of read <-> write here is correct. This is because we translate a call
725        // "volatile_slice.write(buf)" (e.g. "write to volatile_slice from buf") into
726        // "buf.read_volatile(volatile_slice)" (e.g. read from buf into volatile_slice)
727        buf.read_volatile(&mut self.offset(addr)?)
728    }
729
730    /// # Examples
731    /// * Read a slice of size 16 at offset 1010 of a 1024-byte `VolatileSlice`.
732    ///
733    /// ```
734    /// # use vm_memory::{Bytes, VolatileMemory, VolatileSlice};
735    /// #
736    /// let mut mem = [0u8; 1024];
737    /// let vslice = VolatileSlice::from(&mut mem[..]);
738    /// let buf = &mut [0u8; 16];
739    /// let res = vslice.read(buf, 1010);
740    ///
741    /// assert!(res.is_ok());
742    /// assert_eq!(res.unwrap(), 14);
743    /// ```
744    fn read(&self, mut buf: &mut [u8], addr: usize) -> Result<usize> {
745        if buf.is_empty() {
746            return Ok(0);
747        }
748
749        if addr >= self.size {
750            return Err(Error::OutOfBounds { addr });
751        }
752
753        // NOTE: The duality of read <-> write here is correct. This is because we translate a call
754        // volatile_slice.read(buf) (e.g. read from volatile_slice into buf) into
755        // "buf.write_volatile(volatile_slice)" (e.g. write into buf from volatile_slice)
756        // Both express data transfer from volatile_slice to buf.
757        buf.write_volatile(&self.offset(addr)?)
758    }
759
760    /// # Examples
761    /// * Write a slice at offset 256.
762    ///
763    /// ```
764    /// # use vm_memory::{Bytes, VolatileMemory, VolatileSlice};
765    /// #
766    /// # // Create a buffer
767    /// # let mut mem = [0u8; 1024];
768    /// #
769    /// # // Get a `VolatileSlice` from the buffer
770    /// # let vslice = VolatileSlice::from(&mut mem[..]);
771    /// #
772    /// let res = vslice.write_slice(&[1, 2, 3, 4, 5], 256);
773    ///
774    /// assert!(res.is_ok());
775    /// assert_eq!(res.unwrap(), ());
776    /// ```
777    fn write_slice(&self, buf: &[u8], addr: usize) -> Result<()> {
778        // `mark_dirty` called within `self.write`.
779        let len = self.write(buf, addr)?;
780        if len != buf.len() {
781            return Err(Error::PartialBuffer {
782                expected: buf.len(),
783                completed: len,
784            });
785        }
786        Ok(())
787    }
788
789    /// # Examples
790    /// * Read a slice of size 16 at offset 256.
791    ///
792    /// ```
793    /// # use vm_memory::{Bytes, VolatileMemory, VolatileSlice};
794    /// #
795    /// # // Create a buffer
796    /// # let mut mem = [0u8; 1024];
797    /// #
798    /// # // Get a `VolatileSlice` from the buffer
799    /// # let vslice = VolatileSlice::from(&mut mem[..]);
800    /// #
801    /// let buf = &mut [0u8; 16];
802    /// let res = vslice.read_slice(buf, 256);
803    ///
804    /// assert!(res.is_ok());
805    /// ```
806    fn read_slice(&self, buf: &mut [u8], addr: usize) -> Result<()> {
807        let len = self.read(buf, addr)?;
808        if len != buf.len() {
809            return Err(Error::PartialBuffer {
810                expected: buf.len(),
811                completed: len,
812            });
813        }
814        Ok(())
815    }
816
817    fn read_volatile_from<F>(&self, addr: usize, src: &mut F, count: usize) -> Result<usize>
818    where
819        F: ReadVolatile,
820    {
821        let slice = self.offset(addr)?;
822        /* Unwrap safe here because (0, min(len, count)) is definitely a valid subslice */
823        let mut slice = slice.subslice(0, slice.len().min(count)).unwrap();
824        retry_eintr!(src.read_volatile(&mut slice))
825    }
826
827    fn read_exact_volatile_from<F>(&self, addr: usize, src: &mut F, count: usize) -> Result<()>
828    where
829        F: ReadVolatile,
830    {
831        src.read_exact_volatile(&mut self.get_slice(addr, count)?)
832    }
833
834    fn write_volatile_to<F>(&self, addr: usize, dst: &mut F, count: usize) -> Result<usize>
835    where
836        F: WriteVolatile,
837    {
838        let slice = self.offset(addr)?;
839        /* Unwrap safe here because (0, min(len, count)) is definitely a valid subslice */
840        let slice = slice.subslice(0, slice.len().min(count)).unwrap();
841        retry_eintr!(dst.write_volatile(&slice))
842    }
843
844    fn write_all_volatile_to<F>(&self, addr: usize, dst: &mut F, count: usize) -> Result<()>
845    where
846        F: WriteVolatile,
847    {
848        dst.write_all_volatile(&self.get_slice(addr, count)?)
849    }
850
851    fn store<T: AtomicAccess>(&self, val: T, addr: usize, order: Ordering) -> Result<()> {
852        self.get_atomic_ref::<T::A>(addr).map(|r| {
853            r.store(val.into(), order);
854            self.bitmap.mark_dirty(addr, size_of::<T>())
855        })
856    }
857
858    fn load<T: AtomicAccess>(&self, addr: usize, order: Ordering) -> Result<T> {
859        self.get_atomic_ref::<T::A>(addr)
860            .map(|r| r.load(order).into())
861    }
862}
863
864impl<B: BitmapSlice> VolatileMemory for VolatileSlice<'_, B> {
865    type B = B;
866
867    fn len(&self) -> usize {
868        self.size
869    }
870
871    fn get_slice(&self, offset: usize, count: usize) -> Result<VolatileSlice<'_, B>> {
872        self.subslice(offset, count)
873    }
874}
875
876/// A memory location that supports volatile access to an instance of `T`.
877///
878/// # Examples
879///
880/// ```
881/// # use vm_memory::VolatileRef;
882/// #
883/// let mut v = 5u32;
884/// let v_ref = unsafe { VolatileRef::new(&mut v as *mut u32 as *mut u8) };
885///
886/// assert_eq!(v, 5);
887/// assert_eq!(v_ref.load(), 5);
888/// v_ref.store(500);
889/// assert_eq!(v, 500);
890/// ```
891#[derive(Clone, Copy, Debug)]
892pub struct VolatileRef<'a, T, B = ()> {
893    addr: *mut Packed<T>,
894    bitmap: B,
895    mmap: Option<&'a MmapInfo>,
896}
897
898impl<T> VolatileRef<'_, T, ()>
899where
900    T: ByteValued,
901{
902    /// Creates a [`VolatileRef`](struct.VolatileRef.html) to an instance of `T`.
903    ///
904    /// # Safety
905    ///
906    /// To use this safely, the caller must guarantee that the memory at `addr` is big enough for a
907    /// `T` and is available for the duration of the lifetime of the new `VolatileRef`. The caller
908    /// must also guarantee that all other users of the given chunk of memory are using volatile
909    /// accesses.
910    pub unsafe fn new(addr: *mut u8) -> Self {
911        Self::with_bitmap(addr, (), None)
912    }
913}
914
915#[allow(clippy::len_without_is_empty)]
916impl<'a, T, B> VolatileRef<'a, T, B>
917where
918    T: ByteValued,
919    B: BitmapSlice,
920{
921    /// Creates a [`VolatileRef`](struct.VolatileRef.html) to an instance of `T`, using the
922    /// provided `bitmap` object for dirty page tracking.
923    ///
924    /// # Safety
925    ///
926    /// To use this safely, the caller must guarantee that the memory at `addr` is big enough for a
927    /// `T` and is available for the duration of the lifetime of the new `VolatileRef`. The caller
928    /// must also guarantee that all other users of the given chunk of memory are using volatile
929    /// accesses.
930    pub unsafe fn with_bitmap(addr: *mut u8, bitmap: B, mmap: Option<&'a MmapInfo>) -> Self {
931        VolatileRef {
932            addr: addr as *mut Packed<T>,
933            bitmap,
934            mmap,
935        }
936    }
937
938    /// Returns a guard for the pointer to the underlying memory.
939    pub fn ptr_guard(&self) -> PtrGuard {
940        PtrGuard::read(self.mmap, self.addr as *mut u8, self.len())
941    }
942
943    /// Returns a mutable guard for the pointer to the underlying memory.
944    pub fn ptr_guard_mut(&self) -> PtrGuardMut {
945        PtrGuardMut::write(self.mmap, self.addr as *mut u8, self.len())
946    }
947
948    /// Gets the size of the referenced type `T`.
949    ///
950    /// # Examples
951    ///
952    /// ```
953    /// # use std::mem::size_of;
954    /// # use vm_memory::VolatileRef;
955    /// #
956    /// let v_ref = unsafe { VolatileRef::<u32>::new(0 as *mut _) };
957    /// assert_eq!(v_ref.len(), size_of::<u32>() as usize);
958    /// ```
959    pub fn len(&self) -> usize {
960        size_of::<T>()
961    }
962
963    /// Borrows the inner `BitmapSlice`.
964    pub fn bitmap(&self) -> &B {
965        &self.bitmap
966    }
967
968    /// Does a volatile write of the value `v` to the address of this ref.
969    #[inline(always)]
970    pub fn store(&self, v: T) {
971        let guard = self.ptr_guard_mut();
972
973        // SAFETY: Safe because we checked the address and size when creating this VolatileRef.
974        unsafe { write_volatile(guard.as_ptr() as *mut Packed<T>, Packed::<T>(v)) };
975        self.bitmap.mark_dirty(0, self.len())
976    }
977
978    /// Does a volatile read of the value at the address of this ref.
979    #[inline(always)]
980    pub fn load(&self) -> T {
981        let guard = self.ptr_guard();
982
983        // SAFETY: Safe because we checked the address and size when creating this VolatileRef.
984        // For the purposes of demonstrating why read_volatile is necessary, try replacing the code
985        // in this function with the commented code below and running `cargo test --release`.
986        // unsafe { *(self.addr as *const T) }
987        unsafe { read_volatile(guard.as_ptr() as *const Packed<T>).0 }
988    }
989
990    /// Converts this to a [`VolatileSlice`](struct.VolatileSlice.html) with the same size and
991    /// address.
992    pub fn to_slice(&self) -> VolatileSlice<'a, B> {
993        // SAFETY: Safe because we checked the address and size when creating this VolatileRef.
994        unsafe {
995            VolatileSlice::with_bitmap(
996                self.addr as *mut u8,
997                size_of::<T>(),
998                self.bitmap.clone(),
999                self.mmap,
1000            )
1001        }
1002    }
1003}
1004
1005/// A memory location that supports volatile access to an array of elements of type `T`.
1006///
1007/// # Examples
1008///
1009/// ```
1010/// # use vm_memory::VolatileArrayRef;
1011/// #
1012/// let mut v = [5u32; 1];
1013/// let v_ref = unsafe { VolatileArrayRef::new(&mut v[0] as *mut u32 as *mut u8, v.len()) };
1014///
1015/// assert_eq!(v[0], 5);
1016/// assert_eq!(v_ref.load(0), 5);
1017/// v_ref.store(0, 500);
1018/// assert_eq!(v[0], 500);
1019/// ```
1020#[derive(Clone, Copy, Debug)]
1021pub struct VolatileArrayRef<'a, T, B = ()> {
1022    addr: *mut u8,
1023    nelem: usize,
1024    bitmap: B,
1025    phantom: PhantomData<&'a T>,
1026    mmap: Option<&'a MmapInfo>,
1027}
1028
1029impl<T> VolatileArrayRef<'_, T>
1030where
1031    T: ByteValued,
1032{
1033    /// Creates a [`VolatileArrayRef`](struct.VolatileArrayRef.html) to an array of elements of
1034    /// type `T`.
1035    ///
1036    /// # Safety
1037    ///
1038    /// To use this safely, the caller must guarantee that the memory at `addr` is big enough for
1039    /// `nelem` values of type `T` and is available for the duration of the lifetime of the new
1040    /// `VolatileRef`. The caller must also guarantee that all other users of the given chunk of
1041    /// memory are using volatile accesses.
1042    pub unsafe fn new(addr: *mut u8, nelem: usize) -> Self {
1043        Self::with_bitmap(addr, nelem, (), None)
1044    }
1045}
1046
1047impl<'a, T, B> VolatileArrayRef<'a, T, B>
1048where
1049    T: ByteValued,
1050    B: BitmapSlice,
1051{
1052    /// Creates a [`VolatileArrayRef`](struct.VolatileArrayRef.html) to an array of elements of
1053    /// type `T`, using the provided `bitmap` object for dirty page tracking.
1054    ///
1055    /// # Safety
1056    ///
1057    /// To use this safely, the caller must guarantee that the memory at `addr` is big enough for
1058    /// `nelem` values of type `T` and is available for the duration of the lifetime of the new
1059    /// `VolatileRef`. The caller must also guarantee that all other users of the given chunk of
1060    /// memory are using volatile accesses.
1061    pub unsafe fn with_bitmap(
1062        addr: *mut u8,
1063        nelem: usize,
1064        bitmap: B,
1065        mmap: Option<&'a MmapInfo>,
1066    ) -> Self {
1067        VolatileArrayRef {
1068            addr,
1069            nelem,
1070            bitmap,
1071            phantom: PhantomData,
1072            mmap,
1073        }
1074    }
1075
1076    /// Returns `true` if this array is empty.
1077    ///
1078    /// # Examples
1079    ///
1080    /// ```
1081    /// # use vm_memory::VolatileArrayRef;
1082    /// #
1083    /// let v_array = unsafe { VolatileArrayRef::<u32>::new(0 as *mut _, 0) };
1084    /// assert!(v_array.is_empty());
1085    /// ```
1086    pub fn is_empty(&self) -> bool {
1087        self.nelem == 0
1088    }
1089
1090    /// Returns the number of elements in the array.
1091    ///
1092    /// # Examples
1093    ///
1094    /// ```
1095    /// # use vm_memory::VolatileArrayRef;
1096    /// #
1097    /// # let v_array = unsafe { VolatileArrayRef::<u32>::new(0 as *mut _, 1) };
1098    /// assert_eq!(v_array.len(), 1);
1099    /// ```
1100    pub fn len(&self) -> usize {
1101        self.nelem
1102    }
1103
1104    /// Returns the size of `T`.
1105    ///
1106    /// # Examples
1107    ///
1108    /// ```
1109    /// # use std::mem::size_of;
1110    /// # use vm_memory::VolatileArrayRef;
1111    /// #
1112    /// let v_ref = unsafe { VolatileArrayRef::<u32>::new(0 as *mut _, 0) };
1113    /// assert_eq!(v_ref.element_size(), size_of::<u32>() as usize);
1114    /// ```
1115    pub fn element_size(&self) -> usize {
1116        size_of::<T>()
1117    }
1118
1119    /// Returns a guard for the pointer to the underlying memory.
1120    pub fn ptr_guard(&self) -> PtrGuard {
1121        PtrGuard::read(self.mmap, self.addr, self.len())
1122    }
1123
1124    /// Returns a mutable guard for the pointer to the underlying memory.
1125    pub fn ptr_guard_mut(&self) -> PtrGuardMut {
1126        PtrGuardMut::write(self.mmap, self.addr, self.len())
1127    }
1128
1129    /// Borrows the inner `BitmapSlice`.
1130    pub fn bitmap(&self) -> &B {
1131        &self.bitmap
1132    }
1133
1134    /// Converts this to a `VolatileSlice` with the same size and address.
1135    pub fn to_slice(&self) -> VolatileSlice<'a, B> {
1136        // SAFETY: Safe as long as the caller validated addr when creating this object.
1137        unsafe {
1138            VolatileSlice::with_bitmap(
1139                self.addr,
1140                self.nelem * self.element_size(),
1141                self.bitmap.clone(),
1142                self.mmap,
1143            )
1144        }
1145    }
1146
1147    /// Does a volatile read of the element at `index`.
1148    ///
1149    /// # Panics
1150    ///
1151    /// Panics if `index` is less than the number of elements of the array to which `&self` points.
1152    pub fn ref_at(&self, index: usize) -> VolatileRef<'a, T, B> {
1153        assert!(index < self.nelem);
1154        // SAFETY: Safe because the memory has the same lifetime and points to a subset of the
1155        // memory of the VolatileArrayRef.
1156        unsafe {
1157            // byteofs must fit in an isize as it was checked in get_array_ref.
1158            let byteofs = (self.element_size() * index) as isize;
1159            let ptr = self.addr.offset(byteofs);
1160            VolatileRef::with_bitmap(ptr, self.bitmap.slice_at(byteofs as usize), self.mmap)
1161        }
1162    }
1163
1164    /// Does a volatile read of the element at `index`.
1165    pub fn load(&self, index: usize) -> T {
1166        self.ref_at(index).load()
1167    }
1168
1169    /// Does a volatile write of the element at `index`.
1170    pub fn store(&self, index: usize, value: T) {
1171        // The `VolatileRef::store` call below implements the required dirty bitmap tracking logic,
1172        // so no need to do that in this method as well.
1173        self.ref_at(index).store(value)
1174    }
1175
1176    /// Copies as many elements of type `T` as possible from this array to `buf`.
1177    ///
1178    /// Copies `self.len()` or `buf.len()` times the size of `T` bytes, whichever is smaller,
1179    /// to `buf`. The copy happens from smallest to largest address in `T` sized chunks
1180    /// using volatile reads.
1181    ///
1182    /// # Examples
1183    ///
1184    /// ```
1185    /// # use vm_memory::VolatileArrayRef;
1186    /// #
1187    /// let mut v = [0u8; 32];
1188    /// let v_ref = unsafe { VolatileArrayRef::new(v.as_mut_ptr(), v.len()) };
1189    ///
1190    /// let mut buf = [5u8; 16];
1191    /// v_ref.copy_to(&mut buf[..]);
1192    /// for &v in &buf[..] {
1193    ///     assert_eq!(v, 0);
1194    /// }
1195    /// ```
1196    pub fn copy_to(&self, buf: &mut [T]) -> usize {
1197        // A fast path for u8/i8
1198        if size_of::<T>() == 1 {
1199            let source = self.to_slice();
1200            let total = buf.len().min(source.len());
1201
1202            // SAFETY:
1203            // - dst is valid for writes of at least `total`, since total <= buf.len()
1204            // - src is valid for reads of at least `total` as total <= source.len()
1205            // - The regions are non-overlapping as `src` points to guest memory and `buf` is
1206            //   a slice and thus has to live outside of guest memory (there can be more slices to
1207            //   guest memory without violating rust's aliasing rules)
1208            // - size is always a multiple of alignment, so treating *mut T as *mut u8 is fine
1209            return unsafe {
1210                copy_from_volatile_slice(buf.as_mut_ptr() as *mut u8, &source, total)
1211            };
1212        }
1213
1214        let guard = self.ptr_guard();
1215        let mut ptr = guard.as_ptr() as *const Packed<T>;
1216        let start = ptr;
1217
1218        for v in buf.iter_mut().take(self.len()) {
1219            // SAFETY: read_volatile is safe because the pointers are range-checked when
1220            // the slices are created, and they never escape the VolatileSlices.
1221            // ptr::add is safe because get_array_ref() validated that
1222            // size_of::<T>() * self.len() fits in an isize.
1223            unsafe {
1224                *v = read_volatile(ptr).0;
1225                ptr = ptr.add(1);
1226            }
1227        }
1228
1229        // SAFETY: It is guaranteed that start and ptr point to the regions of the same slice.
1230        unsafe { ptr.offset_from(start) as usize }
1231    }
1232
1233    /// Copies as many bytes as possible from this slice to the provided `slice`.
1234    ///
1235    /// The copies happen in an undefined order.
1236    ///
1237    /// # Examples
1238    ///
1239    /// ```
1240    /// # use vm_memory::VolatileArrayRef;
1241    /// #
1242    /// let mut v = [0u8; 32];
1243    /// let v_ref = unsafe { VolatileArrayRef::<u8>::new(v.as_mut_ptr(), v.len()) };
1244    /// let mut buf = [5u8; 16];
1245    /// let v_ref2 = unsafe { VolatileArrayRef::<u8>::new(buf.as_mut_ptr(), buf.len()) };
1246    ///
1247    /// v_ref.copy_to_volatile_slice(v_ref2.to_slice());
1248    /// for &v in &buf[..] {
1249    ///     assert_eq!(v, 0);
1250    /// }
1251    /// ```
1252    pub fn copy_to_volatile_slice<S: BitmapSlice>(&self, slice: VolatileSlice<S>) {
1253        // SAFETY: Safe because the pointers are range-checked when the slices
1254        // are created, and they never escape the VolatileSlices.
1255        // FIXME: ... however, is it really okay to mix non-volatile
1256        // operations such as copy with read_volatile and write_volatile?
1257        unsafe {
1258            let count = min(self.len() * self.element_size(), slice.size);
1259            copy(self.addr, slice.addr, count);
1260            slice.bitmap.mark_dirty(0, count);
1261        }
1262    }
1263
1264    /// Copies as many elements of type `T` as possible from `buf` to this slice.
1265    ///
1266    /// Copies `self.len()` or `buf.len()` times the size of `T` bytes, whichever is smaller,
1267    /// to this slice's memory. The copy happens from smallest to largest address in
1268    /// `T` sized chunks using volatile writes.
1269    ///
1270    /// # Examples
1271    ///
1272    /// ```
1273    /// # use vm_memory::VolatileArrayRef;
1274    /// #
1275    /// let mut v = [0u8; 32];
1276    /// let v_ref = unsafe { VolatileArrayRef::<u8>::new(v.as_mut_ptr(), v.len()) };
1277    ///
1278    /// let buf = [5u8; 64];
1279    /// v_ref.copy_from(&buf[..]);
1280    /// for &val in &v[..] {
1281    ///     assert_eq!(5u8, val);
1282    /// }
1283    /// ```
1284    pub fn copy_from(&self, buf: &[T]) {
1285        // A fast path for u8/i8
1286        if size_of::<T>() == 1 {
1287            let destination = self.to_slice();
1288            let total = buf.len().min(destination.len());
1289
1290            // absurd formatting brought to you by clippy
1291            // SAFETY:
1292            // - dst is valid for writes of at least `total`, since total <= destination.len()
1293            // - src is valid for reads of at least `total` as total <= buf.len()
1294            // - The regions are non-overlapping as `dst` points to guest memory and `buf` is
1295            //   a slice and thus has to live outside of guest memory (there can be more slices to
1296            //   guest memory without violating rust's aliasing rules)
1297            // - size is always a multiple of alignment, so treating *const T as *const u8 is fine
1298            unsafe { copy_to_volatile_slice(&destination, buf.as_ptr() as *const u8, total) };
1299        } else {
1300            let guard = self.ptr_guard_mut();
1301            let start = guard.as_ptr();
1302            let mut ptr = start as *mut Packed<T>;
1303
1304            for &v in buf.iter().take(self.len()) {
1305                // SAFETY: write_volatile is safe because the pointers are range-checked when
1306                // the slices are created, and they never escape the VolatileSlices.
1307                // ptr::add is safe because get_array_ref() validated that
1308                // size_of::<T>() * self.len() fits in an isize.
1309                unsafe {
1310                    write_volatile(ptr, Packed::<T>(v));
1311                    ptr = ptr.add(1);
1312                }
1313            }
1314
1315            self.bitmap.mark_dirty(0, ptr as usize - start as usize);
1316        }
1317    }
1318}
1319
1320impl<'a, B: BitmapSlice> From<VolatileSlice<'a, B>> for VolatileArrayRef<'a, u8, B> {
1321    fn from(slice: VolatileSlice<'a, B>) -> Self {
1322        // SAFETY: Safe because the result has the same lifetime and points to the same
1323        // memory as the incoming VolatileSlice.
1324        unsafe { VolatileArrayRef::with_bitmap(slice.addr, slice.len(), slice.bitmap, slice.mmap) }
1325    }
1326}
1327
1328// Return the largest value that `addr` is aligned to. Forcing this function to return 1 will
1329// cause test_non_atomic_access to fail.
1330fn alignment(addr: usize) -> usize {
1331    // Rust is silly and does not let me write addr & -addr.
1332    addr & (!addr + 1)
1333}
1334
1335pub(crate) mod copy_slice_impl {
1336    use super::*;
1337
1338    // SAFETY: Has the same safety requirements as `read_volatile` + `write_volatile`, namely:
1339    // - `src_addr` and `dst_addr` must be valid for reads/writes.
1340    // - `src_addr` and `dst_addr` must be properly aligned with respect to `align`.
1341    // - `src_addr` must point to a properly initialized value, which is true here because
1342    //   we're only using integer primitives.
1343    unsafe fn copy_single(align: usize, src_addr: *const u8, dst_addr: *mut u8) {
1344        match align {
1345            8 => write_volatile(dst_addr as *mut u64, read_volatile(src_addr as *const u64)),
1346            4 => write_volatile(dst_addr as *mut u32, read_volatile(src_addr as *const u32)),
1347            2 => write_volatile(dst_addr as *mut u16, read_volatile(src_addr as *const u16)),
1348            1 => write_volatile(dst_addr, read_volatile(src_addr)),
1349            _ => unreachable!(),
1350        }
1351    }
1352
1353    /// Copies `total` bytes from `src` to `dst` using a loop of volatile reads and writes
1354    ///
1355    /// SAFETY: `src` and `dst` must be point to a contiguously allocated memory region of at least
1356    /// length `total`. The regions must not overlap
1357    unsafe fn copy_slice_volatile(mut dst: *mut u8, mut src: *const u8, total: usize) -> usize {
1358        let mut left = total;
1359
1360        let align = min(alignment(src as usize), alignment(dst as usize));
1361
1362        let mut copy_aligned_slice = |min_align| {
1363            if align < min_align {
1364                return;
1365            }
1366
1367            while left >= min_align {
1368                // SAFETY: Safe because we check alignment beforehand, the memory areas are valid
1369                // for reads/writes, and the source always contains a valid value.
1370                unsafe { copy_single(min_align, src, dst) };
1371
1372                left -= min_align;
1373
1374                if left == 0 {
1375                    break;
1376                }
1377
1378                // SAFETY: We only explain the invariants for `src`, the argument for `dst` is
1379                // analogous.
1380                // - `src` and `src + min_align` are within (or one byte past) the same allocated object
1381                //   This is given by the invariant on this function ensuring that [src, src + total)
1382                //   are part of the same allocated object, and the condition on the while loop
1383                //   ensures that we do not go outside this object
1384                // - The computed offset in bytes cannot overflow isize, because `min_align` is at
1385                //   most 8 when the closure is called (see below)
1386                // - The sum `src as usize + min_align` can only wrap around if src as usize + min_align - 1 == usize::MAX,
1387                //   however in this case, left == 0, and we'll have exited the loop above.
1388                unsafe {
1389                    src = src.add(min_align);
1390                    dst = dst.add(min_align);
1391                }
1392            }
1393        };
1394
1395        if size_of::<usize>() > 4 {
1396            copy_aligned_slice(8);
1397        }
1398        copy_aligned_slice(4);
1399        copy_aligned_slice(2);
1400        copy_aligned_slice(1);
1401
1402        total
1403    }
1404
1405    /// Copies `total` bytes from `src` to `dst`
1406    ///
1407    /// SAFETY: `src` and `dst` must be point to a contiguously allocated memory region of at least
1408    /// length `total`. The regions must not overlap
1409    unsafe fn copy_slice(dst: *mut u8, src: *const u8, total: usize) -> usize {
1410        if total <= size_of::<usize>() {
1411            // SAFETY: Invariants of copy_slice_volatile are the same as invariants of copy_slice
1412            unsafe {
1413                copy_slice_volatile(dst, src, total);
1414            };
1415        } else {
1416            // SAFETY:
1417            // - Both src and dst are allocated for reads/writes of length `total` by function
1418            //   invariant
1419            // - src and dst are properly aligned, as any alignment is valid for u8
1420            // - The regions are not overlapping by function invariant
1421            unsafe {
1422                std::ptr::copy_nonoverlapping(src, dst, total);
1423            }
1424        }
1425
1426        total
1427    }
1428
1429    /// Copies `total` bytes from `slice` to `dst`
1430    ///
1431    /// SAFETY: `slice` and `dst` must be point to a contiguously allocated memory region of at
1432    /// least length `total`. The regions must not overlap.
1433    pub(crate) unsafe fn copy_from_volatile_slice<B: BitmapSlice>(
1434        dst: *mut u8,
1435        slice: &VolatileSlice<'_, B>,
1436        total: usize,
1437    ) -> usize {
1438        let guard = slice.ptr_guard();
1439
1440        // SAFETY: guaranteed by function invariants.
1441        copy_slice(dst, guard.as_ptr(), total)
1442    }
1443
1444    /// Copies `total` bytes from 'src' to `slice`
1445    ///
1446    /// SAFETY: `slice` and `src` must be point to a contiguously allocated memory region of at
1447    /// least length `total`. The regions must not overlap.
1448    pub(crate) unsafe fn copy_to_volatile_slice<B: BitmapSlice>(
1449        slice: &VolatileSlice<'_, B>,
1450        src: *const u8,
1451        total: usize,
1452    ) -> usize {
1453        let guard = slice.ptr_guard_mut();
1454
1455        // SAFETY: guaranteed by function invariants.
1456        let count = copy_slice(guard.as_ptr(), src, total);
1457        slice.bitmap.mark_dirty(0, count);
1458        count
1459    }
1460}
1461
1462#[cfg(test)]
1463mod tests {
1464    #![allow(clippy::undocumented_unsafe_blocks)]
1465
1466    use super::*;
1467    use std::alloc::Layout;
1468
1469    #[cfg(feature = "rawfd")]
1470    use std::fs::File;
1471    #[cfg(feature = "backend-bitmap")]
1472    use std::mem::size_of_val;
1473    #[cfg(feature = "rawfd")]
1474    use std::path::Path;
1475    use std::sync::atomic::{AtomicUsize, Ordering};
1476    use std::sync::{Arc, Barrier};
1477    use std::thread::spawn;
1478
1479    use matches::assert_matches;
1480    #[cfg(feature = "backend-bitmap")]
1481    use std::num::NonZeroUsize;
1482    #[cfg(feature = "rawfd")]
1483    use vmm_sys_util::tempfile::TempFile;
1484
1485    #[cfg(feature = "backend-bitmap")]
1486    use crate::bitmap::tests::{
1487        check_range, range_is_clean, range_is_dirty, test_bytes, test_volatile_memory,
1488    };
1489    #[cfg(feature = "backend-bitmap")]
1490    use crate::bitmap::{AtomicBitmap, RefSlice};
1491
1492    #[cfg(feature = "backend-bitmap")]
1493    const DEFAULT_PAGE_SIZE: NonZeroUsize = NonZeroUsize::new(0x1000).unwrap();
1494
1495    #[test]
1496    fn test_compute_end_offset() {
1497        let mut array = [1, 2, 3, 4, 5];
1498        let slice = VolatileSlice::from(array.as_mut_slice());
1499
1500        // Iterate over all valid ranges, assert that they pass validation.
1501        // This includes edge cases such as len = 0 and base = 5!
1502        for len in 0..slice.len() {
1503            for base in 0..=slice.len() - len {
1504                assert_eq!(
1505                    slice.compute_end_offset(base, len).unwrap(),
1506                    len + base,
1507                    "compute_end_offset rejected valid base/offset pair {base} + {len}"
1508                );
1509            }
1510        }
1511
1512        // Check invalid configurations
1513        slice.compute_end_offset(5, 1).unwrap_err();
1514        slice.compute_end_offset(6, 0).unwrap_err();
1515    }
1516
1517    #[test]
1518    fn misaligned_ref() {
1519        let mut a = [0u8; 3];
1520        let a_ref = VolatileSlice::from(&mut a[..]);
1521        unsafe {
1522            let result0 = a_ref.aligned_as_ref::<u16>(0);
1523            let result1 = a_ref.aligned_as_ref::<u16>(1);
1524            assert_matches!((result0, result1), (Ok(_), Err(_)) | (Err(_), Ok(_)));
1525
1526            let result0 = a_ref.aligned_as_mut::<u16>(0);
1527            let result1 = a_ref.aligned_as_mut::<u16>(1);
1528            assert_matches!((result0, result1), (Ok(_), Err(_)) | (Err(_), Ok(_)));
1529        }
1530    }
1531
1532    #[test]
1533    fn atomic_store() {
1534        let mut a = [0usize; 1];
1535        {
1536            let a_ref = unsafe {
1537                VolatileSlice::new(&mut a[0] as *mut usize as *mut u8, size_of::<usize>())
1538            };
1539            let atomic = a_ref.get_atomic_ref::<AtomicUsize>(0).unwrap();
1540            atomic.store(2usize, Ordering::Relaxed)
1541        }
1542        assert_eq!(a[0], 2);
1543    }
1544
1545    #[test]
1546    fn atomic_load() {
1547        let mut a = [5usize; 1];
1548        {
1549            let a_ref = unsafe {
1550                VolatileSlice::new(&mut a[0] as *mut usize as *mut u8,
1551                                   size_of::<usize>())
1552            };
1553            let atomic = {
1554                let atomic = a_ref.get_atomic_ref::<AtomicUsize>(0).unwrap();
1555                assert_eq!(atomic.load(Ordering::Relaxed), 5usize);
1556                atomic
1557            };
1558            // To make sure we can take the atomic out of the scope we made it in:
1559            atomic.load(Ordering::Relaxed);
1560            // but not too far:
1561            // atomicu8
1562        } //.load(std::sync::atomic::Ordering::Relaxed)
1563        ;
1564    }
1565
1566    #[test]
1567    fn misaligned_atomic() {
1568        let mut a = [5usize, 5usize];
1569        let a_ref =
1570            unsafe { VolatileSlice::new(&mut a[0] as *mut usize as *mut u8, size_of::<usize>()) };
1571        a_ref.get_atomic_ref::<AtomicUsize>(0).unwrap();
1572        assert_matches!(
1573            a_ref.get_atomic_ref::<AtomicUsize>(1).unwrap_err(),
1574            Error::OutOfBounds { addr: 9 }
1575        );
1576    }
1577
1578    #[test]
1579    fn ref_store() {
1580        let mut a = [0u8; 1];
1581        {
1582            let a_ref = VolatileSlice::from(&mut a[..]);
1583            let v_ref = a_ref.get_ref(0).unwrap();
1584            v_ref.store(2u8);
1585        }
1586        assert_eq!(a[0], 2);
1587    }
1588
1589    #[test]
1590    fn ref_load() {
1591        let mut a = [5u8; 1];
1592        {
1593            let a_ref = VolatileSlice::from(&mut a[..]);
1594            let c = {
1595                let v_ref = a_ref.get_ref::<u8>(0).unwrap();
1596                assert_eq!(v_ref.load(), 5u8);
1597                v_ref
1598            };
1599            // To make sure we can take a v_ref out of the scope we made it in:
1600            c.load();
1601            // but not too far:
1602            // c
1603        } //.load()
1604        ;
1605    }
1606
1607    #[test]
1608    fn ref_to_slice() {
1609        let mut a = [1u8; 5];
1610        let a_ref = VolatileSlice::from(&mut a[..]);
1611        let v_ref = a_ref.get_ref(1).unwrap();
1612        v_ref.store(0x1234_5678u32);
1613        let ref_slice = v_ref.to_slice();
1614        assert_eq!(v_ref.addr as usize, ref_slice.addr as usize);
1615        assert_eq!(v_ref.len(), ref_slice.len());
1616        assert!(!ref_slice.is_empty());
1617    }
1618
1619    #[test]
1620    fn observe_mutate() {
1621        struct RawMemory(*mut u8);
1622
1623        // SAFETY: we use property synchronization below
1624        unsafe impl Send for RawMemory {}
1625        unsafe impl Sync for RawMemory {}
1626
1627        let mem = Arc::new(RawMemory(unsafe {
1628            std::alloc::alloc(Layout::from_size_align(1, 1).unwrap())
1629        }));
1630
1631        let outside_slice = unsafe { VolatileSlice::new(Arc::clone(&mem).0, 1) };
1632        let inside_arc = Arc::clone(&mem);
1633
1634        let v_ref = outside_slice.get_ref::<u8>(0).unwrap();
1635        let barrier = Arc::new(Barrier::new(2));
1636        let barrier1 = barrier.clone();
1637
1638        v_ref.store(99);
1639        spawn(move || {
1640            barrier1.wait();
1641            let inside_slice = unsafe { VolatileSlice::new(inside_arc.0, 1) };
1642            let clone_v_ref = inside_slice.get_ref::<u8>(0).unwrap();
1643            clone_v_ref.store(0);
1644            barrier1.wait();
1645        });
1646
1647        assert_eq!(v_ref.load(), 99);
1648        barrier.wait();
1649        barrier.wait();
1650        assert_eq!(v_ref.load(), 0);
1651
1652        unsafe { std::alloc::dealloc(mem.0, Layout::from_size_align(1, 1).unwrap()) }
1653    }
1654
1655    #[test]
1656    fn mem_is_empty() {
1657        let mut backing = vec![0u8; 100];
1658        let a = VolatileSlice::from(backing.as_mut_slice());
1659        assert!(!a.is_empty());
1660
1661        let mut backing = vec![];
1662        let a = VolatileSlice::from(backing.as_mut_slice());
1663        assert!(a.is_empty());
1664    }
1665
1666    #[test]
1667    fn slice_len() {
1668        let mut backing = vec![0u8; 100];
1669        let mem = VolatileSlice::from(backing.as_mut_slice());
1670        let slice = mem.get_slice(0, 27).unwrap();
1671        assert_eq!(slice.len(), 27);
1672        assert!(!slice.is_empty());
1673
1674        let slice = mem.get_slice(34, 27).unwrap();
1675        assert_eq!(slice.len(), 27);
1676        assert!(!slice.is_empty());
1677
1678        let slice = slice.get_slice(20, 5).unwrap();
1679        assert_eq!(slice.len(), 5);
1680        assert!(!slice.is_empty());
1681
1682        let slice = mem.get_slice(34, 0).unwrap();
1683        assert!(slice.is_empty());
1684    }
1685
1686    #[test]
1687    fn slice_subslice() {
1688        let mut backing = vec![0u8; 100];
1689        let mem = VolatileSlice::from(backing.as_mut_slice());
1690        let slice = mem.get_slice(0, 100).unwrap();
1691        slice.write(&[1; 80], 10).unwrap();
1692
1693        slice.subslice(0, 0).unwrap();
1694        assert_matches!(
1695            slice.subslice(0, 101).unwrap_err(),
1696            Error::OutOfBounds { addr: 101 }
1697        );
1698
1699        slice.subslice(99, 0).unwrap();
1700        slice.subslice(99, 1).unwrap();
1701        assert_matches!(
1702            slice.subslice(99, 2).unwrap_err(),
1703            Error::OutOfBounds { addr: 101 }
1704        );
1705
1706        slice.subslice(100, 0).unwrap();
1707        assert_matches!(
1708            slice.subslice(100, 1).unwrap_err(),
1709            Error::OutOfBounds { addr: 101 }
1710        );
1711
1712        assert_matches!(
1713            slice.subslice(101, 0).unwrap_err(),
1714            Error::OutOfBounds { addr: 101 }
1715        );
1716        assert_matches!(
1717            slice.subslice(101, 1).unwrap_err(),
1718            Error::OutOfBounds { addr: 102 }
1719        );
1720
1721        assert_matches!(
1722            slice.subslice(usize::MAX, 2).unwrap_err(),
1723            Error::Overflow {
1724                base: usize::MAX,
1725                offset: 2
1726            }
1727        );
1728        assert_matches!(
1729            slice.subslice(2, usize::MAX).unwrap_err(),
1730            Error::Overflow {
1731                base: 2,
1732                offset: usize::MAX
1733            }
1734        );
1735
1736        let offset_slice = slice.subslice(10, 80).unwrap();
1737        assert_eq!(offset_slice.len(), 80);
1738
1739        let mut buf = [0; 80];
1740        offset_slice.read(&mut buf, 0).unwrap();
1741        assert_eq!(&buf[0..80], &[1; 80][0..80]);
1742    }
1743
1744    #[test]
1745    fn slice_offset() {
1746        let mut backing = vec![0u8; 100];
1747        let mem = VolatileSlice::from(backing.as_mut_slice());
1748        let slice = mem.get_slice(0, 100).unwrap();
1749        slice.write(&[1; 80], 10).unwrap();
1750
1751        assert_matches!(
1752            slice.offset(101).unwrap_err(),
1753            Error::OutOfBounds { addr } if addr == slice.addr as usize + 101
1754        );
1755
1756        let offset_slice = slice.offset(10).unwrap();
1757        assert_eq!(offset_slice.len(), 90);
1758        let mut buf = [0; 90];
1759        offset_slice.read(&mut buf, 0).unwrap();
1760        assert_eq!(&buf[0..80], &[1; 80][0..80]);
1761        assert_eq!(&buf[80..90], &[0; 10][0..10]);
1762    }
1763
1764    #[test]
1765    fn slice_copy_to_u8() {
1766        let mut a = [2u8, 4, 6, 8, 10];
1767        let mut b = [0u8; 4];
1768        let mut c = [0u8; 6];
1769        let a_ref = VolatileSlice::from(&mut a[..]);
1770        let v_ref = a_ref.get_slice(0, a_ref.len()).unwrap();
1771        v_ref.copy_to(&mut b[..]);
1772        v_ref.copy_to(&mut c[..]);
1773        assert_eq!(b[0..4], a[0..4]);
1774        assert_eq!(c[0..5], a[0..5]);
1775    }
1776
1777    #[test]
1778    fn slice_copy_to_u16() {
1779        let mut a = [0x01u16, 0x2, 0x03, 0x4, 0x5];
1780        let mut b = [0u16; 4];
1781        let mut c = [0u16; 6];
1782        let a_ref = &mut a[..];
1783        let v_ref = unsafe { VolatileSlice::new(a_ref.as_mut_ptr() as *mut u8, 9) };
1784
1785        v_ref.copy_to(&mut b[..]);
1786        v_ref.copy_to(&mut c[..]);
1787        assert_eq!(b[0..4], a_ref[0..4]);
1788        assert_eq!(c[0..4], a_ref[0..4]);
1789        assert_eq!(c[4], 0);
1790    }
1791
1792    #[test]
1793    fn slice_copy_from_u8() {
1794        let a = [2u8, 4, 6, 8, 10];
1795        let mut b = [0u8; 4];
1796        let mut c = [0u8; 6];
1797        let b_ref = VolatileSlice::from(&mut b[..]);
1798        let v_ref = b_ref.get_slice(0, b_ref.len()).unwrap();
1799        v_ref.copy_from(&a[..]);
1800        assert_eq!(b[0..4], a[0..4]);
1801
1802        let c_ref = VolatileSlice::from(&mut c[..]);
1803        let v_ref = c_ref.get_slice(0, c_ref.len()).unwrap();
1804        v_ref.copy_from(&a[..]);
1805        assert_eq!(c[0..5], a[0..5]);
1806    }
1807
1808    #[test]
1809    fn slice_copy_from_u16() {
1810        let a = [2u16, 4, 6, 8, 10];
1811        let mut b = [0u16; 4];
1812        let mut c = [0u16; 6];
1813        let b_ref = &mut b[..];
1814        let v_ref = unsafe { VolatileSlice::new(b_ref.as_mut_ptr() as *mut u8, 8) };
1815        v_ref.copy_from(&a[..]);
1816        assert_eq!(b_ref[0..4], a[0..4]);
1817
1818        let c_ref = &mut c[..];
1819        let v_ref = unsafe { VolatileSlice::new(c_ref.as_mut_ptr() as *mut u8, 9) };
1820        v_ref.copy_from(&a[..]);
1821        assert_eq!(c_ref[0..4], a[0..4]);
1822        assert_eq!(c_ref[4], 0);
1823    }
1824
1825    #[test]
1826    fn slice_copy_to_volatile_slice() {
1827        let mut a = [2u8, 4, 6, 8, 10];
1828        let a_ref = VolatileSlice::from(&mut a[..]);
1829        let a_slice = a_ref.get_slice(0, a_ref.len()).unwrap();
1830
1831        let mut b = [0u8; 4];
1832        let b_ref = VolatileSlice::from(&mut b[..]);
1833        let b_slice = b_ref.get_slice(0, b_ref.len()).unwrap();
1834
1835        a_slice.copy_to_volatile_slice(b_slice);
1836        assert_eq!(b, [2, 4, 6, 8]);
1837    }
1838
1839    #[test]
1840    fn slice_overflow_error() {
1841        let mut backing = vec![0u8];
1842        let a = VolatileSlice::from(backing.as_mut_slice());
1843        let res = a.get_slice(usize::MAX, 1).unwrap_err();
1844        assert_matches!(
1845            res,
1846            Error::Overflow {
1847                base: usize::MAX,
1848                offset: 1,
1849            }
1850        );
1851    }
1852
1853    #[test]
1854    fn slice_oob_error() {
1855        let mut backing = vec![0u8; 100];
1856        let a = VolatileSlice::from(backing.as_mut_slice());
1857        a.get_slice(50, 50).unwrap();
1858        let res = a.get_slice(55, 50).unwrap_err();
1859        assert_matches!(res, Error::OutOfBounds { addr: 105 });
1860    }
1861
1862    #[test]
1863    fn ref_overflow_error() {
1864        let mut backing = vec![0u8];
1865        let a = VolatileSlice::from(backing.as_mut_slice());
1866        let res = a.get_ref::<u8>(usize::MAX).unwrap_err();
1867        assert_matches!(
1868            res,
1869            Error::Overflow {
1870                base: usize::MAX,
1871                offset: 1,
1872            }
1873        );
1874    }
1875
1876    #[test]
1877    fn ref_oob_error() {
1878        let mut backing = vec![0u8; 100];
1879        let a = VolatileSlice::from(backing.as_mut_slice());
1880        a.get_ref::<u8>(99).unwrap();
1881        let res = a.get_ref::<u16>(99).unwrap_err();
1882        assert_matches!(res, Error::OutOfBounds { addr: 101 });
1883    }
1884
1885    #[test]
1886    fn ref_oob_too_large() {
1887        let mut backing = vec![0u8; 3];
1888        let a = VolatileSlice::from(backing.as_mut_slice());
1889        let res = a.get_ref::<u32>(0).unwrap_err();
1890        assert_matches!(res, Error::OutOfBounds { addr: 4 });
1891    }
1892
1893    #[test]
1894    fn slice_store() {
1895        let mut backing = vec![0u8; 5];
1896        let a = VolatileSlice::from(backing.as_mut_slice());
1897        let s = a.as_volatile_slice();
1898        let r = a.get_ref(2).unwrap();
1899        r.store(9u16);
1900        assert_eq!(s.read_obj::<u16>(2).unwrap(), 9);
1901    }
1902
1903    #[test]
1904    fn test_write_past_end() {
1905        let mut backing = vec![0u8; 5];
1906        let a = VolatileSlice::from(backing.as_mut_slice());
1907        let s = a.as_volatile_slice();
1908        let res = s.write(&[1, 2, 3, 4, 5, 6], 0);
1909        assert_eq!(res.unwrap(), 5);
1910    }
1911
1912    #[test]
1913    fn slice_read_and_write() {
1914        let mut backing = vec![0u8; 5];
1915        let a = VolatileSlice::from(backing.as_mut_slice());
1916        let s = a.as_volatile_slice();
1917        let sample_buf = [1, 2, 3];
1918        assert_matches!(
1919            s.write(&sample_buf, 5).unwrap_err(),
1920            Error::OutOfBounds { addr: 5 }
1921        );
1922        s.write(&sample_buf, 2).unwrap();
1923        let mut buf = [0u8; 3];
1924        assert_matches!(
1925            s.read(&mut buf, 5).unwrap_err(),
1926            Error::OutOfBounds { addr: 5 }
1927        );
1928        s.read_slice(&mut buf, 2).unwrap();
1929        assert_eq!(buf, sample_buf);
1930
1931        // Writing an empty buffer at the end of the volatile slice works.
1932        assert_eq!(s.write(&[], 100).unwrap(), 0);
1933        let buf: &mut [u8] = &mut [];
1934        assert_eq!(s.read(buf, 4).unwrap(), 0);
1935
1936        // Check that reading and writing an empty buffer does not yield an error.
1937        let mut backing = Vec::new();
1938        let empty_mem = VolatileSlice::from(backing.as_mut_slice());
1939        let empty = empty_mem.as_volatile_slice();
1940        assert_eq!(empty.write(&[], 1).unwrap(), 0);
1941        assert_eq!(empty.read(buf, 1).unwrap(), 0);
1942    }
1943
1944    #[test]
1945    fn obj_read_and_write() {
1946        let mut backing = vec![0u8; 5];
1947        let a = VolatileSlice::from(backing.as_mut_slice());
1948        let s = a.as_volatile_slice();
1949        assert_matches!(
1950            s.write_obj(55u16, 4).unwrap_err(),
1951            Error::PartialBuffer {
1952                expected: 2,
1953                completed: 1
1954            }
1955        );
1956        assert_matches!(
1957            s.write_obj(55u16, usize::MAX).unwrap_err(),
1958            Error::OutOfBounds { addr: usize::MAX }
1959        );
1960        s.write_obj(55u16, 2).unwrap();
1961        assert_eq!(s.read_obj::<u16>(2).unwrap(), 55u16);
1962        assert_matches!(
1963            s.read_obj::<u16>(4).unwrap_err(),
1964            Error::PartialBuffer {
1965                expected: 2,
1966                completed: 1
1967            }
1968        );
1969        assert_matches!(
1970            s.read_obj::<u16>(usize::MAX).unwrap_err(),
1971            Error::OutOfBounds { addr: usize::MAX }
1972        );
1973    }
1974
1975    #[test]
1976    #[cfg(feature = "rawfd")]
1977    fn mem_read_and_write() {
1978        let mut backing = vec![0u8; 5];
1979        let a = VolatileSlice::from(backing.as_mut_slice());
1980        let s = a.as_volatile_slice();
1981        s.write_obj(!0u32, 1).unwrap();
1982        let mut file = if cfg!(target_family = "unix") {
1983            File::open(Path::new("/dev/zero")).unwrap()
1984        } else {
1985            File::open(Path::new("c:\\Windows\\system32\\ntoskrnl.exe")).unwrap()
1986        };
1987
1988        file.read_exact_volatile(&mut s.get_slice(1, size_of::<u32>()).unwrap())
1989            .unwrap();
1990
1991        let mut f = TempFile::new().unwrap().into_file();
1992        f.read_exact_volatile(&mut s.get_slice(1, size_of::<u32>()).unwrap())
1993            .unwrap_err();
1994
1995        let value = s.read_obj::<u32>(1).unwrap();
1996        if cfg!(target_family = "unix") {
1997            assert_eq!(value, 0);
1998        } else {
1999            assert_eq!(value, 0x0090_5a4d);
2000        }
2001
2002        let mut sink = vec![0; size_of::<u32>()];
2003        sink.as_mut_slice()
2004            .write_all_volatile(&s.get_slice(1, size_of::<u32>()).unwrap())
2005            .unwrap();
2006
2007        if cfg!(target_family = "unix") {
2008            assert_eq!(sink, vec![0; size_of::<u32>()]);
2009        } else {
2010            assert_eq!(sink, vec![0x4d, 0x5a, 0x90, 0x00]);
2011        };
2012    }
2013
2014    #[test]
2015    fn unaligned_read_and_write() {
2016        let mut backing = vec![0u8; 7];
2017        let a = VolatileSlice::from(backing.as_mut_slice());
2018        let s = a.as_volatile_slice();
2019        let sample_buf: [u8; 7] = [1, 2, 0xAA, 0xAA, 0xAA, 0xAA, 4];
2020        s.write_slice(&sample_buf, 0).unwrap();
2021        let r = a.get_ref::<u32>(2).unwrap();
2022        assert_eq!(r.load(), 0xAAAA_AAAA);
2023
2024        r.store(0x5555_5555);
2025        let sample_buf: [u8; 7] = [1, 2, 0x55, 0x55, 0x55, 0x55, 4];
2026        let mut buf: [u8; 7] = Default::default();
2027        s.read_slice(&mut buf, 0).unwrap();
2028        assert_eq!(buf, sample_buf);
2029    }
2030
2031    #[test]
2032    fn test_read_from_exceeds_size() {
2033        #[derive(Debug, Default, Copy, Clone)]
2034        struct BytesToRead {
2035            _val1: u128, // 16 bytes
2036            _val2: u128, // 16 bytes
2037        }
2038        unsafe impl ByteValued for BytesToRead {}
2039        let cursor_size = 20;
2040        let image = vec![1u8; cursor_size];
2041
2042        // Trying to read more bytes than we have space for in image
2043        // make the read_from function return maximum vec size (i.e. 20).
2044        let mut bytes_to_read = BytesToRead::default();
2045        assert_eq!(
2046            image
2047                .as_slice()
2048                .read_volatile(&mut bytes_to_read.as_bytes())
2049                .unwrap(),
2050            cursor_size
2051        );
2052    }
2053
2054    #[test]
2055    fn ref_array_from_slice() {
2056        let mut a = [2, 4, 6, 8, 10];
2057        let a_vec = a.to_vec();
2058        let a_ref = VolatileSlice::from(&mut a[..]);
2059        let a_slice = a_ref.get_slice(0, a_ref.len()).unwrap();
2060        let a_array_ref: VolatileArrayRef<u8, ()> = a_slice.into();
2061        for (i, entry) in a_vec.iter().enumerate() {
2062            assert_eq!(&a_array_ref.load(i), entry);
2063        }
2064    }
2065
2066    #[test]
2067    fn ref_array_store() {
2068        let mut a = [0u8; 5];
2069        {
2070            let a_ref = VolatileSlice::from(&mut a[..]);
2071            let v_ref = a_ref.get_array_ref(1, 4).unwrap();
2072            v_ref.store(1, 2u8);
2073            v_ref.store(2, 4u8);
2074            v_ref.store(3, 6u8);
2075        }
2076        let expected = [2u8, 4u8, 6u8];
2077        assert_eq!(a[2..=4], expected);
2078    }
2079
2080    #[test]
2081    fn ref_array_load() {
2082        let mut a = [0, 0, 2, 3, 10];
2083        {
2084            let a_ref = VolatileSlice::from(&mut a[..]);
2085            let c = {
2086                let v_ref = a_ref.get_array_ref::<u8>(1, 4).unwrap();
2087                assert_eq!(v_ref.load(1), 2u8);
2088                assert_eq!(v_ref.load(2), 3u8);
2089                assert_eq!(v_ref.load(3), 10u8);
2090                v_ref
2091            };
2092            // To make sure we can take a v_ref out of the scope we made it in:
2093            c.load(0);
2094            // but not too far:
2095            // c
2096        } //.load()
2097        ;
2098    }
2099
2100    #[test]
2101    fn ref_array_overflow() {
2102        let mut a = [0, 0, 2, 3, 10];
2103        let a_ref = VolatileSlice::from(&mut a[..]);
2104        let res = a_ref.get_array_ref::<u32>(4, usize::MAX).unwrap_err();
2105        assert_matches!(
2106            res,
2107            Error::TooBig {
2108                nelements: usize::MAX,
2109                size: 4,
2110            }
2111        );
2112    }
2113
2114    #[test]
2115    fn alignment() {
2116        let a = [0u8; 64];
2117        let a = &a[a.as_ptr().align_offset(32)] as *const u8 as usize;
2118        assert!(super::alignment(a) >= 32);
2119        assert_eq!(super::alignment(a + 9), 1);
2120        assert_eq!(super::alignment(a + 30), 2);
2121        assert_eq!(super::alignment(a + 12), 4);
2122        assert_eq!(super::alignment(a + 8), 8);
2123    }
2124
2125    #[test]
2126    fn test_atomic_accesses() {
2127        let len = 0x1000;
2128        let buf = unsafe { std::alloc::alloc_zeroed(Layout::from_size_align(len, 8).unwrap()) };
2129        let a = unsafe { VolatileSlice::new(buf, len) };
2130
2131        crate::bytes::tests::check_atomic_accesses(a, 0, 0x1000);
2132        unsafe {
2133            std::alloc::dealloc(buf, Layout::from_size_align(len, 8).unwrap());
2134        }
2135    }
2136
2137    #[test]
2138    fn split_at() {
2139        let mut mem = [0u8; 32];
2140        let mem_ref = VolatileSlice::from(&mut mem[..]);
2141        let vslice = mem_ref.get_slice(0, 32).unwrap();
2142        let (start, end) = vslice.split_at(8).unwrap();
2143        assert_eq!(start.len(), 8);
2144        assert_eq!(end.len(), 24);
2145        let (start, end) = vslice.split_at(0).unwrap();
2146        assert_eq!(start.len(), 0);
2147        assert_eq!(end.len(), 32);
2148        let (start, end) = vslice.split_at(31).unwrap();
2149        assert_eq!(start.len(), 31);
2150        assert_eq!(end.len(), 1);
2151        let (start, end) = vslice.split_at(32).unwrap();
2152        assert_eq!(start.len(), 32);
2153        assert_eq!(end.len(), 0);
2154        let err = vslice.split_at(33).unwrap_err();
2155        assert_matches!(err, Error::OutOfBounds { addr: _ })
2156    }
2157
2158    #[test]
2159    #[cfg(feature = "backend-bitmap")]
2160    fn test_volatile_slice_dirty_tracking() {
2161        let val = 123u64;
2162        let dirty_offset = 0x1000;
2163        let dirty_len = size_of_val(&val);
2164
2165        let len = 0x10000;
2166        let buf = unsafe { std::alloc::alloc_zeroed(Layout::from_size_align(len, 8).unwrap()) };
2167
2168        // Invoke the `Bytes` test helper function.
2169        {
2170            let bitmap = AtomicBitmap::new(len, DEFAULT_PAGE_SIZE);
2171            let slice = unsafe { VolatileSlice::with_bitmap(buf, len, bitmap.slice_at(0), None) };
2172
2173            test_bytes(
2174                &slice,
2175                |s: &VolatileSlice<RefSlice<AtomicBitmap>>,
2176                 start: usize,
2177                 len: usize,
2178                 clean: bool| { check_range(s.bitmap(), start, len, clean) },
2179                |offset| offset,
2180                0x1000,
2181            );
2182        }
2183
2184        // Invoke the `VolatileMemory` test helper function.
2185        {
2186            let bitmap = AtomicBitmap::new(len, DEFAULT_PAGE_SIZE);
2187            let slice = unsafe { VolatileSlice::with_bitmap(buf, len, bitmap.slice_at(0), None) };
2188            test_volatile_memory(&slice);
2189        }
2190
2191        let bitmap = AtomicBitmap::new(len, DEFAULT_PAGE_SIZE);
2192        let slice = unsafe { VolatileSlice::with_bitmap(buf, len, bitmap.slice_at(0), None) };
2193
2194        let bitmap2 = AtomicBitmap::new(len, DEFAULT_PAGE_SIZE);
2195        let slice2 = unsafe { VolatileSlice::with_bitmap(buf, len, bitmap2.slice_at(0), None) };
2196
2197        let bitmap3 = AtomicBitmap::new(len, DEFAULT_PAGE_SIZE);
2198        let slice3 = unsafe { VolatileSlice::with_bitmap(buf, len, bitmap3.slice_at(0), None) };
2199
2200        assert!(range_is_clean(slice.bitmap(), 0, slice.len()));
2201        assert!(range_is_clean(slice2.bitmap(), 0, slice2.len()));
2202
2203        slice.write_obj(val, dirty_offset).unwrap();
2204        assert!(range_is_dirty(slice.bitmap(), dirty_offset, dirty_len));
2205
2206        slice.copy_to_volatile_slice(slice2);
2207        assert!(range_is_dirty(slice2.bitmap(), 0, slice2.len()));
2208
2209        {
2210            let (s1, s2) = slice.split_at(dirty_offset).unwrap();
2211            assert!(range_is_clean(s1.bitmap(), 0, s1.len()));
2212            assert!(range_is_dirty(s2.bitmap(), 0, dirty_len));
2213        }
2214
2215        {
2216            let s = slice.subslice(dirty_offset, dirty_len).unwrap();
2217            assert!(range_is_dirty(s.bitmap(), 0, s.len()));
2218        }
2219
2220        {
2221            let s = slice.offset(dirty_offset).unwrap();
2222            assert!(range_is_dirty(s.bitmap(), 0, dirty_len));
2223        }
2224
2225        // Test `copy_from` for size_of::<T> == 1.
2226        {
2227            let buf = vec![1u8; dirty_offset];
2228
2229            assert!(range_is_clean(slice.bitmap(), 0, dirty_offset));
2230            slice.copy_from(&buf);
2231            assert!(range_is_dirty(slice.bitmap(), 0, dirty_offset));
2232        }
2233
2234        // Test `copy_from` for size_of::<T> > 1.
2235        {
2236            let val = 1u32;
2237            let buf = vec![val; dirty_offset / size_of_val(&val)];
2238
2239            assert!(range_is_clean(slice3.bitmap(), 0, dirty_offset));
2240            slice3.copy_from(&buf);
2241            assert!(range_is_dirty(slice3.bitmap(), 0, dirty_offset));
2242        }
2243
2244        unsafe {
2245            std::alloc::dealloc(buf, Layout::from_size_align(len, 8).unwrap());
2246        }
2247    }
2248
2249    #[test]
2250    #[cfg(feature = "backend-bitmap")]
2251    fn test_volatile_ref_dirty_tracking() {
2252        let val = 123u64;
2253        let mut buf = vec![val];
2254
2255        let bitmap = AtomicBitmap::new(size_of_val(&val), DEFAULT_PAGE_SIZE);
2256        let vref = unsafe {
2257            VolatileRef::with_bitmap(buf.as_mut_ptr() as *mut u8, bitmap.slice_at(0), None)
2258        };
2259
2260        assert!(range_is_clean(vref.bitmap(), 0, vref.len()));
2261        vref.store(val);
2262        assert!(range_is_dirty(vref.bitmap(), 0, vref.len()));
2263    }
2264
2265    #[cfg(feature = "backend-bitmap")]
2266    fn test_volatile_array_ref_copy_from_tracking<T>(
2267        buf: &mut [T],
2268        index: usize,
2269        page_size: NonZeroUsize,
2270    ) where
2271        T: ByteValued + From<u8>,
2272    {
2273        let bitmap = AtomicBitmap::new(size_of_val(buf), page_size);
2274        let arr = unsafe {
2275            VolatileArrayRef::with_bitmap(
2276                buf.as_mut_ptr() as *mut u8,
2277                index + 1,
2278                bitmap.slice_at(0),
2279                None,
2280            )
2281        };
2282
2283        let val = T::from(123);
2284        let copy_buf = vec![val; index + 1];
2285
2286        assert!(range_is_clean(arr.bitmap(), 0, arr.len() * size_of::<T>()));
2287        arr.copy_from(copy_buf.as_slice());
2288        assert!(range_is_dirty(arr.bitmap(), 0, size_of_val(buf)));
2289    }
2290
2291    #[test]
2292    #[cfg(feature = "backend-bitmap")]
2293    fn test_volatile_array_ref_dirty_tracking() {
2294        let val = 123u64;
2295        let dirty_len = size_of_val(&val);
2296        let index = 0x1000;
2297        let dirty_offset = dirty_len * index;
2298
2299        let mut buf = vec![0u64; index + 1];
2300        let mut byte_buf = vec![0u8; index + 1];
2301
2302        // Test `ref_at`.
2303        {
2304            let bitmap = AtomicBitmap::new(buf.len() * size_of_val(&val), DEFAULT_PAGE_SIZE);
2305            let arr = unsafe {
2306                VolatileArrayRef::with_bitmap(
2307                    buf.as_mut_ptr() as *mut u8,
2308                    index + 1,
2309                    bitmap.slice_at(0),
2310                    None,
2311                )
2312            };
2313
2314            assert!(range_is_clean(arr.bitmap(), 0, arr.len() * dirty_len));
2315            arr.ref_at(index).store(val);
2316            assert!(range_is_dirty(arr.bitmap(), dirty_offset, dirty_len));
2317        }
2318
2319        // Test `store`.
2320        {
2321            let bitmap = AtomicBitmap::new(buf.len() * size_of_val(&val), DEFAULT_PAGE_SIZE);
2322            let arr = unsafe {
2323                VolatileArrayRef::with_bitmap(
2324                    buf.as_mut_ptr() as *mut u8,
2325                    index + 1,
2326                    bitmap.slice_at(0),
2327                    None,
2328                )
2329            };
2330
2331            let slice = arr.to_slice();
2332            assert!(range_is_clean(slice.bitmap(), 0, slice.len()));
2333            arr.store(index, val);
2334            assert!(range_is_dirty(slice.bitmap(), dirty_offset, dirty_len));
2335        }
2336
2337        // Test `copy_from` when size_of::<T>() == 1.
2338        test_volatile_array_ref_copy_from_tracking(&mut byte_buf, index, DEFAULT_PAGE_SIZE);
2339        // Test `copy_from` when size_of::<T>() > 1.
2340        test_volatile_array_ref_copy_from_tracking(&mut buf, index, DEFAULT_PAGE_SIZE);
2341    }
2342}