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