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}