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