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