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}