Skip to main content

guestmem/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Interfaces to read and write guest memory.
5
6// UNSAFETY: This crate's whole purpose is manual memory mapping and management.
7#![expect(unsafe_code)]
8#![expect(missing_docs)]
9
10pub mod ranges;
11
12use self::ranges::PagedRange;
13use inspect::Inspect;
14use pal_event::Event;
15use sparse_mmap::AsMappableRef;
16use std::any::Any;
17use std::fmt::Debug;
18use std::future::Future;
19use std::io;
20use std::ops::Deref;
21use std::ops::DerefMut;
22use std::ops::Range;
23use std::ptr::NonNull;
24use std::sync::Arc;
25use std::sync::atomic::AtomicU8;
26use thiserror::Error;
27use zerocopy::FromBytes;
28use zerocopy::FromZeros;
29use zerocopy::Immutable;
30use zerocopy::IntoBytes;
31use zerocopy::KnownLayout;
32
33// Effective page size for page-related operations in this crate.
34pub const PAGE_SIZE: usize = 4096;
35const PAGE_SIZE64: u64 = 4096;
36
37/// A memory access error returned by one of the [`GuestMemory`] methods.
38#[derive(Debug, Error)]
39#[error(transparent)]
40pub struct GuestMemoryError(Box<GuestMemoryErrorInner>);
41
42impl GuestMemoryError {
43    fn new(
44        debug_name: &Arc<str>,
45        range: Option<Range<u64>>,
46        op: GuestMemoryOperation,
47        err: GuestMemoryBackingError,
48    ) -> Self {
49        GuestMemoryError(Box::new(GuestMemoryErrorInner {
50            op,
51            debug_name: debug_name.clone(),
52            range,
53            gpa: (err.gpa != INVALID_ERROR_GPA).then_some(err.gpa),
54            kind: err.kind,
55            err: err.err,
56        }))
57    }
58
59    /// Returns the kind of the error.
60    pub fn kind(&self) -> GuestMemoryErrorKind {
61        self.0.kind
62    }
63}
64
65#[derive(Debug, Copy, Clone)]
66enum GuestMemoryOperation {
67    Read,
68    Write,
69    Fill,
70    CompareExchange,
71    Lock,
72    Subrange,
73    Probe,
74}
75
76impl std::fmt::Display for GuestMemoryOperation {
77    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78        f.pad(match self {
79            GuestMemoryOperation::Read => "read",
80            GuestMemoryOperation::Write => "write",
81            GuestMemoryOperation::Fill => "fill",
82            GuestMemoryOperation::CompareExchange => "compare exchange",
83            GuestMemoryOperation::Lock => "lock",
84            GuestMemoryOperation::Subrange => "subrange",
85            GuestMemoryOperation::Probe => "probe",
86        })
87    }
88}
89
90#[derive(Debug, Error)]
91struct GuestMemoryErrorInner {
92    op: GuestMemoryOperation,
93    debug_name: Arc<str>,
94    range: Option<Range<u64>>,
95    gpa: Option<u64>,
96    kind: GuestMemoryErrorKind,
97    #[source]
98    err: Box<dyn std::error::Error + Send + Sync>,
99}
100
101impl std::fmt::Display for GuestMemoryErrorInner {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        write!(
104            f,
105            "guest memory '{debug_name}': {op} error: failed to access ",
106            debug_name = self.debug_name,
107            op = self.op
108        )?;
109        if let Some(range) = &self.range {
110            write!(f, "{:#x}-{:#x}", range.start, range.end)?;
111        } else {
112            f.write_str("memory")?;
113        }
114        // Include the precise GPA if provided and different from the start of
115        // the range.
116        if let Some(gpa) = self.gpa {
117            if self.range.as_ref().is_none_or(|range| range.start != gpa) {
118                write!(f, " at {:#x}", gpa)?;
119            }
120        }
121        Ok(())
122    }
123}
124
125/// A memory access error returned by a [`GuestMemoryAccess`] trait method.
126#[derive(Debug)]
127pub struct GuestMemoryBackingError {
128    gpa: u64,
129    kind: GuestMemoryErrorKind,
130    err: Box<dyn std::error::Error + Send + Sync>,
131}
132
133/// The kind of memory access error.
134#[derive(Debug, Copy, Clone, PartialEq, Eq)]
135#[non_exhaustive]
136pub enum GuestMemoryErrorKind {
137    /// An error that does not fit any other category.
138    Other,
139    /// The address is outside the valid range of the memory.
140    OutOfRange,
141    /// The memory has been protected by a higher virtual trust level.
142    VtlProtected,
143    /// The memory is shared but was accessed via a private address.
144    NotPrivate,
145    /// The memory is private but was accessed via a shared address.
146    NotShared,
147}
148
149/// An error returned by a page fault handler in [`GuestMemoryAccess::page_fault`].
150pub struct PageFaultError {
151    kind: GuestMemoryErrorKind,
152    err: Box<dyn std::error::Error + Send + Sync>,
153}
154
155impl PageFaultError {
156    /// Returns a new page fault error.
157    pub fn new(
158        kind: GuestMemoryErrorKind,
159        err: impl Into<Box<dyn std::error::Error + Send + Sync>>,
160    ) -> Self {
161        Self {
162            kind,
163            err: err.into(),
164        }
165    }
166
167    /// Returns a page fault error without an explicit kind.
168    pub fn other(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
169        Self::new(GuestMemoryErrorKind::Other, err)
170    }
171}
172
173/// Used to avoid needing an `Option` for [`GuestMemoryBackingError::gpa`], to
174/// save size in hot paths.
175const INVALID_ERROR_GPA: u64 = !0;
176
177impl GuestMemoryBackingError {
178    /// Returns a new error for a memory access failure at address `gpa`.
179    pub fn new(
180        kind: GuestMemoryErrorKind,
181        gpa: u64,
182        err: impl Into<Box<dyn std::error::Error + Send + Sync>>,
183    ) -> Self {
184        // `gpa` might incorrectly be INVALID_ERROR_GPA; this is harmless (just
185        // affecting the error message), so don't assert on it in case this is
186        // an untrusted value in some path.
187        Self {
188            kind,
189            gpa,
190            err: err.into(),
191        }
192    }
193
194    /// Returns a new error without an explicit kind.
195    pub fn other(gpa: u64, err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
196        Self::new(GuestMemoryErrorKind::Other, gpa, err)
197    }
198
199    fn gpn(err: InvalidGpn) -> Self {
200        Self {
201            kind: GuestMemoryErrorKind::OutOfRange,
202            gpa: INVALID_ERROR_GPA,
203            err: err.into(),
204        }
205    }
206}
207
208#[derive(Debug, Error)]
209#[error("no memory at address")]
210struct OutOfRange;
211
212#[derive(Debug, Error)]
213#[error("memory not lockable")]
214struct NotLockable;
215
216#[derive(Debug, Error)]
217#[error("no fallback for this operation")]
218struct NoFallback;
219
220#[derive(Debug, Error)]
221#[error("the specified page is not mapped")]
222struct NotMapped;
223
224#[derive(Debug, Error)]
225#[error("page inaccessible in bitmap")]
226struct BitmapFailure;
227
228/// A trait for a guest memory backing that is fully available via a virtual
229/// address mapping, as opposed to the fallback functions such as
230/// [`GuestMemoryAccess::read_fallback`].
231///
232/// By implementing this trait, a type guarantees that its
233/// [`GuestMemoryAccess::mapping`] will return `Some(_)` and that all of its
234/// memory can be accessed through that mapping, without needing to call the
235/// fallback functions.
236pub trait LinearGuestMemory: GuestMemoryAccess {}
237
238// SAFETY: the allocation will stay valid for the lifetime of the object.
239unsafe impl GuestMemoryAccess for sparse_mmap::alloc::SharedMem {
240    fn mapping(&self) -> Option<NonNull<u8>> {
241        NonNull::new(self.as_ptr().cast_mut().cast())
242    }
243
244    fn max_address(&self) -> u64 {
245        self.len() as u64
246    }
247}
248
249impl LinearGuestMemory for sparse_mmap::alloc::SharedMem {}
250
251/// A page-aligned heap allocation for use with [`GuestMemory`].
252pub struct AlignedHeapMemory {
253    pages: Box<[AlignedPage]>,
254}
255
256impl Debug for AlignedHeapMemory {
257    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258        f.debug_struct("AlignedHeapMemory")
259            .field("len", &self.len())
260            .finish()
261    }
262}
263
264#[repr(C, align(4096))]
265struct AlignedPage([AtomicU8; PAGE_SIZE]);
266
267impl AlignedHeapMemory {
268    /// Allocates a new memory of `size` bytes, rounded up to a page size.
269    pub fn new(size: usize) -> Self {
270        #[expect(clippy::declare_interior_mutable_const)] // <https://github.com/rust-lang/rust-clippy/issues/7665>
271        const ZERO: AtomicU8 = AtomicU8::new(0);
272        #[expect(clippy::declare_interior_mutable_const)]
273        const ZERO_PAGE: AlignedPage = AlignedPage([ZERO; PAGE_SIZE]);
274        let mut pages = Vec::new();
275        pages.resize_with(size.div_ceil(PAGE_SIZE), || ZERO_PAGE);
276        Self {
277            pages: pages.into(),
278        }
279    }
280
281    /// Returns the length of the memory in bytes.
282    pub fn len(&self) -> usize {
283        self.pages.len() * PAGE_SIZE
284    }
285
286    /// Returns an immutable slice of bytes.
287    ///
288    /// This must take `&mut self` since the buffer is mutable via interior
289    /// mutability with just `&self`.
290    pub fn as_bytes(&mut self) -> &[u8] {
291        self.as_mut()
292    }
293
294    /// Returns a mutable slice of bytes.
295    pub fn as_mut_bytes(&mut self) -> &mut [u8] {
296        self.as_mut()
297    }
298}
299
300impl Deref for AlignedHeapMemory {
301    type Target = [AtomicU8];
302
303    fn deref(&self) -> &Self::Target {
304        // SAFETY: the buffer has the correct size and validity.
305        unsafe { std::slice::from_raw_parts(self.pages.as_ptr().cast(), self.len()) }
306    }
307}
308
309impl DerefMut for AlignedHeapMemory {
310    fn deref_mut(&mut self) -> &mut Self::Target {
311        // SAFETY: the buffer is unaliased and valid.
312        unsafe { std::slice::from_raw_parts_mut(self.pages.as_mut_ptr().cast(), self.len()) }
313    }
314}
315
316impl AsRef<[AtomicU8]> for AlignedHeapMemory {
317    fn as_ref(&self) -> &[AtomicU8] {
318        self
319    }
320}
321
322impl AsMut<[AtomicU8]> for AlignedHeapMemory {
323    fn as_mut(&mut self) -> &mut [AtomicU8] {
324        self
325    }
326}
327
328impl AsMut<[u8]> for AlignedHeapMemory {
329    fn as_mut(&mut self) -> &mut [u8] {
330        // FUTURE: use AtomicU8::get_mut_slice once stabilized.
331        // SAFETY: the buffer is unaliased, so it is fine to cast away the atomicness of the
332        // slice.
333        unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) }
334    }
335}
336
337// SAFETY: the allocation remains alive and valid for the lifetime of the
338// object.
339unsafe impl GuestMemoryAccess for AlignedHeapMemory {
340    fn mapping(&self) -> Option<NonNull<u8>> {
341        NonNull::new(self.pages.as_ptr().cast_mut().cast())
342    }
343
344    fn max_address(&self) -> u64 {
345        (self.pages.len() * PAGE_SIZE) as u64
346    }
347}
348
349impl LinearGuestMemory for AlignedHeapMemory {}
350
351/// A shareable region of guest memory backed by a file (Unix) or
352/// section handle (Windows).
353///
354/// The backing file must already contain committed data for the region —
355/// the consumer will map it directly, without any guestmem-managed lazy
356/// commitment or fault handling. All bytes in the range must be accessible
357/// without triggering SIGSEGV or SIGBUS due to missing backing. Normal OS
358/// demand paging and minor faults on first access are still expected; this
359/// requirement is specifically incompatible with bitmap-gated access or
360/// lazy fault-in schemes.
361pub struct ShareableRegion {
362    /// Guest physical address of this region.
363    pub guest_address: u64,
364    /// Size in bytes.
365    pub size: u64,
366    /// Backing file/handle, shared via `Arc` to avoid OS-level `dup()`.
367    pub file: Arc<sparse_mmap::Mappable>,
368    /// Offset into `file` where this region starts.
369    pub file_offset: u64,
370}
371
372/// Error type for [`ProvideShareableRegions::get_regions`].
373pub type ShareableRegionError = Box<dyn std::error::Error + Send + Sync>;
374
375/// Opaque control object for accessing the shareable backing of guest
376/// memory. Not all `GuestMemory` instances support this — those backed
377/// by private memory or heap allocations return `None`.
378///
379/// # Contract
380///
381/// * The regions returned by [`get_regions`](Self::get_regions) must have
382///   fully committed backing — the consumer will map them directly,
383///   without guestmem-managed fault handling.
384/// * The set of regions is currently static for the lifetime of the VM.
385///   Hotplug and hot-remove of shareable regions are not yet supported;
386///   once they are, additional methods will be added here to notify
387///   consumers of changes.
388pub struct GuestMemorySharing {
389    inner: Box<dyn DynProvideShareableRegions>,
390}
391
392impl GuestMemorySharing {
393    /// Construct from a trait implementation. Called by `GuestMemoryAccess`
394    /// implementations (e.g., `VaMapper` in membacking).
395    pub fn new(inner: impl ProvideShareableRegions + 'static) -> Self {
396        Self {
397            inner: Box::new(inner),
398        }
399    }
400
401    /// Return the current set of shareable backing regions.
402    pub async fn get_regions(&self) -> Result<Vec<ShareableRegion>, ShareableRegionError> {
403        self.inner.get_regions().await
404    }
405}
406
407/// Trait for providing shareable region information.
408///
409/// Implementors must return regions whose backing files have fully
410/// committed data — consumers will map them directly without
411/// guestmem-managed fault handling. The region set is currently static;
412/// dynamic updates (hotplug / hot-remove) are not yet supported.
413///
414/// This trait must be public so that crates like `membacking` can
415/// implement it, but callers should interact with
416/// [`GuestMemorySharing`]'s methods rather than this trait directly.
417pub trait ProvideShareableRegions: Send + Sync {
418    /// Return the current set of shareable backing regions.
419    fn get_regions(
420        &self,
421    ) -> impl Future<Output = Result<Vec<ShareableRegion>, ShareableRegionError>> + Send + '_;
422}
423
424/// Dyn-compatible version of [`ProvideShareableRegions`].
425trait DynProvideShareableRegions: Send + Sync {
426    fn get_regions(
427        &self,
428    ) -> std::pin::Pin<
429        Box<dyn Future<Output = Result<Vec<ShareableRegion>, ShareableRegionError>> + Send + '_>,
430    >;
431}
432
433impl<T: ProvideShareableRegions> DynProvideShareableRegions for T {
434    fn get_regions(
435        &self,
436    ) -> std::pin::Pin<
437        Box<dyn Future<Output = Result<Vec<ShareableRegion>, ShareableRegionError>> + Send + '_>,
438    > {
439        Box::pin(ProvideShareableRegions::get_regions(self))
440    }
441}
442
443/// A trait for a guest memory backing.
444///
445/// Guest memory may be backed by a virtual memory mapping, in which case this
446/// trait can provide the VA and length of that mapping. Alternatively, it may
447/// be backed by some other means, in which case this trait can provide fallback
448/// methods for reading and writing memory.
449///
450/// Memory access should first be attempted via the virtual address mapping. If
451/// this fails or is not present, the caller should fall back to `read_fallback`
452/// or `write_fallback`. This allows an implementation to have a fast path using
453/// the mapping, and a slow path using the fallback functions.
454///
455/// # Safety
456///
457/// The implementor must follow the contract for each method.
458pub unsafe trait GuestMemoryAccess: 'static + Send + Sync {
459    /// Returns a stable VA mapping for guest memory.
460    ///
461    /// The size of the mapping is the same as `max_address`.
462    ///
463    /// The VA is guaranteed to remain reserved, but individual ranges may be
464    /// uncommitted.
465    fn mapping(&self) -> Option<NonNull<u8>>;
466
467    /// The maximum address that can be passed to the `*_fallback` methods, as
468    /// well as the maximum offset into the VA range described by `mapping`.
469    fn max_address(&self) -> u64;
470
471    /// The bitmaps to check for validity, one bit per page. If a bit is set,
472    /// then the page is valid to access via the mapping; if it is clear, then
473    /// the page will not be accessed.
474    ///
475    /// The bitmaps must be at least `ceil(bitmap_start + max_address() /
476    /// PAGE_SIZE)` bits long, and they must be valid for atomic read access for
477    /// the lifetime of this object from any thread.
478    ///
479    /// The bitmaps are only checked if there is a mapping. If the bitmap check
480    /// fails, then the associated `*_fallback` routine is called to handle the
481    /// error.
482    ///
483    /// Bitmap checks are performed under the [`rcu()`] RCU domain, with relaxed
484    /// accesses. After a thread updates the bitmap to be more restrictive, it
485    /// must call [minircu::RcuDomain::synchronize()] on [`minircu::global()`]
486    /// to ensure that all threads see the update before taking any action that
487    /// depends on the bitmap update being visible.
488    #[cfg(feature = "bitmap")]
489    fn access_bitmap(&self) -> Option<BitmapInfo> {
490        None
491    }
492
493    // Returns an accessor for a subrange, or `None` to use the default
494    // implementation.
495    fn subrange(
496        &self,
497        offset: u64,
498        len: u64,
499        allow_preemptive_locking: bool,
500    ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
501        let _ = (offset, len, allow_preemptive_locking);
502        Ok(None)
503    }
504
505    /// Called when access to memory via the mapped range fails, either due to a
506    /// bitmap failure or due to a failure when accessing the virtual address.
507    ///
508    /// `address` is the address where the access failed. `len` is the remainder
509    /// of the access; it is not necessarily the case that all `len` bytes are
510    /// inaccessible in the bitmap or mapping.
511    ///
512    /// Returns whether the faulting operation should be retried, failed, or that
513    /// one of the fallback operations (e.g. `read_fallback`) should be called.
514    fn page_fault(
515        &self,
516        address: u64,
517        len: usize,
518        write: bool,
519        bitmap_failure: bool,
520    ) -> PageFaultAction {
521        let _ = (address, len, write);
522        let err = if bitmap_failure {
523            PageFaultError::other(BitmapFailure)
524        } else {
525            PageFaultError::other(NotMapped)
526        };
527        PageFaultAction::Fail(err)
528    }
529
530    /// Fallback called if a read fails via direct access to `mapped_range`.
531    ///
532    /// This is only called if `mapping()` returns `None` or if `page_fault()`
533    /// returns `PageFaultAction::Fallback`.
534    ///
535    /// Implementors must ensure that `dest[..len]` is fully initialized on
536    /// successful return.
537    ///
538    /// # Safety
539    /// The caller must ensure that `dest[..len]` is valid for write. Note,
540    /// however, that `dest` might be aliased by other threads, the guest, or
541    /// the kernel.
542    unsafe fn read_fallback(
543        &self,
544        addr: u64,
545        dest: *mut u8,
546        len: usize,
547    ) -> Result<(), GuestMemoryBackingError> {
548        let _ = (dest, len);
549        Err(GuestMemoryBackingError::other(addr, NoFallback))
550    }
551
552    /// Fallback called if a write fails via direct access to `mapped_range`.
553    ///
554    /// This is only called if `mapping()` returns `None` or if `page_fault()`
555    /// returns `PageFaultAction::Fallback`.
556    ///
557    /// # Safety
558    /// The caller must ensure that `src[..len]` is valid for read. Note,
559    /// however, that `src` might be aliased by other threads, the guest, or
560    /// the kernel.
561    unsafe fn write_fallback(
562        &self,
563        addr: u64,
564        src: *const u8,
565        len: usize,
566    ) -> Result<(), GuestMemoryBackingError> {
567        let _ = (src, len);
568        Err(GuestMemoryBackingError::other(addr, NoFallback))
569    }
570
571    /// Fallback called if a fill fails via direct access to `mapped_range`.
572    ///
573    /// This is only called if `mapping()` returns `None` or if `page_fault()`
574    /// returns `PageFaultAction::Fallback`.
575    fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
576        let _ = (val, len);
577        Err(GuestMemoryBackingError::other(addr, NoFallback))
578    }
579
580    /// Fallback called if a compare exchange fails via direct access to `mapped_range`.
581    ///
582    /// On compare failure, returns `Ok(false)` and updates `current`.
583    ///
584    /// This is only called if `mapping()` returns `None` or if `page_fault()`
585    /// returns `PageFaultAction::Fallback`.
586    fn compare_exchange_fallback(
587        &self,
588        addr: u64,
589        current: &mut [u8],
590        new: &[u8],
591    ) -> Result<bool, GuestMemoryBackingError> {
592        let _ = (current, new);
593        Err(GuestMemoryBackingError::other(addr, NoFallback))
594    }
595
596    /// Prepares a guest page for having its virtual address exposed as part of
597    /// a lock call.
598    ///
599    /// This is useful to ensure that the address is mapped in a way that it can
600    /// be passed to the kernel for DMA.
601    fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
602        let _ = (address, len);
603        Ok(())
604    }
605
606    /// Returns the base IO virtual address for the mapping.
607    ///
608    /// This is the base address that should be used for DMA from a user-mode
609    /// device driver whose device is not otherwise configured to go through an
610    /// IOMMU.
611    fn base_iova(&self) -> Option<u64> {
612        None
613    }
614
615    /// Locks the specified guest physical pages (GPNs), preventing any mapping
616    /// or permission changes until they are unlocked.
617    ///
618    /// Returns a boolean indicating whether unlocking is required.
619    fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError> {
620        let _ = gpns;
621        Ok(false)
622    }
623
624    /// Unlocks the specified guest physical pages (GPNs) after exclusive access.
625    ///
626    /// Panics if asked to unlock a page that was not previously locked. The
627    /// caller must ensure that the given slice has the same ordering as the
628    /// one passed to `lock_gpns`.
629    fn unlock_gpns(&self, gpns: &[u64]) {
630        let _ = gpns;
631    }
632
633    /// Return a sharing control object if this memory backing supports
634    /// file-based sharing (e.g., memfd on Linux, section on Windows).
635    ///
636    /// Returns `None` for private memory, heap-backed test memory, or
637    /// other non-shareable backings.
638    fn sharing(&self) -> Option<GuestMemorySharing> {
639        None
640    }
641
642    /// Returns whether this backing supports locking pages via
643    /// [`lock_gpns`](Self::lock_gpns).
644    ///
645    /// Locking requires a stable host mapping (see
646    /// [`mapping`](Self::mapping)), so the default returns whether a mapping
647    /// is present. Backings that translate each access on demand (e.g., memory
648    /// behind an emulated IOMMU) have no mapping and thus report `false`.
649    /// Callers that use locking as a zero-copy fast path should check this and
650    /// fall back to a copying path when it returns `false`.
651    ///
652    /// This is authoritative: when it returns `false`, the corresponding
653    /// [`GuestMemory`] locking APIs fail without invoking
654    /// [`lock_gpns`](Self::lock_gpns).
655    fn supports_locking(&self) -> bool {
656        self.mapping().is_some()
657    }
658}
659
660trait DynGuestMemoryAccess: 'static + Send + Sync + Any {
661    fn subrange(
662        &self,
663        offset: u64,
664        len: u64,
665        allow_preemptive_locking: bool,
666    ) -> Result<Option<GuestMemory>, GuestMemoryBackingError>;
667
668    fn page_fault(
669        &self,
670        address: u64,
671        len: usize,
672        write: bool,
673        bitmap_failure: bool,
674    ) -> PageFaultAction;
675
676    /// # Safety
677    /// See [`GuestMemoryAccess::read_fallback`].
678    unsafe fn read_fallback(
679        &self,
680        addr: u64,
681        dest: *mut u8,
682        len: usize,
683    ) -> Result<(), GuestMemoryBackingError>;
684
685    /// # Safety
686    /// See [`GuestMemoryAccess::write_fallback`].
687    unsafe fn write_fallback(
688        &self,
689        addr: u64,
690        src: *const u8,
691        len: usize,
692    ) -> Result<(), GuestMemoryBackingError>;
693
694    fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError>;
695
696    fn compare_exchange_fallback(
697        &self,
698        addr: u64,
699        current: &mut [u8],
700        new: &[u8],
701    ) -> Result<bool, GuestMemoryBackingError>;
702
703    fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError>;
704
705    fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError>;
706
707    fn unlock_gpns(&self, gpns: &[u64]);
708
709    fn sharing(&self) -> Option<GuestMemorySharing>;
710}
711
712impl<T: GuestMemoryAccess> DynGuestMemoryAccess for T {
713    fn subrange(
714        &self,
715        offset: u64,
716        len: u64,
717        allow_preemptive_locking: bool,
718    ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
719        self.subrange(offset, len, allow_preemptive_locking)
720    }
721
722    fn page_fault(
723        &self,
724        address: u64,
725        len: usize,
726        write: bool,
727        bitmap_failure: bool,
728    ) -> PageFaultAction {
729        self.page_fault(address, len, write, bitmap_failure)
730    }
731
732    unsafe fn read_fallback(
733        &self,
734        addr: u64,
735        dest: *mut u8,
736        len: usize,
737    ) -> Result<(), GuestMemoryBackingError> {
738        // SAFETY: guaranteed by caller.
739        unsafe { self.read_fallback(addr, dest, len) }
740    }
741
742    unsafe fn write_fallback(
743        &self,
744        addr: u64,
745        src: *const u8,
746        len: usize,
747    ) -> Result<(), GuestMemoryBackingError> {
748        // SAFETY: guaranteed by caller.
749        unsafe { self.write_fallback(addr, src, len) }
750    }
751
752    fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
753        self.fill_fallback(addr, val, len)
754    }
755
756    fn compare_exchange_fallback(
757        &self,
758        addr: u64,
759        current: &mut [u8],
760        new: &[u8],
761    ) -> Result<bool, GuestMemoryBackingError> {
762        self.compare_exchange_fallback(addr, current, new)
763    }
764
765    fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
766        self.expose_va(address, len)
767    }
768
769    fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError> {
770        self.lock_gpns(gpns)
771    }
772
773    fn unlock_gpns(&self, gpns: &[u64]) {
774        self.unlock_gpns(gpns)
775    }
776
777    fn sharing(&self) -> Option<GuestMemorySharing> {
778        self.sharing()
779    }
780}
781
782/// The action to take after [`GuestMemoryAccess::page_fault`] returns to
783/// continue the operation.
784pub enum PageFaultAction {
785    /// Fail the operation.
786    Fail(PageFaultError),
787    /// Retry the operation.
788    Retry,
789    /// Use the fallback method to access the memory.
790    Fallback,
791}
792
793/// Returned by [`GuestMemoryAccess::access_bitmap`].
794#[cfg(feature = "bitmap")]
795pub struct BitmapInfo {
796    /// A pointer to the bitmap for read access.
797    pub read_bitmap: NonNull<u8>,
798    /// A pointer to the bitmap for write access.
799    pub write_bitmap: NonNull<u8>,
800    /// The bit offset of the beginning of the bitmap.
801    ///
802    /// Typically this is zero, but it is needed to support subranges that are
803    /// not 8-page multiples.
804    pub bit_offset: u8,
805}
806
807// SAFETY: passing through guarantees from `T`.
808unsafe impl<T: GuestMemoryAccess> GuestMemoryAccess for Arc<T> {
809    fn mapping(&self) -> Option<NonNull<u8>> {
810        self.as_ref().mapping()
811    }
812
813    fn max_address(&self) -> u64 {
814        self.as_ref().max_address()
815    }
816
817    #[cfg(feature = "bitmap")]
818    fn access_bitmap(&self) -> Option<BitmapInfo> {
819        self.as_ref().access_bitmap()
820    }
821
822    fn subrange(
823        &self,
824        offset: u64,
825        len: u64,
826        allow_preemptive_locking: bool,
827    ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
828        self.as_ref()
829            .subrange(offset, len, allow_preemptive_locking)
830    }
831
832    fn page_fault(
833        &self,
834        addr: u64,
835        len: usize,
836        write: bool,
837        bitmap_failure: bool,
838    ) -> PageFaultAction {
839        self.as_ref().page_fault(addr, len, write, bitmap_failure)
840    }
841
842    unsafe fn read_fallback(
843        &self,
844        addr: u64,
845        dest: *mut u8,
846        len: usize,
847    ) -> Result<(), GuestMemoryBackingError> {
848        // SAFETY: passing through guarantees from caller.
849        unsafe { self.as_ref().read_fallback(addr, dest, len) }
850    }
851
852    unsafe fn write_fallback(
853        &self,
854        addr: u64,
855        src: *const u8,
856        len: usize,
857    ) -> Result<(), GuestMemoryBackingError> {
858        // SAFETY: passing through guarantees from caller.
859        unsafe { self.as_ref().write_fallback(addr, src, len) }
860    }
861
862    fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
863        self.as_ref().fill_fallback(addr, val, len)
864    }
865
866    fn compare_exchange_fallback(
867        &self,
868        addr: u64,
869        current: &mut [u8],
870        new: &[u8],
871    ) -> Result<bool, GuestMemoryBackingError> {
872        self.as_ref().compare_exchange_fallback(addr, current, new)
873    }
874
875    fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
876        self.as_ref().expose_va(address, len)
877    }
878
879    fn base_iova(&self) -> Option<u64> {
880        self.as_ref().base_iova()
881    }
882
883    fn sharing(&self) -> Option<GuestMemorySharing> {
884        self.as_ref().sharing()
885    }
886}
887
888// SAFETY: the allocation will stay valid for the lifetime of the object.
889unsafe impl GuestMemoryAccess for sparse_mmap::SparseMapping {
890    fn mapping(&self) -> Option<NonNull<u8>> {
891        NonNull::new(self.as_ptr().cast())
892    }
893
894    fn max_address(&self) -> u64 {
895        self.len() as u64
896    }
897}
898
899/// Default guest memory range type, enforcing access boundaries.
900struct GuestMemoryAccessRange {
901    base: Arc<GuestMemoryInner>,
902    offset: u64,
903    len: u64,
904    region: usize,
905}
906
907impl GuestMemoryAccessRange {
908    fn adjust_range(&self, address: u64, len: u64) -> Result<u64, GuestMemoryBackingError> {
909        if address <= self.len && len <= self.len - address {
910            Ok(self.offset + address)
911        } else {
912            Err(GuestMemoryBackingError::new(
913                GuestMemoryErrorKind::OutOfRange,
914                address,
915                OutOfRange,
916            ))
917        }
918    }
919}
920
921// SAFETY: `mapping()` is guaranteed to be valid for the lifetime of the object.
922unsafe impl GuestMemoryAccess for GuestMemoryAccessRange {
923    fn mapping(&self) -> Option<NonNull<u8>> {
924        let region = &self.base.regions[self.region];
925        region.mapping.and_then(|mapping| {
926            let offset = self.offset & self.base.region_def.region_mask;
927            // This is guaranteed by construction.
928            assert!(region.len >= offset + self.len);
929            // SAFETY: this mapping is guaranteed to be within range by
930            // construction (and validated again via the assertion above).
931            NonNull::new(unsafe { mapping.0.as_ptr().add(offset as usize) })
932        })
933    }
934
935    fn max_address(&self) -> u64 {
936        self.len
937    }
938
939    #[cfg(feature = "bitmap")]
940    fn access_bitmap(&self) -> Option<BitmapInfo> {
941        let region = &self.base.regions[self.region];
942        region.bitmaps.map(|bitmaps| {
943            let offset = self.offset & self.base.region_def.region_mask;
944            let bit_offset = region.bitmap_start as u64 + offset / PAGE_SIZE64;
945            let [read_bitmap, write_bitmap] = bitmaps.map(|SendPtrU8(ptr)| {
946                // SAFETY: the bitmap is guaranteed to be big enough for the region
947                // by construction.
948                NonNull::new(unsafe { ptr.as_ptr().add((bit_offset / 8) as usize) }).unwrap()
949            });
950            let bitmap_start = (bit_offset % 8) as u8;
951            BitmapInfo {
952                read_bitmap,
953                write_bitmap,
954                bit_offset: bitmap_start,
955            }
956        })
957    }
958
959    fn subrange(
960        &self,
961        offset: u64,
962        len: u64,
963        _allow_preemptive_locking: bool,
964    ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
965        let address = self.adjust_range(offset, len)?;
966        Ok(Some(GuestMemory::new(
967            self.base.debug_name.clone(),
968            GuestMemoryAccessRange {
969                base: self.base.clone(),
970                offset: address,
971                len,
972                region: self.region,
973            },
974        )))
975    }
976
977    fn page_fault(
978        &self,
979        address: u64,
980        len: usize,
981        write: bool,
982        bitmap_failure: bool,
983    ) -> PageFaultAction {
984        let address = self
985            .adjust_range(address, len as u64)
986            .expect("the caller should have validated the range was in the mapping");
987
988        self.base
989            .imp
990            .page_fault(address, len, write, bitmap_failure)
991    }
992
993    unsafe fn write_fallback(
994        &self,
995        address: u64,
996        src: *const u8,
997        len: usize,
998    ) -> Result<(), GuestMemoryBackingError> {
999        let address = self.adjust_range(address, len as u64)?;
1000        // SAFETY: guaranteed by caller.
1001        unsafe { self.base.imp.write_fallback(address, src, len) }
1002    }
1003
1004    fn fill_fallback(
1005        &self,
1006        address: u64,
1007        val: u8,
1008        len: usize,
1009    ) -> Result<(), GuestMemoryBackingError> {
1010        let address = self.adjust_range(address, len as u64)?;
1011        self.base.imp.fill_fallback(address, val, len)
1012    }
1013
1014    fn compare_exchange_fallback(
1015        &self,
1016        addr: u64,
1017        current: &mut [u8],
1018        new: &[u8],
1019    ) -> Result<bool, GuestMemoryBackingError> {
1020        let address = self.adjust_range(addr, new.len() as u64)?;
1021        self.base
1022            .imp
1023            .compare_exchange_fallback(address, current, new)
1024    }
1025
1026    unsafe fn read_fallback(
1027        &self,
1028        address: u64,
1029        dest: *mut u8,
1030        len: usize,
1031    ) -> Result<(), GuestMemoryBackingError> {
1032        let address = self.adjust_range(address, len as u64)?;
1033        // SAFETY: guaranteed by caller.
1034        unsafe { self.base.imp.read_fallback(address, dest, len) }
1035    }
1036
1037    fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
1038        let address = self.adjust_range(address, len)?;
1039        self.base.imp.expose_va(address, len)
1040    }
1041
1042    fn base_iova(&self) -> Option<u64> {
1043        let region = &self.base.regions[self.region];
1044        Some(region.base_iova? + (self.offset & self.base.region_def.region_mask))
1045    }
1046}
1047
1048/// Create a default guest memory subrange that verifies range limits and calls
1049/// back into the base implementation.
1050fn create_memory_subrange(
1051    base: Arc<GuestMemoryInner>,
1052    offset: u64,
1053    len: u64,
1054    _allow_preemptive_locking: bool,
1055) -> Result<GuestMemory, GuestMemoryBackingError> {
1056    let (_, _, region) = base.region(offset, len)?;
1057    Ok(GuestMemory::new(
1058        base.debug_name.clone(),
1059        GuestMemoryAccessRange {
1060            base,
1061            offset,
1062            len,
1063            region,
1064        },
1065    ))
1066}
1067
1068struct MultiRegionGuestMemoryAccess<T> {
1069    imps: Vec<Option<T>>,
1070    region_def: RegionDefinition,
1071}
1072
1073impl<T> MultiRegionGuestMemoryAccess<T> {
1074    fn region(&self, gpa: u64, len: u64) -> Result<(&T, u64), GuestMemoryBackingError> {
1075        let (i, offset) = self.region_def.region(gpa, len)?;
1076        let imp = self.imps[i].as_ref().ok_or(GuestMemoryBackingError::new(
1077            GuestMemoryErrorKind::OutOfRange,
1078            gpa,
1079            OutOfRange,
1080        ))?;
1081        Ok((imp, offset))
1082    }
1083}
1084
1085// SAFETY: `mapping()` is unreachable and panics if called.
1086impl<T: GuestMemoryAccess> DynGuestMemoryAccess for MultiRegionGuestMemoryAccess<T> {
1087    fn subrange(
1088        &self,
1089        offset: u64,
1090        len: u64,
1091        allow_preemptive_locking: bool,
1092    ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
1093        let (region, offset_in_region) = self.region(offset, len)?;
1094        region.subrange(offset_in_region, len, allow_preemptive_locking)
1095    }
1096
1097    unsafe fn read_fallback(
1098        &self,
1099        addr: u64,
1100        dest: *mut u8,
1101        len: usize,
1102    ) -> Result<(), GuestMemoryBackingError> {
1103        let (region, offset_in_region) = self.region(addr, len as u64)?;
1104        // SAFETY: guaranteed by caller.
1105        unsafe { region.read_fallback(offset_in_region, dest, len) }
1106    }
1107
1108    unsafe fn write_fallback(
1109        &self,
1110        addr: u64,
1111        src: *const u8,
1112        len: usize,
1113    ) -> Result<(), GuestMemoryBackingError> {
1114        let (region, offset_in_region) = self.region(addr, len as u64)?;
1115        // SAFETY: guaranteed by caller.
1116        unsafe { region.write_fallback(offset_in_region, src, len) }
1117    }
1118
1119    fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
1120        let (region, offset_in_region) = self.region(addr, len as u64)?;
1121        region.fill_fallback(offset_in_region, val, len)
1122    }
1123
1124    fn compare_exchange_fallback(
1125        &self,
1126        addr: u64,
1127        current: &mut [u8],
1128        new: &[u8],
1129    ) -> Result<bool, GuestMemoryBackingError> {
1130        let (region, offset_in_region) = self.region(addr, new.len() as u64)?;
1131        region.compare_exchange_fallback(offset_in_region, current, new)
1132    }
1133
1134    fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
1135        let (region, offset_in_region) = self.region(address, len)?;
1136        region.expose_va(offset_in_region, len)
1137    }
1138
1139    fn page_fault(
1140        &self,
1141        address: u64,
1142        len: usize,
1143        write: bool,
1144        bitmap_failure: bool,
1145    ) -> PageFaultAction {
1146        match self.region(address, len as u64) {
1147            Ok((region, offset_in_region)) => {
1148                region.page_fault(offset_in_region, len, write, bitmap_failure)
1149            }
1150            Err(err) => PageFaultAction::Fail(PageFaultError {
1151                kind: err.kind,
1152                err: err.err,
1153            }),
1154        }
1155    }
1156
1157    fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError> {
1158        let mut ret = false;
1159        for gpn in gpns {
1160            let (region, offset_in_region) = self.region(gpn * PAGE_SIZE64, PAGE_SIZE64)?;
1161            ret |= region.lock_gpns(&[offset_in_region / PAGE_SIZE64])?;
1162        }
1163        Ok(ret)
1164    }
1165
1166    fn unlock_gpns(&self, gpns: &[u64]) {
1167        for gpn in gpns {
1168            let (region, offset_in_region) = self.region(gpn * PAGE_SIZE64, PAGE_SIZE64).unwrap();
1169            region.unlock_gpns(&[offset_in_region / PAGE_SIZE64]);
1170        }
1171    }
1172
1173    fn sharing(&self) -> Option<GuestMemorySharing> {
1174        // FUTURE: multi-region setups could aggregate shareable regions from
1175        // their sub-regions. For now, sharing is only supported for
1176        // single-region guest memory (the common case). If a VM uses
1177        // MultiRegionGuestMemoryAccess with vhost-user, this will return
1178        // None and the vhost-user backend will fail to initialize.
1179        None
1180    }
1181}
1182
1183/// A wrapper around a `GuestMemoryAccess` that provides methods for safely
1184/// reading and writing guest memory.
1185// NOTE: this type uses `inspect(skip)`, as it end up being a dependency of
1186// _many_ objects, and littering the inspect graph with references to the same
1187// node would be silly.
1188#[derive(Debug, Clone, Inspect)]
1189#[inspect(skip)]
1190pub struct GuestMemory {
1191    inner: Arc<GuestMemoryInner>,
1192}
1193
1194struct GuestMemoryInner<T: ?Sized = dyn DynGuestMemoryAccess> {
1195    region_def: RegionDefinition,
1196    regions: Vec<MemoryRegion>,
1197    debug_name: Arc<str>,
1198    allocated: bool,
1199    /// Cached result of [`GuestMemoryAccess::supports_locking`], since it is
1200    /// queried on hot zero-copy paths and never changes for a given backing.
1201    supports_locking: bool,
1202    imp: T,
1203}
1204
1205impl<T: ?Sized> Debug for GuestMemoryInner<T> {
1206    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1207        f.debug_struct("GuestMemoryInner")
1208            .field("region_def", &self.region_def)
1209            .field("regions", &self.regions)
1210            .finish()
1211    }
1212}
1213
1214#[derive(Debug, Copy, Clone, Default)]
1215struct MemoryRegion {
1216    mapping: Option<SendPtrU8>,
1217    #[cfg(feature = "bitmap")]
1218    bitmaps: Option<[SendPtrU8; 2]>,
1219    #[cfg(feature = "bitmap")]
1220    bitmap_start: u8,
1221    len: u64,
1222    base_iova: Option<u64>,
1223}
1224
1225/// The type of access that guest memory will be used for.
1226///
1227/// The discriminants correspond to bitmap indexes (read = 0, write = 1) and
1228/// must not be reordered.
1229#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1230pub enum AccessType {
1231    /// Read access.
1232    Read = 0,
1233    /// Write access.
1234    Write = 1,
1235}
1236
1237/// `NonNull<u8>` that implements `Send+Sync`.
1238///
1239/// Rust makes pointers `!Send+!Sync` by default to force you to think about the
1240/// ownership model and thread safety of types using pointers--there is nothing
1241/// safety-related about `Send`/`Sync` on pointers by themselves since all such
1242/// accesses to pointers require `unsafe` blocks anyway.
1243///
1244/// However, in practice, this leads to spurious manual `Send+Sync` impls on
1245/// types containing pointers, especially those containing generics. Define a
1246/// wrapping pointer type that implements `Send+Sync` so that the normal auto
1247/// trait rules apply to types containing these pointers.
1248#[derive(Debug, Copy, Clone)]
1249struct SendPtrU8(NonNull<u8>);
1250
1251// SAFETY: see type description.
1252unsafe impl Send for SendPtrU8 {}
1253// SAFETY: see type description.
1254unsafe impl Sync for SendPtrU8 {}
1255
1256impl MemoryRegion {
1257    fn new(imp: &impl GuestMemoryAccess) -> Self {
1258        #[cfg(feature = "bitmap")]
1259        let (bitmaps, bitmap_start) = {
1260            let bitmap_info = imp.access_bitmap();
1261            let bitmaps = bitmap_info
1262                .as_ref()
1263                .map(|bm| [SendPtrU8(bm.read_bitmap), SendPtrU8(bm.write_bitmap)]);
1264            let bitmap_start = bitmap_info.map_or(0, |bi| bi.bit_offset);
1265            (bitmaps, bitmap_start)
1266        };
1267        Self {
1268            mapping: imp.mapping().map(SendPtrU8),
1269            #[cfg(feature = "bitmap")]
1270            bitmaps,
1271            #[cfg(feature = "bitmap")]
1272            bitmap_start,
1273            len: imp.max_address(),
1274            base_iova: imp.base_iova(),
1275        }
1276    }
1277
1278    /// # Safety
1279    ///
1280    /// The caller must ensure that `offset + len` fits in this region, and that
1281    /// the object bitmap is currently valid for atomic read access from this
1282    /// thread.
1283    unsafe fn check_access(
1284        &self,
1285        access_type: AccessType,
1286        offset: u64,
1287        len: u64,
1288    ) -> Result<(), u64> {
1289        debug_assert!(self.len >= offset + len);
1290        #[cfg(not(feature = "bitmap"))]
1291        let _ = access_type;
1292
1293        #[cfg(feature = "bitmap")]
1294        if len == 0 {
1295            return Ok(());
1296        } else if let Some(bitmaps) = &self.bitmaps {
1297            let SendPtrU8(bitmap) = bitmaps[access_type as usize];
1298            let start = offset / PAGE_SIZE64;
1299            let end = (offset + len - 1) / PAGE_SIZE64;
1300            // FUTURE: consider optimizing this separately for multi-page and
1301            // single-page accesses.
1302            for gpn in start..=end {
1303                let bit_offset = self.bitmap_start as u64 + gpn;
1304                // SAFETY: the caller ensures that the bitmap is big enough and
1305                // valid for atomic read access from this thread.
1306                let bit = unsafe {
1307                    (*bitmap
1308                        .as_ptr()
1309                        .cast_const()
1310                        .cast::<AtomicU8>()
1311                        .add(bit_offset as usize / 8))
1312                    .load(std::sync::atomic::Ordering::Relaxed)
1313                        & (1 << (bit_offset % 8))
1314                };
1315                if bit == 0 {
1316                    return Err((gpn * PAGE_SIZE64).saturating_sub(offset));
1317                }
1318            }
1319        }
1320
1321        Ok(())
1322    }
1323}
1324
1325/// The default implementation is [`GuestMemory::empty`].
1326impl Default for GuestMemory {
1327    fn default() -> Self {
1328        Self::empty()
1329    }
1330}
1331
1332struct Empty;
1333
1334// SAFETY: the mapping is empty, so all requirements are trivially satisfied.
1335unsafe impl GuestMemoryAccess for Empty {
1336    fn mapping(&self) -> Option<NonNull<u8>> {
1337        None
1338    }
1339
1340    fn max_address(&self) -> u64 {
1341        0
1342    }
1343
1344    fn supports_locking(&self) -> bool {
1345        // This implementation trivially supports locking since there are no
1346        // pages to lock.
1347        true
1348    }
1349}
1350
1351#[derive(Debug, Error)]
1352pub enum MultiRegionError {
1353    #[error("region size {0:#x} is not a power of 2")]
1354    NotPowerOfTwo(u64),
1355    #[error("region size {0:#x} is smaller than a page")]
1356    RegionSizeTooSmall(u64),
1357    #[error(
1358        "too many regions ({region_count}) for region size {region_size:#x}; max is {max_region_count}"
1359    )]
1360    TooManyRegions {
1361        region_count: usize,
1362        max_region_count: usize,
1363        region_size: u64,
1364    },
1365    #[error("backing size {backing_size:#x} is too large for region size {region_size:#x}")]
1366    BackingTooLarge { backing_size: u64, region_size: u64 },
1367}
1368
1369/// The RCU domain memory accesses occur under. Updates to any memory access
1370/// bitmaps must be synchronized under this domain.
1371///
1372/// See [`GuestMemoryAccess::access_bitmap`] for more details.
1373///
1374/// This is currently the global domain, but this is reexported here to make
1375/// calling code clearer.
1376#[cfg(feature = "bitmap")]
1377pub fn rcu() -> minircu::RcuDomain {
1378    // Use the global domain unless we find a reason to do something else.
1379    minircu::global()
1380}
1381
1382impl GuestMemory {
1383    /// Returns a new instance using `imp` as the backing.
1384    ///
1385    /// `debug_name` is used to specify which guest memory is being accessed in
1386    /// error messages.
1387    pub fn new(debug_name: impl Into<Arc<str>>, imp: impl GuestMemoryAccess) -> Self {
1388        // Install signal handlers on unix if a mapping is present.
1389        //
1390        // Skip this on miri even when there is a mapping, since the mapping may
1391        // never be accessed by the code under test.
1392        if imp.mapping().is_some() && !cfg!(miri) {
1393            trycopy::initialize_try_copy();
1394        }
1395        Self::new_inner(debug_name.into(), imp, false)
1396    }
1397
1398    fn new_inner(debug_name: Arc<str>, imp: impl GuestMemoryAccess, allocated: bool) -> Self {
1399        let regions = vec![MemoryRegion::new(&imp)];
1400        let supports_locking = imp.supports_locking();
1401        Self {
1402            inner: Arc::new(GuestMemoryInner {
1403                imp,
1404                debug_name,
1405                region_def: RegionDefinition {
1406                    invalid_mask: 1 << 63,
1407                    region_mask: !0 >> 1,
1408                    region_bits: 63, // right shift of 64 isn't valid, so restrict the space
1409                },
1410                regions,
1411                allocated,
1412                supports_locking,
1413            }),
1414        }
1415    }
1416
1417    /// Creates a new multi-region guest memory, made up of multiple mappings.
1418    /// This allows you to create a very large sparse layout (up to the limits
1419    /// of the VM's physical address space) without having to allocate an
1420    /// enormous amount of virtual address space.
1421    ///
1422    /// Each region will be `region_size` bytes and will start immediately after
1423    /// the last one. This must be a power of two, be at least a page in size,
1424    /// and cannot fill the full 64-bit address space.
1425    ///
1426    /// `imps` must be a list of [`GuestMemoryAccess`] implementations, one for
1427    /// each region. Use `None` if the corresponding region is empty.
1428    ///
1429    /// A region's mapping cannot fully fill the region. This is necessary to
1430    /// avoid callers expecting to be able to access a memory range that spans
1431    /// two regions.
1432    pub fn new_multi_region(
1433        debug_name: impl Into<Arc<str>>,
1434        region_size: u64,
1435        mut imps: Vec<Option<impl GuestMemoryAccess>>,
1436    ) -> Result<Self, MultiRegionError> {
1437        // Install signal handlers.
1438        trycopy::initialize_try_copy();
1439
1440        if !region_size.is_power_of_two() {
1441            return Err(MultiRegionError::NotPowerOfTwo(region_size));
1442        }
1443        if region_size < PAGE_SIZE64 {
1444            return Err(MultiRegionError::RegionSizeTooSmall(region_size));
1445        }
1446        let region_bits = region_size.trailing_zeros();
1447
1448        let max_region_count = 1 << (63 - region_bits);
1449
1450        let region_count = imps.len().next_power_of_two();
1451        if region_count > max_region_count {
1452            return Err(MultiRegionError::TooManyRegions {
1453                region_count,
1454                max_region_count,
1455                region_size,
1456            });
1457        }
1458
1459        let valid_bits = region_bits + region_count.trailing_zeros();
1460        assert!(valid_bits < 64);
1461        let invalid_mask = !0 << valid_bits;
1462
1463        let mut regions = vec![MemoryRegion::default(); region_count];
1464        for (imp, region) in imps.iter().zip(&mut regions) {
1465            let Some(imp) = imp else { continue };
1466            let backing_size = imp.max_address();
1467            if backing_size > region_size {
1468                return Err(MultiRegionError::BackingTooLarge {
1469                    backing_size,
1470                    region_size,
1471                });
1472            }
1473            *region = MemoryRegion::new(imp);
1474        }
1475
1476        let region_def = RegionDefinition {
1477            invalid_mask,
1478            region_mask: region_size - 1,
1479            region_bits,
1480        };
1481
1482        imps.resize_with(region_count, || None);
1483        // Locking is only supported if every backing region supports it.
1484        let supports_locking = imps
1485            .iter()
1486            .flatten()
1487            .all(GuestMemoryAccess::supports_locking);
1488        let imp = MultiRegionGuestMemoryAccess { imps, region_def };
1489
1490        let inner = GuestMemoryInner {
1491            debug_name: debug_name.into(),
1492            region_def,
1493            regions,
1494            imp,
1495            allocated: false,
1496            supports_locking,
1497        };
1498
1499        Ok(Self {
1500            inner: Arc::new(inner),
1501        })
1502    }
1503
1504    /// Allocates a guest memory object on the heap with the given size in
1505    /// bytes.
1506    ///
1507    /// `size` will be rounded up to the page size. The backing buffer will be
1508    /// page aligned.
1509    ///
1510    /// The debug name in errors will be "heap". If you want to provide a
1511    /// different debug name, manually use `GuestMemory::new` with
1512    /// [`AlignedHeapMemory`].
1513    pub fn allocate(size: usize) -> Self {
1514        Self::new_inner("heap".into(), AlignedHeapMemory::new(size), true)
1515    }
1516
1517    /// If this memory is unaliased and was created via
1518    /// [`GuestMemory::allocate`], returns the backing buffer.
1519    ///
1520    /// Returns `Err(self)` if there are other references to this memory (via
1521    /// `clone()`).
1522    pub fn into_inner_buf(self) -> Result<AlignedHeapMemory, Self> {
1523        if !self.inner.allocated {
1524            return Err(self);
1525        }
1526        // FUTURE: consider using `Any` and `Arc::downcast` once trait upcasting is stable.
1527        // SAFETY: the inner implementation is guaranteed to be a `AlignedHeapMemory`.
1528        let inner = unsafe {
1529            Arc::<GuestMemoryInner<AlignedHeapMemory>>::from_raw(Arc::into_raw(self.inner).cast())
1530        };
1531        let inner = Arc::try_unwrap(inner).map_err(|inner| Self { inner })?;
1532        Ok(inner.imp)
1533    }
1534
1535    /// If this memory was created via [`GuestMemory::allocate`], returns a slice to
1536    /// the allocated buffer.
1537    pub fn inner_buf(&self) -> Option<&[AtomicU8]> {
1538        if !self.inner.allocated {
1539            return None;
1540        }
1541        // FUTURE: consider using `<dyn Any>::downcast` once trait upcasting is stable.
1542        // SAFETY: the inner implementation is guaranteed to be a `AlignedHeapMemory`.
1543        let inner = unsafe { &*core::ptr::from_ref(&self.inner.imp).cast::<AlignedHeapMemory>() };
1544        Some(inner)
1545    }
1546
1547    /// If this memory was created via [`GuestMemory::allocate`] and there are
1548    /// no other references to it, returns a mutable slice to the backing
1549    /// buffer.
1550    pub fn inner_buf_mut(&mut self) -> Option<&mut [u8]> {
1551        if !self.inner.allocated {
1552            return None;
1553        }
1554        let inner = Arc::get_mut(&mut self.inner)?;
1555        // FUTURE: consider using `<dyn Any>::downcast` once trait upcasting is stable.
1556        // SAFETY: the inner implementation is guaranteed to be a `AlignedHeapMemory`.
1557        let imp = unsafe { &mut *core::ptr::from_mut(&mut inner.imp).cast::<AlignedHeapMemory>() };
1558        Some(imp.as_mut())
1559    }
1560
1561    /// Returns an empty guest memory, which fails every operation.
1562    pub fn empty() -> Self {
1563        GuestMemory::new("empty", Empty)
1564    }
1565
1566    fn wrap_err(
1567        &self,
1568        gpa_len: Option<(u64, u64)>,
1569        op: GuestMemoryOperation,
1570        err: GuestMemoryBackingError,
1571    ) -> GuestMemoryError {
1572        let range = gpa_len.map(|(gpa, len)| gpa..gpa.wrapping_add(len));
1573        GuestMemoryError::new(&self.inner.debug_name, range, op, err)
1574    }
1575
1576    fn with_op<T>(
1577        &self,
1578        gpa_len: Option<(u64, u64)>,
1579        op: GuestMemoryOperation,
1580        f: impl FnOnce() -> Result<T, GuestMemoryBackingError>,
1581    ) -> Result<T, GuestMemoryError> {
1582        f().map_err(|err| self.wrap_err(gpa_len, op, err))
1583    }
1584
1585    /// Creates a smaller view into guest memory, constraining accesses within the new boundaries. For smaller ranges,
1586    /// some memory implementations (e.g. HDV) may choose to lock the pages into memory for faster access. Locking
1587    /// random guest memory may cause issues, so only opt in to this behavior when the range can be considered "owned"
1588    /// by the caller.
1589    pub fn subrange(
1590        &self,
1591        offset: u64,
1592        len: u64,
1593        allow_preemptive_locking: bool,
1594    ) -> Result<GuestMemory, GuestMemoryError> {
1595        self.with_op(Some((offset, len)), GuestMemoryOperation::Subrange, || {
1596            if let Some(guest_memory) =
1597                self.inner
1598                    .imp
1599                    .subrange(offset, len, allow_preemptive_locking)?
1600            {
1601                Ok(guest_memory)
1602            } else {
1603                create_memory_subrange(self.inner.clone(), offset, len, allow_preemptive_locking)
1604            }
1605        })
1606    }
1607
1608    /// Returns a subrange where pages from the subrange can be locked.
1609    pub fn lockable_subrange(
1610        &self,
1611        offset: u64,
1612        len: u64,
1613    ) -> Result<GuestMemory, GuestMemoryError> {
1614        // TODO: Enforce subrange is actually lockable.
1615        self.subrange(offset, len, true)
1616    }
1617
1618    /// Returns the mapping for all of guest memory.
1619    ///
1620    /// Returns `None` if there is more than one region or if the memory is not
1621    /// mapped.
1622    pub fn full_mapping(&self) -> Option<(*mut u8, usize)> {
1623        if let [region] = self.inner.regions.as_slice() {
1624            #[cfg(feature = "bitmap")]
1625            if region.bitmaps.is_some() {
1626                return None;
1627            }
1628            region
1629                .mapping
1630                .map(|SendPtrU8(ptr)| (ptr.as_ptr(), region.len as usize))
1631        } else {
1632            None
1633        }
1634    }
1635
1636    /// Gets the IO address for DMAing to `gpa` from a user-mode driver not
1637    /// going through an IOMMU.
1638    pub fn iova(&self, gpa: u64) -> Option<u64> {
1639        let (region, offset, _) = self.inner.region(gpa, 1).ok()?;
1640        Some(region.base_iova? + offset)
1641    }
1642
1643    /// Returns a sharing object if this memory supports
1644    /// file-based sharing. See [`GuestMemorySharing`].
1645    pub fn sharing(&self) -> Option<GuestMemorySharing> {
1646        self.inner.imp.sharing()
1647    }
1648
1649    /// Returns whether this memory supports locking pages via
1650    /// [`lock_gpns`](Self::lock_gpns) and [`lock_range`](Self::lock_range).
1651    ///
1652    /// Memory behind an emulated IOMMU has no stable host mapping and cannot
1653    /// be locked; zero-copy callers should check this and fall back to a
1654    /// copying path when it returns `false`. This is authoritative: when it
1655    /// returns `false`, [`lock_gpns`](Self::lock_gpns) and
1656    /// [`lock_range`](Self::lock_range) fail with a `NotLockable` error.
1657    pub fn supports_locking(&self) -> bool {
1658        self.inner.supports_locking
1659    }
1660
1661    /// Gets a pointer to the VA range for `gpa..gpa+len`.
1662    ///
1663    /// Returns `Ok(None)` if there is no mapping. Returns `Err(_)` if the
1664    /// memory is out of range.
1665    fn mapping_range(
1666        &self,
1667        access_type: AccessType,
1668        gpa: u64,
1669        len: usize,
1670    ) -> Result<Option<*mut u8>, GuestMemoryBackingError> {
1671        let (region, offset, _) = self.inner.region(gpa, len as u64)?;
1672        if let Some(SendPtrU8(ptr)) = region.mapping {
1673            loop {
1674                // SAFETY: offset + len is checked by `region()` to be inside the VA range.
1675                let fault_offset = unsafe {
1676                    match region.check_access(access_type, offset, len as u64) {
1677                        Ok(()) => return Ok(Some(ptr.as_ptr().add(offset as usize))),
1678                        Err(n) => n,
1679                    }
1680                };
1681
1682                // Resolve the fault and try again.
1683                match self.inner.imp.page_fault(
1684                    gpa + fault_offset,
1685                    len - fault_offset as usize,
1686                    access_type == AccessType::Write,
1687                    true,
1688                ) {
1689                    PageFaultAction::Fail(err) => {
1690                        return Err(GuestMemoryBackingError::new(
1691                            err.kind,
1692                            gpa + fault_offset,
1693                            err.err,
1694                        ));
1695                    }
1696                    PageFaultAction::Retry => {}
1697                    PageFaultAction::Fallback => break,
1698                }
1699            }
1700        }
1701        Ok(None)
1702    }
1703
1704    /// Runs `f` with a pointer to the mapped memory. If `f` fails, tries to
1705    /// resolve the fault (failing on error), then loops.
1706    ///
1707    /// If there is no mapping for the memory, or if the fault handler requests
1708    /// it, call `fallback` instead. `fallback` will not be called unless `gpa`
1709    /// and `len` are in range.
1710    fn run_on_mapping<T, P>(
1711        &self,
1712        access_type: AccessType,
1713        gpa: u64,
1714        len: usize,
1715        mut param: P,
1716        mut f: impl FnMut(&mut P, *mut u8) -> Result<T, trycopy::MemoryError>,
1717        fallback: impl FnOnce(&mut P) -> Result<T, GuestMemoryBackingError>,
1718    ) -> Result<T, GuestMemoryBackingError> {
1719        let op = || {
1720            let Some(mapping) = self.mapping_range(access_type, gpa, len)? else {
1721                return fallback(&mut param);
1722            };
1723
1724            // Try until the fault fails to resolve.
1725            loop {
1726                match f(&mut param, mapping) {
1727                    Ok(t) => return Ok(t),
1728                    Err(fault) => {
1729                        match self.inner.imp.page_fault(
1730                            gpa + fault.offset() as u64,
1731                            len - fault.offset(),
1732                            access_type == AccessType::Write,
1733                            false,
1734                        ) {
1735                            PageFaultAction::Fail(err) => {
1736                                return Err(GuestMemoryBackingError::new(
1737                                    err.kind,
1738                                    gpa + fault.offset() as u64,
1739                                    err.err,
1740                                ));
1741                            }
1742                            PageFaultAction::Retry => {}
1743                            PageFaultAction::Fallback => return fallback(&mut param),
1744                        }
1745                    }
1746                }
1747            }
1748        };
1749        // If the `bitmap` feature is enabled, run the function in an RCU
1750        // critical section. This will allow callers to flush concurrent
1751        // accesses after bitmap updates.
1752        #[cfg(feature = "bitmap")]
1753        return rcu().run(op);
1754        #[cfg(not(feature = "bitmap"))]
1755        op()
1756    }
1757
1758    /// # Safety
1759    ///
1760    /// The caller must ensure that `src`..`src + len` is a valid buffer for reads.
1761    unsafe fn write_ptr(
1762        &self,
1763        gpa: u64,
1764        src: *const u8,
1765        len: usize,
1766    ) -> Result<(), GuestMemoryBackingError> {
1767        if len == 0 {
1768            return Ok(());
1769        }
1770        self.run_on_mapping(
1771            AccessType::Write,
1772            gpa,
1773            len,
1774            (),
1775            |(), dest| {
1776                // SAFETY: dest..dest+len is guaranteed to point to a reserved VA
1777                // range, and src..src+len is guaranteed by the caller to be a valid
1778                // buffer for reads.
1779                unsafe { trycopy::try_copy(src, dest, len) }
1780            },
1781            |()| {
1782                // SAFETY: src..src+len is guaranteed by the caller to point to a valid
1783                // buffer for reads.
1784                unsafe { self.inner.imp.write_fallback(gpa, src, len) }
1785            },
1786        )
1787    }
1788
1789    /// Writes `src` into guest memory at address `gpa`.
1790    pub fn write_at(&self, gpa: u64, src: &[u8]) -> Result<(), GuestMemoryError> {
1791        self.with_op(
1792            Some((gpa, src.len() as u64)),
1793            GuestMemoryOperation::Write,
1794            || self.write_at_inner(gpa, src),
1795        )
1796    }
1797
1798    fn write_at_inner(&self, gpa: u64, src: &[u8]) -> Result<(), GuestMemoryBackingError> {
1799        // SAFETY: `src` is a valid buffer for reads.
1800        unsafe { self.write_ptr(gpa, src.as_ptr(), src.len()) }
1801    }
1802
1803    /// Writes `src` into guest memory at address `gpa`.
1804    pub fn write_from_atomic(&self, gpa: u64, src: &[AtomicU8]) -> Result<(), GuestMemoryError> {
1805        self.with_op(
1806            Some((gpa, src.len() as u64)),
1807            GuestMemoryOperation::Write,
1808            || {
1809                // SAFETY: `src` is a valid buffer for reads.
1810                unsafe { self.write_ptr(gpa, src.as_ptr().cast(), src.len()) }
1811            },
1812        )
1813    }
1814
1815    /// Writes `len` bytes of `val` into guest memory at address `gpa`.
1816    pub fn fill_at(&self, gpa: u64, val: u8, len: usize) -> Result<(), GuestMemoryError> {
1817        self.with_op(Some((gpa, len as u64)), GuestMemoryOperation::Fill, || {
1818            self.fill_at_inner(gpa, val, len)
1819        })
1820    }
1821
1822    fn fill_at_inner(&self, gpa: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
1823        if len == 0 {
1824            return Ok(());
1825        }
1826        self.run_on_mapping(
1827            AccessType::Write,
1828            gpa,
1829            len,
1830            (),
1831            |(), dest| {
1832                // SAFETY: dest..dest+len is guaranteed to point to a reserved VA range.
1833                unsafe { trycopy::try_write_bytes(dest, val, len) }
1834            },
1835            |()| self.inner.imp.fill_fallback(gpa, val, len),
1836        )
1837    }
1838
1839    /// Reads from guest memory into `dest..dest+len`.
1840    ///
1841    /// # Safety
1842    /// The caller must ensure dest..dest+len is a valid buffer for writes.
1843    unsafe fn read_ptr(
1844        &self,
1845        gpa: u64,
1846        dest: *mut u8,
1847        len: usize,
1848    ) -> Result<(), GuestMemoryBackingError> {
1849        if len == 0 {
1850            return Ok(());
1851        }
1852        self.run_on_mapping(
1853            AccessType::Read,
1854            gpa,
1855            len,
1856            (),
1857            |(), src| {
1858                // SAFETY: src..src+len is guaranteed to point to a reserved VA
1859                // range, and dest..dest+len is guaranteed by the caller to be a
1860                // valid buffer for writes.
1861                unsafe { trycopy::try_copy(src, dest, len) }
1862            },
1863            |()| {
1864                // SAFETY: dest..dest+len is guaranteed by the caller to point to a
1865                // valid buffer for writes.
1866                unsafe { self.inner.imp.read_fallback(gpa, dest, len) }
1867            },
1868        )
1869    }
1870
1871    fn read_at_inner(&self, gpa: u64, dest: &mut [u8]) -> Result<(), GuestMemoryBackingError> {
1872        // SAFETY: `dest` is a valid buffer for writes.
1873        unsafe { self.read_ptr(gpa, dest.as_mut_ptr(), dest.len()) }
1874    }
1875
1876    /// Reads from guest memory address `gpa` into `dest`.
1877    pub fn read_at(&self, gpa: u64, dest: &mut [u8]) -> Result<(), GuestMemoryError> {
1878        self.with_op(
1879            Some((gpa, dest.len() as u64)),
1880            GuestMemoryOperation::Read,
1881            || self.read_at_inner(gpa, dest),
1882        )
1883    }
1884
1885    /// Reads from guest memory address `gpa` into `dest`.
1886    pub fn read_to_atomic(&self, gpa: u64, dest: &[AtomicU8]) -> Result<(), GuestMemoryError> {
1887        self.with_op(
1888            Some((gpa, dest.len() as u64)),
1889            GuestMemoryOperation::Read,
1890            // SAFETY: `dest` is a valid buffer for writes.
1891            || unsafe { self.read_ptr(gpa, dest.as_ptr() as *mut u8, dest.len()) },
1892        )
1893    }
1894
1895    /// Writes an object to guest memory at address `gpa`.
1896    ///
1897    /// If the object is 1, 2, 4, or 8 bytes and the address is naturally
1898    /// aligned, then the write will be performed atomically. Here, this means
1899    /// that concurrent readers (via `read_plain`) cannot observe a torn write
1900    /// but will observe either the old or new value.
1901    ///
1902    /// The memory ordering of the write is unspecified.
1903    ///
1904    /// FUTURE: once we are on Rust 1.79, add a method specifically for atomic
1905    /// accesses that const asserts that the size is appropriate.
1906    pub fn write_plain<T: IntoBytes + Immutable + KnownLayout>(
1907        &self,
1908        gpa: u64,
1909        b: &T,
1910    ) -> Result<(), GuestMemoryError> {
1911        // Note that this is const, so the match below will compile out.
1912        let len = size_of::<T>();
1913        self.with_op(Some((gpa, len as u64)), GuestMemoryOperation::Write, || {
1914            self.run_on_mapping(
1915                AccessType::Write,
1916                gpa,
1917                len,
1918                (),
1919                |(), dest| {
1920                    // SAFETY: dest..dest+len is guaranteed to point to
1921                    // a reserved VA range.
1922                    unsafe { trycopy::try_write_volatile(dest.cast(), b) }
1923                },
1924                |()| {
1925                    // SAFETY: b is a valid buffer for reads.
1926                    unsafe {
1927                        self.inner
1928                            .imp
1929                            .write_fallback(gpa, b.as_bytes().as_ptr(), len)
1930                    }
1931                },
1932            )
1933        })
1934    }
1935
1936    /// Attempts a sequentially-consistent compare exchange of the value at `gpa`.
1937    pub fn compare_exchange<T: IntoBytes + FromBytes + Immutable + KnownLayout + Copy>(
1938        &self,
1939        gpa: u64,
1940        current: T,
1941        new: T,
1942    ) -> Result<Result<T, T>, GuestMemoryError> {
1943        const {
1944            assert!(matches!(size_of::<T>(), 1 | 2 | 4 | 8));
1945            assert!(align_of::<T>() >= size_of::<T>());
1946        };
1947        let len = size_of_val(&new);
1948        self.with_op(
1949            Some((gpa, len as u64)),
1950            GuestMemoryOperation::CompareExchange,
1951            || {
1952                // Assume that if write is allowed, then read is allowed.
1953                self.run_on_mapping(
1954                    AccessType::Write,
1955                    gpa,
1956                    len,
1957                    (),
1958                    |(), dest| {
1959                        // SAFETY: dest..dest+len is guaranteed by the caller to be a valid
1960                        // buffer for writes.
1961                        unsafe { trycopy::try_compare_exchange(dest.cast(), current, new) }
1962                    },
1963                    |()| {
1964                        let mut current = current;
1965                        let success = self.inner.imp.compare_exchange_fallback(
1966                            gpa,
1967                            current.as_mut_bytes(),
1968                            new.as_bytes(),
1969                        )?;
1970
1971                        Ok(if success { Ok(new) } else { Err(current) })
1972                    },
1973                )
1974            },
1975        )
1976    }
1977
1978    /// Reads an object from guest memory at address `gpa`.
1979    ///
1980    /// If the object is 1, 2, 4, or 8 bytes and the address is naturally
1981    /// aligned, then the read will be performed atomically. Here, this means
1982    /// that when there is a concurrent writer, callers will observe either the
1983    /// old or new value, but not a torn read.
1984    ///
1985    /// The memory ordering of the read is unspecified.
1986    ///
1987    /// FUTURE: once we are on Rust 1.79, add a method specifically for atomic
1988    /// accesses that const asserts that the size is appropriate.
1989    pub fn read_plain<T: FromBytes + Immutable + KnownLayout>(
1990        &self,
1991        gpa: u64,
1992    ) -> Result<T, GuestMemoryError> {
1993        self.with_op(
1994            Some((gpa, size_of::<T>() as u64)),
1995            GuestMemoryOperation::Read,
1996            || self.read_plain_inner(gpa),
1997        )
1998    }
1999
2000    fn read_plain_inner<T: FromBytes + Immutable + KnownLayout>(
2001        &self,
2002        gpa: u64,
2003    ) -> Result<T, GuestMemoryBackingError> {
2004        let len = size_of::<T>();
2005        self.run_on_mapping(
2006            AccessType::Read,
2007            gpa,
2008            len,
2009            (),
2010            |(), src| {
2011                // SAFETY: src..src+len is guaranteed to point to a reserved VA
2012                // range.
2013                unsafe { trycopy::try_read_volatile(src.cast::<T>()) }
2014            },
2015            |()| {
2016                let mut obj = std::mem::MaybeUninit::<T>::zeroed();
2017                // SAFETY: dest..dest+len is guaranteed by the caller to point to a
2018                // valid buffer for writes.
2019                unsafe {
2020                    self.inner
2021                        .imp
2022                        .read_fallback(gpa, obj.as_mut_ptr().cast(), len)?;
2023                }
2024                // SAFETY: `obj` was fully initialized by `read_fallback`.
2025                Ok(unsafe { obj.assume_init() })
2026            },
2027        )
2028    }
2029
2030    fn probe_page_for_lock(
2031        &self,
2032        access: AccessType,
2033        with_kernel_access: bool,
2034        gpa: u64,
2035    ) -> Result<*const AtomicU8, GuestMemoryBackingError> {
2036        let (region, offset, _) = self.inner.region(gpa, 1)?;
2037        let Some(SendPtrU8(ptr)) = region.mapping else {
2038            return Err(GuestMemoryBackingError::other(gpa, NotLockable));
2039        };
2040        // Ensure the virtual address can be exposed.
2041        if with_kernel_access {
2042            self.inner.imp.expose_va(gpa, 1)?;
2043        }
2044        // Fault the page in for the access the caller will perform through the
2045        // returned pointer. A write lock must fault for *write* so that a
2046        // read-only-until-write backing (e.g. Windows soft large pages, which
2047        // map guest RAM read-only until the first write raises it to
2048        // read-write) is made writable before the caller writes; otherwise the
2049        // write would hit a read-only page and access-violate. A read-only lock
2050        // only faults for read, so it neither forces writability (which
2051        // genuinely read-only memory would reject) nor needlessly promotes soft
2052        // large pages.
2053        match access {
2054            AccessType::Read => {
2055                self.read_plain_inner::<u8>(gpa)?;
2056            }
2057            AccessType::Write => {
2058                self.probe_mapped_page_writable(gpa)?;
2059            }
2060        }
2061        // SAFETY: the read_at call includes a check that ensures that
2062        // `gpa` is in the VA range.
2063        let page = unsafe { ptr.as_ptr().add(offset as usize) };
2064        Ok(page.cast())
2065    }
2066
2067    /// Faults a single **mapped** guest page in for write without changing its
2068    /// contents, so that a read-only-until-write backing (e.g. Windows soft
2069    /// large pages) is raised to read-write before a write lock hands out a
2070    /// pointer to it.
2071    ///
2072    /// This is a helper for the locking path and requires the page to be backed
2073    /// by a host mapping. It works by performing a no-op compare-exchange
2074    /// against the mapping: on a read-only page the locked read-modify-write
2075    /// triggers the write fault handler (raising the window to read-write), and
2076    /// once writable the exchange leaves the value unchanged (writing back the
2077    /// same value on a match and nothing on a mismatch).
2078    ///
2079    /// It deliberately does **not** fall back to
2080    /// [`GuestMemoryAccess::compare_exchange_fallback`]: the write-probe is
2081    /// meaningless without a mapping (there is nothing to fault in), and not all
2082    /// backings implement that fallback. Callers must only reach this after
2083    /// confirming the page is mapped, as the lock path does via
2084    /// [`GuestMemory::supports_locking`]. A non-mapping backing therefore fails
2085    /// with a clear error rather than silently taking an unsupported path.
2086    fn probe_mapped_page_writable(&self, gpa: u64) -> Result<(), GuestMemoryBackingError> {
2087        self.run_on_mapping(
2088            AccessType::Write,
2089            gpa,
2090            1,
2091            (),
2092            |(), dest| {
2093                // SAFETY: dest points to a reserved VA range of at least one byte.
2094                unsafe { trycopy::try_compare_exchange::<u8>(dest.cast(), 0, 0).map(|_| ()) }
2095            },
2096            |()| {
2097                // Only reachable without a mapping (or if a backing's
2098                // `page_fault` requests the fallback). The write-probe only
2099                // makes sense for mapping-based backings, so fail clearly here
2100                // instead of invoking `compare_exchange_fallback`, which many
2101                // backings do not implement.
2102                Err(GuestMemoryBackingError::other(gpa, NotLockable))
2103            },
2104        )
2105    }
2106
2107    /// Locks the specified guest pages (by GPN), returning handles that expose
2108    /// their host VA for zero-copy access.
2109    ///
2110    /// `access` selects whether the pages will be read from or written to: a
2111    /// write lock faults each page in for write so that a
2112    /// read-only-until-write backing (e.g. Windows soft large pages) is raised
2113    /// to read-write before the caller writes through the returned pointer,
2114    /// while a read-only lock (e.g. read-only DMA) only faults for read.
2115    pub fn lock_gpns(
2116        &self,
2117        access: AccessType,
2118        with_kernel_access: bool,
2119        gpns: &[u64],
2120    ) -> Result<LockedPages, GuestMemoryError> {
2121        self.with_op(None, GuestMemoryOperation::Lock, || {
2122            if !self.inner.supports_locking {
2123                let gpa = gpns.first().map_or(0, |&gpn| gpn.wrapping_mul(PAGE_SIZE64));
2124                return Err(GuestMemoryBackingError::other(gpa, NotLockable));
2125            }
2126            let mut pages = Vec::with_capacity(gpns.len());
2127            for &gpn in gpns {
2128                let gpa = gpn_to_gpa(gpn).map_err(GuestMemoryBackingError::gpn)?;
2129                let page = self.probe_page_for_lock(access, with_kernel_access, gpa)?;
2130                pages.push(PagePtr(page));
2131            }
2132            let store_gpns = self.inner.imp.lock_gpns(gpns)?;
2133            Ok(LockedPages {
2134                pages: pages.into_boxed_slice(),
2135                gpns: store_gpns.then(|| gpns.to_vec().into_boxed_slice()),
2136                mem: self.inner.clone(),
2137            })
2138        })
2139    }
2140
2141    pub fn probe_gpns(&self, gpns: &[u64]) -> Result<(), GuestMemoryError> {
2142        self.with_op(None, GuestMemoryOperation::Probe, || {
2143            for &gpn in gpns {
2144                self.read_plain_inner::<u8>(
2145                    gpn_to_gpa(gpn).map_err(GuestMemoryBackingError::gpn)?,
2146                )?;
2147            }
2148            Ok(())
2149        })
2150    }
2151
2152    /// Check if a given GPA is readable or not.
2153    pub fn probe_gpa_readable(&self, gpa: u64) -> Result<(), GuestMemoryErrorKind> {
2154        let mut b = [0];
2155        self.read_at_inner(gpa, &mut b).map_err(|err| err.kind)
2156    }
2157
2158    /// Check if a given GPA is writeable or not.
2159    pub fn probe_gpa_writable(&self, gpa: u64) -> Result<(), GuestMemoryErrorKind> {
2160        let _ = self
2161            .compare_exchange(gpa, 0u8, 0)
2162            .map_err(|err| err.kind())?;
2163        Ok(())
2164    }
2165
2166    /// Gets a slice of guest memory assuming the memory was already locked via
2167    /// [`GuestMemory::lock_gpns`].
2168    ///
2169    /// This is dangerous--if the pages have not been locked, then it could
2170    /// cause an access violation or guest memory corruption.
2171    ///
2172    /// Note that this is not `unsafe` since this cannot cause memory corruption
2173    /// in this process. Even if there is an access violation, the underlying VA
2174    /// space is known to be reserved.
2175    ///
2176    /// Panics if the requested buffer is out of range.
2177    fn dangerous_access_pre_locked_memory(&self, gpa: u64, len: usize) -> &[AtomicU8] {
2178        let addr = self
2179            .mapping_range(AccessType::Write, gpa, len)
2180            .unwrap()
2181            .unwrap();
2182        // SAFETY: addr..addr+len is checked above to be a valid VA range. It's
2183        // possible some of the pages aren't mapped and will cause AVs at
2184        // runtime when accessed, but, as discussed above, at a language level
2185        // this cannot cause any safety issues.
2186        unsafe { std::slice::from_raw_parts(addr.cast(), len) }
2187    }
2188
2189    fn op_range<F: FnMut(u64, Range<usize>) -> Result<(), GuestMemoryBackingError>>(
2190        &self,
2191        op: GuestMemoryOperation,
2192        range: &PagedRange<'_>,
2193        mut f: F,
2194    ) -> Result<(), GuestMemoryError> {
2195        self.with_op(None, op, || {
2196            let gpns = range.gpns();
2197            let offset = range.offset();
2198
2199            // Perform the operation in three phases: the first page (if it is not a
2200            // full page), the full pages, and the last page (if it is not a full
2201            // page).
2202            let mut byte_index = 0;
2203            let mut len = range.len();
2204            let mut page = 0;
2205            if !offset.is_multiple_of(PAGE_SIZE) {
2206                let head_len = std::cmp::min(len, PAGE_SIZE - (offset % PAGE_SIZE));
2207                let addr = gpn_to_gpa(gpns[page]).map_err(GuestMemoryBackingError::gpn)?
2208                    + offset as u64 % PAGE_SIZE64;
2209                f(addr, byte_index..byte_index + head_len)?;
2210                byte_index += head_len;
2211                len -= head_len;
2212                page += 1;
2213            }
2214            while len >= PAGE_SIZE {
2215                f(
2216                    gpn_to_gpa(gpns[page]).map_err(GuestMemoryBackingError::gpn)?,
2217                    byte_index..byte_index + PAGE_SIZE,
2218                )?;
2219                byte_index += PAGE_SIZE;
2220                len -= PAGE_SIZE;
2221                page += 1;
2222            }
2223            if len > 0 {
2224                f(
2225                    gpn_to_gpa(gpns[page]).map_err(GuestMemoryBackingError::gpn)?,
2226                    byte_index..byte_index + len,
2227                )?;
2228            }
2229
2230            Ok(())
2231        })
2232    }
2233
2234    pub fn write_range(&self, range: &PagedRange<'_>, data: &[u8]) -> Result<(), GuestMemoryError> {
2235        assert!(data.len() == range.len());
2236        self.op_range(GuestMemoryOperation::Write, range, move |addr, r| {
2237            self.write_at_inner(addr, &data[r])
2238        })
2239    }
2240
2241    pub fn fill_range(&self, range: &PagedRange<'_>, val: u8) -> Result<(), GuestMemoryError> {
2242        self.op_range(GuestMemoryOperation::Fill, range, move |addr, r| {
2243            self.fill_at_inner(addr, val, r.len())
2244        })
2245    }
2246
2247    pub fn zero_range(&self, range: &PagedRange<'_>) -> Result<(), GuestMemoryError> {
2248        self.op_range(GuestMemoryOperation::Fill, range, move |addr, r| {
2249            self.fill_at_inner(addr, 0, r.len())
2250        })
2251    }
2252
2253    pub fn read_range(
2254        &self,
2255        range: &PagedRange<'_>,
2256        data: &mut [u8],
2257    ) -> Result<(), GuestMemoryError> {
2258        assert!(data.len() == range.len());
2259        self.op_range(GuestMemoryOperation::Read, range, move |addr, r| {
2260            self.read_at_inner(addr, &mut data[r])
2261        })
2262    }
2263
2264    pub fn write_range_from_atomic(
2265        &self,
2266        range: &PagedRange<'_>,
2267        data: &[AtomicU8],
2268    ) -> Result<(), GuestMemoryError> {
2269        assert!(data.len() == range.len());
2270        self.op_range(GuestMemoryOperation::Write, range, move |addr, r| {
2271            let src = &data[r];
2272            // SAFETY: `src` is a valid buffer for reads.
2273            unsafe { self.write_ptr(addr, src.as_ptr().cast(), src.len()) }
2274        })
2275    }
2276
2277    pub fn read_range_to_atomic(
2278        &self,
2279        range: &PagedRange<'_>,
2280        data: &[AtomicU8],
2281    ) -> Result<(), GuestMemoryError> {
2282        assert!(data.len() == range.len());
2283        self.op_range(GuestMemoryOperation::Read, range, move |addr, r| {
2284            let dest = &data[r];
2285            // SAFETY: `dest` is a valid buffer for writes.
2286            unsafe { self.read_ptr(addr, dest.as_ptr().cast_mut().cast(), dest.len()) }
2287        })
2288    }
2289
2290    /// Locks the guest pages spanned by the specified `PagedRange`.
2291    ///
2292    /// # Arguments
2293    /// * 'access' - Whether the locked pages will be read from or written to.
2294    ///   A write lock faults each page in for write so that a
2295    ///   read-only-until-write backing (e.g. Windows soft large pages) is
2296    ///   raised to read-write before the caller writes through the returned
2297    ///   VA; a read-only lock (e.g. read-only DMA) only faults for read.
2298    /// * 'paged_range' - The guest memory range to lock.
2299    /// * 'locked_range' - Receives a list of VA ranges to which each contiguous physical sub-range in `paged_range`
2300    ///   has been mapped. Must be initially empty.
2301    pub fn lock_range<'a, T: LockedRange<'a>>(
2302        &'a self,
2303        access: AccessType,
2304        paged_range: PagedRange<'_>,
2305        mut locked_range: T,
2306    ) -> Result<LockedRangeImpl<'a, T>, GuestMemoryError> {
2307        self.with_op(None, GuestMemoryOperation::Lock, || {
2308            let gpns = paged_range.gpns();
2309            if !self.inner.supports_locking {
2310                let gpa = gpns.first().map_or(0, |&gpn| gpn.wrapping_mul(PAGE_SIZE64));
2311                return Err(GuestMemoryBackingError::other(gpa, NotLockable));
2312            }
2313            for &gpn in gpns {
2314                let gpa = gpn_to_gpa(gpn).map_err(GuestMemoryBackingError::gpn)?;
2315                self.probe_page_for_lock(access, true, gpa)?;
2316            }
2317            for range in paged_range.ranges() {
2318                let range = range.map_err(GuestMemoryBackingError::gpn)?;
2319                locked_range.push_sub_range(
2320                    self.dangerous_access_pre_locked_memory(range.start, range.len() as usize),
2321                );
2322            }
2323            let store_gpns = self.inner.imp.lock_gpns(paged_range.gpns())?;
2324            Ok(LockedRangeImpl {
2325                mem: &self.inner,
2326                gpns: store_gpns.then(|| paged_range.gpns().to_vec().into_boxed_slice()),
2327                inner: locked_range,
2328            })
2329        })
2330    }
2331}
2332
2333#[derive(Debug, Error)]
2334#[error("invalid guest page number {0:#x}")]
2335pub struct InvalidGpn(u64);
2336
2337fn gpn_to_gpa(gpn: u64) -> Result<u64, InvalidGpn> {
2338    gpn.checked_mul(PAGE_SIZE64).ok_or(InvalidGpn(gpn))
2339}
2340
2341#[derive(Debug, Copy, Clone, Default)]
2342struct RegionDefinition {
2343    invalid_mask: u64,
2344    region_mask: u64,
2345    region_bits: u32,
2346}
2347
2348impl RegionDefinition {
2349    fn region(&self, gpa: u64, len: u64) -> Result<(usize, u64), GuestMemoryBackingError> {
2350        if (gpa | len) & self.invalid_mask != 0 {
2351            return Err(GuestMemoryBackingError::new(
2352                GuestMemoryErrorKind::OutOfRange,
2353                gpa,
2354                OutOfRange,
2355            ));
2356        }
2357        let offset = gpa & self.region_mask;
2358        if offset.wrapping_add(len) & !self.region_mask != 0 {
2359            return Err(GuestMemoryBackingError::new(
2360                GuestMemoryErrorKind::OutOfRange,
2361                gpa,
2362                OutOfRange,
2363            ));
2364        }
2365        let index = (gpa >> self.region_bits) as usize;
2366        Ok((index, offset))
2367    }
2368}
2369
2370impl GuestMemoryInner {
2371    fn region(
2372        &self,
2373        gpa: u64,
2374        len: u64,
2375    ) -> Result<(&MemoryRegion, u64, usize), GuestMemoryBackingError> {
2376        let (index, offset) = self.region_def.region(gpa, len)?;
2377        let region = &self.regions[index];
2378        if offset + len > region.len {
2379            return Err(GuestMemoryBackingError::new(
2380                GuestMemoryErrorKind::OutOfRange,
2381                gpa,
2382                OutOfRange,
2383            ));
2384        }
2385        Ok((&self.regions[index], offset, index))
2386    }
2387}
2388
2389pub struct LockedPages {
2390    pages: Box<[PagePtr]>,
2391    gpns: Option<Box<[u64]>>,
2392    // maintain a reference to the backing memory
2393    mem: Arc<GuestMemoryInner>,
2394}
2395
2396impl Drop for LockedPages {
2397    fn drop(&mut self) {
2398        if let Some(gpns) = &self.gpns {
2399            self.mem.imp.unlock_gpns(gpns);
2400        }
2401    }
2402}
2403
2404impl Debug for LockedPages {
2405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2406        f.debug_struct("LockedPages")
2407            .field("page_count", &self.pages.len())
2408            .finish()
2409    }
2410}
2411
2412#[derive(Copy, Clone, Debug)]
2413// Field is read via slice transmute and pointer casts, not actually dead.
2414struct PagePtr(#[expect(dead_code)] *const AtomicU8);
2415
2416// SAFETY: PagePtr is just a pointer with no methods and has no inherent safety
2417// constraints.
2418unsafe impl Send for PagePtr {}
2419// SAFETY: see above comment
2420unsafe impl Sync for PagePtr {}
2421
2422pub type Page = [AtomicU8; PAGE_SIZE];
2423
2424impl LockedPages {
2425    #[inline]
2426    pub fn pages(&self) -> &[&Page] {
2427        // SAFETY: PagePtr is just a pointer to a Page. The pages are kept alive by
2428        // the reference in _mem, and the lifetimes here ensure the LockedPages outlives
2429        // the slice.
2430        unsafe { std::slice::from_raw_parts(self.pages.as_ptr().cast::<&Page>(), self.pages.len()) }
2431    }
2432}
2433
2434impl<'a> AsRef<[&'a Page]> for &'a LockedPages {
2435    fn as_ref(&self) -> &[&'a Page] {
2436        self.pages()
2437    }
2438}
2439
2440/// Represents a range of locked guest pages as an ordered list of the VA sub-ranges
2441/// to which the guest pages are mapped.
2442/// The range may only partially span the first and last page and must fully span all
2443/// intermediate pages.
2444pub trait LockedRange<'a> {
2445    /// Adds a sub-range to this range.
2446    fn push_sub_range(&mut self, sub_range: &'a [AtomicU8]);
2447}
2448
2449pub struct LockedRangeImpl<'a, T: LockedRange<'a>> {
2450    mem: &'a GuestMemoryInner,
2451    gpns: Option<Box<[u64]>>,
2452    inner: T,
2453}
2454
2455impl<'a, T: LockedRange<'a>> LockedRangeImpl<'a, T> {
2456    pub fn get(&self) -> &T {
2457        &self.inner
2458    }
2459
2460    pub fn get_mut(&mut self) -> &mut T {
2461        &mut self.inner
2462    }
2463}
2464
2465impl<'a, T: LockedRange<'a>> Drop for LockedRangeImpl<'a, T> {
2466    fn drop(&mut self) {
2467        if let Some(gpns) = &self.gpns {
2468            self.mem.imp.unlock_gpns(gpns);
2469        }
2470    }
2471}
2472
2473#[derive(Debug, Error)]
2474pub enum AccessError {
2475    #[error("memory access error")]
2476    Memory(#[from] GuestMemoryError),
2477    #[error("out of range: {0:#x} < {1:#x}")]
2478    OutOfRange(usize, usize),
2479    #[error("write attempted to read-only memory")]
2480    ReadOnly,
2481}
2482
2483pub trait MemoryRead {
2484    fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError>;
2485    fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError>;
2486    fn len(&self) -> usize;
2487
2488    fn read_plain<T: IntoBytes + FromBytes + Immutable + KnownLayout>(
2489        &mut self,
2490    ) -> Result<T, AccessError> {
2491        let mut value: T = FromZeros::new_zeroed();
2492        self.read(value.as_mut_bytes())?;
2493        Ok(value)
2494    }
2495
2496    fn read_n<T: IntoBytes + FromBytes + Immutable + KnownLayout + Copy>(
2497        &mut self,
2498        len: usize,
2499    ) -> Result<Vec<T>, AccessError> {
2500        let mut value = vec![FromZeros::new_zeroed(); len];
2501        self.read(value.as_mut_bytes())?;
2502        Ok(value)
2503    }
2504
2505    fn read_all(&mut self) -> Result<Vec<u8>, AccessError> {
2506        let mut value = vec![0; self.len()];
2507        self.read(&mut value)?;
2508        Ok(value)
2509    }
2510
2511    fn limit(self, len: usize) -> Limit<Self>
2512    where
2513        Self: Sized,
2514    {
2515        let len = len.min(self.len());
2516        Limit { inner: self, len }
2517    }
2518}
2519
2520/// A trait for sequentially updating a region of memory.
2521pub trait MemoryWrite {
2522    fn write(&mut self, data: &[u8]) -> Result<(), AccessError>;
2523    fn zero(&mut self, len: usize) -> Result<(), AccessError> {
2524        self.fill(0, len)
2525    }
2526    fn fill(&mut self, val: u8, len: usize) -> Result<(), AccessError>;
2527
2528    /// The space remaining in the memory region.
2529    fn len(&self) -> usize;
2530
2531    fn limit(self, len: usize) -> Limit<Self>
2532    where
2533        Self: Sized,
2534    {
2535        let len = len.min(self.len());
2536        Limit { inner: self, len }
2537    }
2538}
2539
2540impl MemoryRead for &'_ [u8] {
2541    fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError> {
2542        if self.len() < data.len() {
2543            return Err(AccessError::OutOfRange(self.len(), data.len()));
2544        }
2545        let (source, rest) = self.split_at(data.len());
2546        data.copy_from_slice(source);
2547        *self = rest;
2548        Ok(self)
2549    }
2550
2551    fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError> {
2552        if self.len() < len {
2553            return Err(AccessError::OutOfRange(self.len(), len));
2554        }
2555        *self = &self[len..];
2556        Ok(self)
2557    }
2558
2559    fn len(&self) -> usize {
2560        <[u8]>::len(self)
2561    }
2562}
2563
2564impl MemoryWrite for &mut [u8] {
2565    fn write(&mut self, data: &[u8]) -> Result<(), AccessError> {
2566        if self.len() < data.len() {
2567            return Err(AccessError::OutOfRange(self.len(), data.len()));
2568        }
2569        let (dest, rest) = std::mem::take(self).split_at_mut(data.len());
2570        dest.copy_from_slice(data);
2571        *self = rest;
2572        Ok(())
2573    }
2574
2575    fn fill(&mut self, val: u8, len: usize) -> Result<(), AccessError> {
2576        if self.len() < len {
2577            return Err(AccessError::OutOfRange(self.len(), len));
2578        }
2579        let (dest, rest) = std::mem::take(self).split_at_mut(len);
2580        dest.fill(val);
2581        *self = rest;
2582        Ok(())
2583    }
2584
2585    fn len(&self) -> usize {
2586        <[u8]>::len(self)
2587    }
2588}
2589
2590#[derive(Debug, Clone)]
2591pub struct Limit<T> {
2592    inner: T,
2593    len: usize,
2594}
2595
2596impl<T: MemoryRead> MemoryRead for Limit<T> {
2597    fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError> {
2598        let len = data.len();
2599        if len > self.len {
2600            return Err(AccessError::OutOfRange(self.len, len));
2601        }
2602        self.inner.read(data)?;
2603        self.len -= len;
2604        Ok(self)
2605    }
2606
2607    fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError> {
2608        if len > self.len {
2609            return Err(AccessError::OutOfRange(self.len, len));
2610        }
2611        self.inner.skip(len)?;
2612        self.len -= len;
2613        Ok(self)
2614    }
2615
2616    fn len(&self) -> usize {
2617        self.len
2618    }
2619}
2620
2621impl<T: MemoryWrite> MemoryWrite for Limit<T> {
2622    fn write(&mut self, data: &[u8]) -> Result<(), AccessError> {
2623        let len = data.len();
2624        if len > self.len {
2625            return Err(AccessError::OutOfRange(self.len, len));
2626        }
2627        self.inner.write(data)?;
2628        self.len -= len;
2629        Ok(())
2630    }
2631
2632    fn fill(&mut self, val: u8, len: usize) -> Result<(), AccessError> {
2633        if len > self.len {
2634            return Err(AccessError::OutOfRange(self.len, len));
2635        }
2636        self.inner.fill(val, len)?;
2637        self.len -= len;
2638        Ok(())
2639    }
2640
2641    fn len(&self) -> usize {
2642        self.len
2643    }
2644}
2645
2646/// Trait implemented to allow mapping and unmapping a region of memory at
2647/// a particular guest address.
2648pub trait MappableGuestMemory: Send + Sync {
2649    /// Maps the memory into the guest.
2650    ///
2651    /// `writable` specifies whether the guest can write to the memory region.
2652    /// If a guest tries to write to a non-writable region, the virtual
2653    /// processor will exit for MMIO handling.
2654    fn map_to_guest(&mut self, gpa: u64, writable: bool) -> io::Result<()>;
2655
2656    fn unmap_from_guest(&mut self);
2657}
2658
2659/// Trait implemented for a region of memory that can have memory mapped into
2660/// it.
2661pub trait MappedMemoryRegion: Send + Sync {
2662    /// Maps an object at `offset` in the region.
2663    ///
2664    /// Behaves like mmap--overwrites and splits existing mappings.
2665    fn map(
2666        &self,
2667        offset: usize,
2668        section: &dyn AsMappableRef,
2669        file_offset: u64,
2670        len: usize,
2671        writable: bool,
2672    ) -> io::Result<()>;
2673
2674    /// Unmaps any mappings in the specified range within the region.
2675    fn unmap(&self, offset: usize, len: usize) -> io::Result<()>;
2676}
2677
2678/// Trait implemented to allow the creation of memory regions.
2679pub trait MemoryMapper: Send + Sync {
2680    /// Creates a new memory region that can later be mapped into the guest.
2681    ///
2682    /// Returns both an interface for mapping/unmapping the region and for
2683    /// adding internal mappings.
2684    fn new_region(
2685        &self,
2686        len: usize,
2687        debug_name: String,
2688    ) -> io::Result<(Box<dyn MappableGuestMemory>, Arc<dyn MappedMemoryRegion>)>;
2689}
2690
2691/// Doorbell provides a mechanism to register for notifications on writes to specific addresses in guest memory.
2692pub trait DoorbellRegistration: Send + Sync {
2693    /// Register a doorbell event.
2694    fn register_doorbell(
2695        &self,
2696        guest_address: u64,
2697        value: Option<u64>,
2698        length: Option<u32>,
2699        event: &Event,
2700    ) -> io::Result<Box<dyn Send + Sync>>;
2701}
2702
2703/// Trait to map a ROM at one or more locations in guest memory.
2704pub trait MapRom: Send + Sync {
2705    /// Maps the specified portion of the ROM into guest memory at `gpa`.
2706    ///
2707    /// The returned object will implicitly unmap the ROM when dropped.
2708    fn map_rom(&self, gpa: u64, offset: u64, len: u64) -> io::Result<Box<dyn UnmapRom>>;
2709
2710    /// Returns the length of the ROM in bytes.
2711    fn len(&self) -> u64;
2712}
2713
2714/// Trait to unmap a ROM from guest memory.
2715pub trait UnmapRom: Send + Sync {
2716    /// Unmaps the ROM from guest memory.
2717    fn unmap_rom(self);
2718}
2719
2720#[cfg(test)]
2721#[expect(clippy::undocumented_unsafe_blocks)]
2722mod tests {
2723    use crate::GuestMemory;
2724    use crate::PAGE_SIZE64;
2725    use crate::PageFaultAction;
2726    use crate::PageFaultError;
2727
2728    use sparse_mmap::SparseMapping;
2729    use std::ptr::NonNull;
2730    use std::sync::Arc;
2731    use thiserror::Error;
2732
2733    /// An implementation of a GuestMemoryAccess trait that expects all of
2734    /// guest memory to be mapped at a given base, with mmap or the Windows
2735    /// equivalent. Pages that are not backed by RAM will return failure
2736    /// when attempting to access them.
2737    pub struct GuestMemoryMapping {
2738        mapping: SparseMapping,
2739        #[cfg(feature = "bitmap")]
2740        bitmap: Option<Vec<u8>>,
2741    }
2742
2743    unsafe impl crate::GuestMemoryAccess for GuestMemoryMapping {
2744        fn mapping(&self) -> Option<NonNull<u8>> {
2745            NonNull::new(self.mapping.as_ptr().cast())
2746        }
2747
2748        fn max_address(&self) -> u64 {
2749            self.mapping.len() as u64
2750        }
2751
2752        #[cfg(feature = "bitmap")]
2753        fn access_bitmap(&self) -> Option<crate::BitmapInfo> {
2754            self.bitmap.as_ref().map(|bm| crate::BitmapInfo {
2755                read_bitmap: NonNull::new(bm.as_ptr().cast_mut()).unwrap(),
2756                write_bitmap: NonNull::new(bm.as_ptr().cast_mut()).unwrap(),
2757                bit_offset: 0,
2758            })
2759        }
2760    }
2761
2762    const PAGE_SIZE: usize = 4096;
2763    const SIZE_1MB: usize = 1048576;
2764
2765    /// Create a test guest layout:
2766    /// 0           -> 1MB          RAM
2767    /// 1MB         -> 2MB          empty
2768    /// 2MB         -> 3MB          RAM
2769    /// 3MB         -> 3MB + 4K     empty
2770    /// 3MB + 4K    -> 4MB          RAM
2771    fn create_test_mapping() -> GuestMemoryMapping {
2772        let mapping = SparseMapping::new(SIZE_1MB * 4).unwrap();
2773        mapping.alloc(0, SIZE_1MB).unwrap();
2774        mapping.alloc(2 * SIZE_1MB, SIZE_1MB).unwrap();
2775        mapping
2776            .alloc(3 * SIZE_1MB + PAGE_SIZE, SIZE_1MB - PAGE_SIZE)
2777            .unwrap();
2778
2779        GuestMemoryMapping {
2780            mapping,
2781            #[cfg(feature = "bitmap")]
2782            bitmap: None,
2783        }
2784    }
2785
2786    #[test]
2787    fn test_basic_read_write() {
2788        let mapping = create_test_mapping();
2789        let gm = GuestMemory::new("test", mapping);
2790
2791        // Test reading at 0.
2792        let addr = 0;
2793        let result = gm.read_plain::<u8>(addr);
2794        assert_eq!(result.unwrap(), 0);
2795
2796        // Test read/write to first page
2797        let write_buffer = [1, 2, 3, 4, 5];
2798        let mut read_buffer = [0; 5];
2799        gm.write_at(0, &write_buffer).unwrap();
2800        gm.read_at(0, &mut read_buffer).unwrap();
2801        assert_eq!(write_buffer, read_buffer);
2802        assert_eq!(gm.read_plain::<u8>(0).unwrap(), 1);
2803        assert_eq!(gm.read_plain::<u8>(1).unwrap(), 2);
2804        assert_eq!(gm.read_plain::<u8>(2).unwrap(), 3);
2805        assert_eq!(gm.read_plain::<u8>(3).unwrap(), 4);
2806        assert_eq!(gm.read_plain::<u8>(4).unwrap(), 5);
2807
2808        // Test read/write to page at 2MB
2809        let addr = 2 * SIZE_1MB as u64;
2810        let write_buffer: Vec<u8> = (0..PAGE_SIZE).map(|x| x as u8).collect();
2811        let mut read_buffer: Vec<u8> = (0..PAGE_SIZE).map(|_| 0).collect();
2812        gm.write_at(addr, write_buffer.as_slice()).unwrap();
2813        gm.read_at(addr, read_buffer.as_mut_slice()).unwrap();
2814        assert_eq!(write_buffer, read_buffer);
2815
2816        // Test read/write to first 1MB
2817        let write_buffer: Vec<u8> = (0..SIZE_1MB).map(|x| x as u8).collect();
2818        let mut read_buffer: Vec<u8> = (0..SIZE_1MB).map(|_| 0).collect();
2819        gm.write_at(addr, write_buffer.as_slice()).unwrap();
2820        gm.read_at(addr, read_buffer.as_mut_slice()).unwrap();
2821        assert_eq!(write_buffer, read_buffer);
2822
2823        // Test bad read at 1MB
2824        let addr = SIZE_1MB as u64;
2825        let result = gm.read_plain::<u8>(addr);
2826        assert!(result.is_err());
2827    }
2828
2829    #[test]
2830    fn test_multi() {
2831        let len = SIZE_1MB * 4;
2832        let mapping = SparseMapping::new(len).unwrap();
2833        mapping.alloc(0, len).unwrap();
2834        let mapping = Arc::new(GuestMemoryMapping {
2835            mapping,
2836            #[cfg(feature = "bitmap")]
2837            bitmap: None,
2838        });
2839        let region_len = 1 << 30;
2840        let gm = GuestMemory::new_multi_region(
2841            "test",
2842            region_len,
2843            vec![Some(mapping.clone()), None, Some(mapping.clone())],
2844        )
2845        .unwrap();
2846
2847        let mut b = [0];
2848        let len = len as u64;
2849        gm.read_at(0, &mut b).unwrap();
2850        gm.read_at(len, &mut b).unwrap_err();
2851        gm.read_at(region_len, &mut b).unwrap_err();
2852        gm.read_at(2 * region_len, &mut b).unwrap();
2853        gm.read_at(2 * region_len + len, &mut b).unwrap_err();
2854        gm.read_at(3 * region_len, &mut b).unwrap_err();
2855    }
2856
2857    #[cfg(feature = "bitmap")]
2858    #[test]
2859    fn test_bitmap() {
2860        let len = PAGE_SIZE * 4;
2861        let mapping = SparseMapping::new(len).unwrap();
2862        mapping.alloc(0, len).unwrap();
2863        let bitmap = vec![0b0101];
2864        let mapping = Arc::new(GuestMemoryMapping {
2865            mapping,
2866            bitmap: Some(bitmap),
2867        });
2868        let gm = GuestMemory::new("test", mapping);
2869
2870        gm.read_plain::<[u8; 1]>(0).unwrap();
2871        gm.read_plain::<[u8; 1]>(PAGE_SIZE64 - 1).unwrap();
2872        gm.read_plain::<[u8; 2]>(PAGE_SIZE64 - 1).unwrap_err();
2873        gm.read_plain::<[u8; 1]>(PAGE_SIZE64).unwrap_err();
2874        gm.read_plain::<[u8; 1]>(PAGE_SIZE64 * 2).unwrap();
2875        gm.read_plain::<[u8; PAGE_SIZE * 2]>(0).unwrap_err();
2876    }
2877
2878    struct FaultingMapping {
2879        mapping: SparseMapping,
2880    }
2881
2882    #[derive(Debug, Error)]
2883    #[error("fault")]
2884    struct Fault;
2885
2886    unsafe impl crate::GuestMemoryAccess for FaultingMapping {
2887        fn mapping(&self) -> Option<NonNull<u8>> {
2888            NonNull::new(self.mapping.as_ptr().cast())
2889        }
2890
2891        fn max_address(&self) -> u64 {
2892            self.mapping.len() as u64
2893        }
2894
2895        fn page_fault(
2896            &self,
2897            address: u64,
2898            _len: usize,
2899            write: bool,
2900            bitmap_failure: bool,
2901        ) -> PageFaultAction {
2902            assert!(!bitmap_failure);
2903            let qlen = self.mapping.len() as u64 / 4;
2904            if address < qlen || address >= 3 * qlen {
2905                return PageFaultAction::Fail(PageFaultError::other(Fault));
2906            }
2907            let page_address = (address as usize) & !(PAGE_SIZE - 1);
2908            if address >= 2 * qlen {
2909                if write {
2910                    return PageFaultAction::Fail(PageFaultError::other(Fault));
2911                }
2912                self.mapping.map_zero(page_address, PAGE_SIZE).unwrap();
2913            } else {
2914                self.mapping.alloc(page_address, PAGE_SIZE).unwrap();
2915            }
2916            PageFaultAction::Retry
2917        }
2918    }
2919
2920    impl FaultingMapping {
2921        fn new(len: usize) -> Self {
2922            let mapping = SparseMapping::new(len).unwrap();
2923            FaultingMapping { mapping }
2924        }
2925    }
2926
2927    #[test]
2928    fn test_fault() {
2929        let len = PAGE_SIZE * 4;
2930        let mapping = FaultingMapping::new(len);
2931        let gm = GuestMemory::new("test", mapping);
2932
2933        gm.write_plain::<u8>(0, &0).unwrap_err();
2934        gm.read_plain::<u8>(PAGE_SIZE64 - 1).unwrap_err();
2935        gm.read_plain::<u8>(PAGE_SIZE64).unwrap();
2936        gm.write_plain::<u8>(PAGE_SIZE64, &0).unwrap();
2937        gm.write_plain::<u16>(PAGE_SIZE64 * 3 - 1, &0).unwrap_err();
2938        gm.read_plain::<u16>(PAGE_SIZE64 * 3 - 1).unwrap_err();
2939        gm.read_plain::<u8>(PAGE_SIZE64 * 3 - 1).unwrap();
2940        gm.write_plain::<u8>(PAGE_SIZE64 * 3 - 1, &0).unwrap_err();
2941    }
2942
2943    #[cfg(feature = "bitmap")]
2944    #[test]
2945    fn test_zero_length_access_at_offset_zero() {
2946        // Regression test for a fuzzing-reported subtract-with-overflow panic
2947        // in `check_access`: a zero-length access at offset 0 underflowed while
2948        // computing the index of the last accessed page (`offset + len - 1`).
2949        // A zero-length access touches no pages and so must succeed without
2950        // consulting the bitmap, even when the page is marked inaccessible.
2951        let len = PAGE_SIZE * 4;
2952        let mapping = SparseMapping::new(len).unwrap();
2953        mapping.alloc(0, len).unwrap();
2954        let bitmap = vec![0b0000]; // every page marked inaccessible
2955        let mapping = Arc::new(GuestMemoryMapping {
2956            mapping,
2957            bitmap: Some(bitmap),
2958        });
2959        let gm = GuestMemory::new("test", mapping);
2960
2961        // Zero-sized plain accesses reach `check_access` with offset 0 and
2962        // len 0; these previously panicked with "attempt to subtract with
2963        // overflow".
2964        gm.read_plain::<()>(0).unwrap();
2965        gm.write_plain::<()>(0, &()).unwrap();
2966    }
2967
2968    #[test]
2969    fn test_allocated() {
2970        let mut gm = GuestMemory::allocate(0x10000);
2971        let pattern = [0x42; 0x10000];
2972        gm.write_at(0, &pattern).unwrap();
2973        assert_eq!(gm.inner_buf_mut().unwrap(), &pattern);
2974        gm.inner_buf().unwrap();
2975        let gm2 = gm.clone();
2976        assert!(gm.inner_buf_mut().is_none());
2977        gm.inner_buf().unwrap();
2978        let mut gm = gm.into_inner_buf().unwrap_err();
2979        drop(gm2);
2980        assert_eq!(gm.inner_buf_mut().unwrap(), &pattern);
2981        gm.into_inner_buf().unwrap();
2982    }
2983
2984    /// A backing whose locking support can be toggled, used to exercise
2985    /// [`GuestMemory::supports_locking`] aggregation. Backed by a real mapping
2986    /// so it can participate in single- and multi-region construction.
2987    struct ToggleLockMapping {
2988        mapping: SparseMapping,
2989        lockable: bool,
2990    }
2991
2992    impl ToggleLockMapping {
2993        fn new(size: usize, lockable: bool) -> Self {
2994            let mapping = SparseMapping::new(size).unwrap();
2995            mapping.alloc(0, size).unwrap();
2996            Self { mapping, lockable }
2997        }
2998    }
2999
3000    // SAFETY: the mapping is valid for the full range reported by `max_address`.
3001    unsafe impl crate::GuestMemoryAccess for ToggleLockMapping {
3002        fn mapping(&self) -> Option<NonNull<u8>> {
3003            NonNull::new(self.mapping.as_ptr().cast())
3004        }
3005
3006        fn max_address(&self) -> u64 {
3007            self.mapping.len() as u64
3008        }
3009
3010        fn supports_locking(&self) -> bool {
3011            self.lockable
3012        }
3013    }
3014
3015    #[test]
3016    fn test_supports_locking() {
3017        // A mapping-backed backing supports locking by default.
3018        let gm = GuestMemory::allocate(0x10000);
3019        assert!(gm.supports_locking());
3020
3021        // A backing that reports no locking support (e.g. on-demand
3022        // translation behind an emulated IOMMU) does not support locking, and
3023        // `supports_locking` is authoritative: locking fails without touching
3024        // the backing's `lock_gpns`.
3025        let gm = GuestMemory::new("nolock", ToggleLockMapping::new(SIZE_1MB, false));
3026        assert!(!gm.supports_locking());
3027        assert!(gm.lock_gpns(crate::AccessType::Write, false, &[0]).is_err());
3028
3029        // Multi-region: locking is supported only when every present backing
3030        // supports it.
3031        let gm = GuestMemory::new_multi_region(
3032            "multi-lockable",
3033            SIZE_1MB as u64,
3034            vec![
3035                Some(ToggleLockMapping::new(SIZE_1MB / 2, true)),
3036                Some(ToggleLockMapping::new(SIZE_1MB / 2, true)),
3037            ],
3038        )
3039        .unwrap();
3040        assert!(gm.supports_locking());
3041
3042        let gm = GuestMemory::new_multi_region(
3043            "multi-mixed",
3044            SIZE_1MB as u64,
3045            vec![
3046                Some(ToggleLockMapping::new(SIZE_1MB / 2, true)),
3047                Some(ToggleLockMapping::new(SIZE_1MB / 2, false)),
3048            ],
3049        )
3050        .unwrap();
3051        assert!(!gm.supports_locking());
3052    }
3053}