1#![expect(unsafe_code)]
8#![expect(missing_docs)]
9
10pub mod ranges;
11
12use self::ranges::PagedRange;
13use inspect::Inspect;
14use pal_event::Event;
15use sparse_mmap::AsMappableRef;
16use std::any::Any;
17use std::fmt::Debug;
18use std::future::Future;
19use std::io;
20use std::ops::Deref;
21use std::ops::DerefMut;
22use std::ops::Range;
23use std::ptr::NonNull;
24use std::sync::Arc;
25use std::sync::atomic::AtomicU8;
26use thiserror::Error;
27use zerocopy::FromBytes;
28use zerocopy::FromZeros;
29use zerocopy::Immutable;
30use zerocopy::IntoBytes;
31use zerocopy::KnownLayout;
32
33pub const PAGE_SIZE: usize = 4096;
35const PAGE_SIZE64: u64 = 4096;
36
37#[derive(Debug, Error)]
39#[error(transparent)]
40pub struct GuestMemoryError(Box<GuestMemoryErrorInner>);
41
42impl GuestMemoryError {
43 fn new(
44 debug_name: &Arc<str>,
45 range: Option<Range<u64>>,
46 op: GuestMemoryOperation,
47 err: GuestMemoryBackingError,
48 ) -> Self {
49 GuestMemoryError(Box::new(GuestMemoryErrorInner {
50 op,
51 debug_name: debug_name.clone(),
52 range,
53 gpa: (err.gpa != INVALID_ERROR_GPA).then_some(err.gpa),
54 kind: err.kind,
55 err: err.err,
56 }))
57 }
58
59 pub fn kind(&self) -> GuestMemoryErrorKind {
61 self.0.kind
62 }
63}
64
65#[derive(Debug, Copy, Clone)]
66enum GuestMemoryOperation {
67 Read,
68 Write,
69 Fill,
70 CompareExchange,
71 Lock,
72 Subrange,
73 Probe,
74}
75
76impl std::fmt::Display for GuestMemoryOperation {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.pad(match self {
79 GuestMemoryOperation::Read => "read",
80 GuestMemoryOperation::Write => "write",
81 GuestMemoryOperation::Fill => "fill",
82 GuestMemoryOperation::CompareExchange => "compare exchange",
83 GuestMemoryOperation::Lock => "lock",
84 GuestMemoryOperation::Subrange => "subrange",
85 GuestMemoryOperation::Probe => "probe",
86 })
87 }
88}
89
90#[derive(Debug, Error)]
91struct GuestMemoryErrorInner {
92 op: GuestMemoryOperation,
93 debug_name: Arc<str>,
94 range: Option<Range<u64>>,
95 gpa: Option<u64>,
96 kind: GuestMemoryErrorKind,
97 #[source]
98 err: Box<dyn std::error::Error + Send + Sync>,
99}
100
101impl std::fmt::Display for GuestMemoryErrorInner {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 write!(
104 f,
105 "guest memory '{debug_name}': {op} error: failed to access ",
106 debug_name = self.debug_name,
107 op = self.op
108 )?;
109 if let Some(range) = &self.range {
110 write!(f, "{:#x}-{:#x}", range.start, range.end)?;
111 } else {
112 f.write_str("memory")?;
113 }
114 if let Some(gpa) = self.gpa {
117 if self.range.as_ref().is_none_or(|range| range.start != gpa) {
118 write!(f, " at {:#x}", gpa)?;
119 }
120 }
121 Ok(())
122 }
123}
124
125#[derive(Debug)]
127pub struct GuestMemoryBackingError {
128 gpa: u64,
129 kind: GuestMemoryErrorKind,
130 err: Box<dyn std::error::Error + Send + Sync>,
131}
132
133#[derive(Debug, Copy, Clone, PartialEq, Eq)]
135#[non_exhaustive]
136pub enum GuestMemoryErrorKind {
137 Other,
139 OutOfRange,
141 VtlProtected,
143 NotPrivate,
145 NotShared,
147}
148
149pub struct PageFaultError {
151 kind: GuestMemoryErrorKind,
152 err: Box<dyn std::error::Error + Send + Sync>,
153}
154
155impl PageFaultError {
156 pub fn new(
158 kind: GuestMemoryErrorKind,
159 err: impl Into<Box<dyn std::error::Error + Send + Sync>>,
160 ) -> Self {
161 Self {
162 kind,
163 err: err.into(),
164 }
165 }
166
167 pub fn other(err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
169 Self::new(GuestMemoryErrorKind::Other, err)
170 }
171}
172
173const INVALID_ERROR_GPA: u64 = !0;
176
177impl GuestMemoryBackingError {
178 pub fn new(
180 kind: GuestMemoryErrorKind,
181 gpa: u64,
182 err: impl Into<Box<dyn std::error::Error + Send + Sync>>,
183 ) -> Self {
184 Self {
188 kind,
189 gpa,
190 err: err.into(),
191 }
192 }
193
194 pub fn other(gpa: u64, err: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
196 Self::new(GuestMemoryErrorKind::Other, gpa, err)
197 }
198
199 fn gpn(err: InvalidGpn) -> Self {
200 Self {
201 kind: GuestMemoryErrorKind::OutOfRange,
202 gpa: INVALID_ERROR_GPA,
203 err: err.into(),
204 }
205 }
206}
207
208#[derive(Debug, Error)]
209#[error("no memory at address")]
210struct OutOfRange;
211
212#[derive(Debug, Error)]
213#[error("memory not lockable")]
214struct NotLockable;
215
216#[derive(Debug, Error)]
217#[error("no fallback for this operation")]
218struct NoFallback;
219
220#[derive(Debug, Error)]
221#[error("the specified page is not mapped")]
222struct NotMapped;
223
224#[derive(Debug, Error)]
225#[error("page inaccessible in bitmap")]
226struct BitmapFailure;
227
228pub trait LinearGuestMemory: GuestMemoryAccess {}
237
238unsafe impl GuestMemoryAccess for sparse_mmap::alloc::SharedMem {
240 fn mapping(&self) -> Option<NonNull<u8>> {
241 NonNull::new(self.as_ptr().cast_mut().cast())
242 }
243
244 fn max_address(&self) -> u64 {
245 self.len() as u64
246 }
247}
248
249impl LinearGuestMemory for sparse_mmap::alloc::SharedMem {}
250
251pub struct AlignedHeapMemory {
253 pages: Box<[AlignedPage]>,
254}
255
256impl Debug for AlignedHeapMemory {
257 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258 f.debug_struct("AlignedHeapMemory")
259 .field("len", &self.len())
260 .finish()
261 }
262}
263
264#[repr(C, align(4096))]
265struct AlignedPage([AtomicU8; PAGE_SIZE]);
266
267impl AlignedHeapMemory {
268 pub fn new(size: usize) -> Self {
270 #[expect(clippy::declare_interior_mutable_const)] const ZERO: AtomicU8 = AtomicU8::new(0);
272 #[expect(clippy::declare_interior_mutable_const)]
273 const ZERO_PAGE: AlignedPage = AlignedPage([ZERO; PAGE_SIZE]);
274 let mut pages = Vec::new();
275 pages.resize_with(size.div_ceil(PAGE_SIZE), || ZERO_PAGE);
276 Self {
277 pages: pages.into(),
278 }
279 }
280
281 pub fn len(&self) -> usize {
283 self.pages.len() * PAGE_SIZE
284 }
285
286 pub fn as_bytes(&mut self) -> &[u8] {
291 self.as_mut()
292 }
293
294 pub fn as_mut_bytes(&mut self) -> &mut [u8] {
296 self.as_mut()
297 }
298}
299
300impl Deref for AlignedHeapMemory {
301 type Target = [AtomicU8];
302
303 fn deref(&self) -> &Self::Target {
304 unsafe { std::slice::from_raw_parts(self.pages.as_ptr().cast(), self.len()) }
306 }
307}
308
309impl DerefMut for AlignedHeapMemory {
310 fn deref_mut(&mut self) -> &mut Self::Target {
311 unsafe { std::slice::from_raw_parts_mut(self.pages.as_mut_ptr().cast(), self.len()) }
313 }
314}
315
316impl AsRef<[AtomicU8]> for AlignedHeapMemory {
317 fn as_ref(&self) -> &[AtomicU8] {
318 self
319 }
320}
321
322impl AsMut<[AtomicU8]> for AlignedHeapMemory {
323 fn as_mut(&mut self) -> &mut [AtomicU8] {
324 self
325 }
326}
327
328impl AsMut<[u8]> for AlignedHeapMemory {
329 fn as_mut(&mut self) -> &mut [u8] {
330 unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr().cast(), self.len()) }
334 }
335}
336
337unsafe impl GuestMemoryAccess for AlignedHeapMemory {
340 fn mapping(&self) -> Option<NonNull<u8>> {
341 NonNull::new(self.pages.as_ptr().cast_mut().cast())
342 }
343
344 fn max_address(&self) -> u64 {
345 (self.pages.len() * PAGE_SIZE) as u64
346 }
347}
348
349impl LinearGuestMemory for AlignedHeapMemory {}
350
351pub struct ShareableRegion {
362 pub guest_address: u64,
364 pub size: u64,
366 pub file: Arc<sparse_mmap::Mappable>,
368 pub file_offset: u64,
370}
371
372pub type ShareableRegionError = Box<dyn std::error::Error + Send + Sync>;
374
375pub struct GuestMemorySharing {
389 inner: Box<dyn DynProvideShareableRegions>,
390}
391
392impl GuestMemorySharing {
393 pub fn new(inner: impl ProvideShareableRegions + 'static) -> Self {
396 Self {
397 inner: Box::new(inner),
398 }
399 }
400
401 pub async fn get_regions(&self) -> Result<Vec<ShareableRegion>, ShareableRegionError> {
403 self.inner.get_regions().await
404 }
405}
406
407pub trait ProvideShareableRegions: Send + Sync {
418 fn get_regions(
420 &self,
421 ) -> impl Future<Output = Result<Vec<ShareableRegion>, ShareableRegionError>> + Send + '_;
422}
423
424trait DynProvideShareableRegions: Send + Sync {
426 fn get_regions(
427 &self,
428 ) -> std::pin::Pin<
429 Box<dyn Future<Output = Result<Vec<ShareableRegion>, ShareableRegionError>> + Send + '_>,
430 >;
431}
432
433impl<T: ProvideShareableRegions> DynProvideShareableRegions for T {
434 fn get_regions(
435 &self,
436 ) -> std::pin::Pin<
437 Box<dyn Future<Output = Result<Vec<ShareableRegion>, ShareableRegionError>> + Send + '_>,
438 > {
439 Box::pin(ProvideShareableRegions::get_regions(self))
440 }
441}
442
443pub unsafe trait GuestMemoryAccess: 'static + Send + Sync {
459 fn mapping(&self) -> Option<NonNull<u8>>;
466
467 fn max_address(&self) -> u64;
470
471 #[cfg(feature = "bitmap")]
489 fn access_bitmap(&self) -> Option<BitmapInfo> {
490 None
491 }
492
493 fn subrange(
496 &self,
497 offset: u64,
498 len: u64,
499 allow_preemptive_locking: bool,
500 ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
501 let _ = (offset, len, allow_preemptive_locking);
502 Ok(None)
503 }
504
505 fn page_fault(
515 &self,
516 address: u64,
517 len: usize,
518 write: bool,
519 bitmap_failure: bool,
520 ) -> PageFaultAction {
521 let _ = (address, len, write);
522 let err = if bitmap_failure {
523 PageFaultError::other(BitmapFailure)
524 } else {
525 PageFaultError::other(NotMapped)
526 };
527 PageFaultAction::Fail(err)
528 }
529
530 unsafe fn read_fallback(
543 &self,
544 addr: u64,
545 dest: *mut u8,
546 len: usize,
547 ) -> Result<(), GuestMemoryBackingError> {
548 let _ = (dest, len);
549 Err(GuestMemoryBackingError::other(addr, NoFallback))
550 }
551
552 unsafe fn write_fallback(
562 &self,
563 addr: u64,
564 src: *const u8,
565 len: usize,
566 ) -> Result<(), GuestMemoryBackingError> {
567 let _ = (src, len);
568 Err(GuestMemoryBackingError::other(addr, NoFallback))
569 }
570
571 fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
576 let _ = (val, len);
577 Err(GuestMemoryBackingError::other(addr, NoFallback))
578 }
579
580 fn compare_exchange_fallback(
587 &self,
588 addr: u64,
589 current: &mut [u8],
590 new: &[u8],
591 ) -> Result<bool, GuestMemoryBackingError> {
592 let _ = (current, new);
593 Err(GuestMemoryBackingError::other(addr, NoFallback))
594 }
595
596 fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
602 let _ = (address, len);
603 Ok(())
604 }
605
606 fn base_iova(&self) -> Option<u64> {
612 None
613 }
614
615 fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError> {
620 let _ = gpns;
621 Ok(false)
622 }
623
624 fn unlock_gpns(&self, gpns: &[u64]) {
630 let _ = gpns;
631 }
632
633 fn sharing(&self) -> Option<GuestMemorySharing> {
639 None
640 }
641
642 fn supports_locking(&self) -> bool {
656 self.mapping().is_some()
657 }
658}
659
660trait DynGuestMemoryAccess: 'static + Send + Sync + Any {
661 fn subrange(
662 &self,
663 offset: u64,
664 len: u64,
665 allow_preemptive_locking: bool,
666 ) -> Result<Option<GuestMemory>, GuestMemoryBackingError>;
667
668 fn page_fault(
669 &self,
670 address: u64,
671 len: usize,
672 write: bool,
673 bitmap_failure: bool,
674 ) -> PageFaultAction;
675
676 unsafe fn read_fallback(
679 &self,
680 addr: u64,
681 dest: *mut u8,
682 len: usize,
683 ) -> Result<(), GuestMemoryBackingError>;
684
685 unsafe fn write_fallback(
688 &self,
689 addr: u64,
690 src: *const u8,
691 len: usize,
692 ) -> Result<(), GuestMemoryBackingError>;
693
694 fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError>;
695
696 fn compare_exchange_fallback(
697 &self,
698 addr: u64,
699 current: &mut [u8],
700 new: &[u8],
701 ) -> Result<bool, GuestMemoryBackingError>;
702
703 fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError>;
704
705 fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError>;
706
707 fn unlock_gpns(&self, gpns: &[u64]);
708
709 fn sharing(&self) -> Option<GuestMemorySharing>;
710}
711
712impl<T: GuestMemoryAccess> DynGuestMemoryAccess for T {
713 fn subrange(
714 &self,
715 offset: u64,
716 len: u64,
717 allow_preemptive_locking: bool,
718 ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
719 self.subrange(offset, len, allow_preemptive_locking)
720 }
721
722 fn page_fault(
723 &self,
724 address: u64,
725 len: usize,
726 write: bool,
727 bitmap_failure: bool,
728 ) -> PageFaultAction {
729 self.page_fault(address, len, write, bitmap_failure)
730 }
731
732 unsafe fn read_fallback(
733 &self,
734 addr: u64,
735 dest: *mut u8,
736 len: usize,
737 ) -> Result<(), GuestMemoryBackingError> {
738 unsafe { self.read_fallback(addr, dest, len) }
740 }
741
742 unsafe fn write_fallback(
743 &self,
744 addr: u64,
745 src: *const u8,
746 len: usize,
747 ) -> Result<(), GuestMemoryBackingError> {
748 unsafe { self.write_fallback(addr, src, len) }
750 }
751
752 fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
753 self.fill_fallback(addr, val, len)
754 }
755
756 fn compare_exchange_fallback(
757 &self,
758 addr: u64,
759 current: &mut [u8],
760 new: &[u8],
761 ) -> Result<bool, GuestMemoryBackingError> {
762 self.compare_exchange_fallback(addr, current, new)
763 }
764
765 fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
766 self.expose_va(address, len)
767 }
768
769 fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError> {
770 self.lock_gpns(gpns)
771 }
772
773 fn unlock_gpns(&self, gpns: &[u64]) {
774 self.unlock_gpns(gpns)
775 }
776
777 fn sharing(&self) -> Option<GuestMemorySharing> {
778 self.sharing()
779 }
780}
781
782pub enum PageFaultAction {
785 Fail(PageFaultError),
787 Retry,
789 Fallback,
791}
792
793#[cfg(feature = "bitmap")]
795pub struct BitmapInfo {
796 pub read_bitmap: NonNull<u8>,
798 pub write_bitmap: NonNull<u8>,
800 pub bit_offset: u8,
805}
806
807unsafe impl<T: GuestMemoryAccess> GuestMemoryAccess for Arc<T> {
809 fn mapping(&self) -> Option<NonNull<u8>> {
810 self.as_ref().mapping()
811 }
812
813 fn max_address(&self) -> u64 {
814 self.as_ref().max_address()
815 }
816
817 #[cfg(feature = "bitmap")]
818 fn access_bitmap(&self) -> Option<BitmapInfo> {
819 self.as_ref().access_bitmap()
820 }
821
822 fn subrange(
823 &self,
824 offset: u64,
825 len: u64,
826 allow_preemptive_locking: bool,
827 ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
828 self.as_ref()
829 .subrange(offset, len, allow_preemptive_locking)
830 }
831
832 fn page_fault(
833 &self,
834 addr: u64,
835 len: usize,
836 write: bool,
837 bitmap_failure: bool,
838 ) -> PageFaultAction {
839 self.as_ref().page_fault(addr, len, write, bitmap_failure)
840 }
841
842 unsafe fn read_fallback(
843 &self,
844 addr: u64,
845 dest: *mut u8,
846 len: usize,
847 ) -> Result<(), GuestMemoryBackingError> {
848 unsafe { self.as_ref().read_fallback(addr, dest, len) }
850 }
851
852 unsafe fn write_fallback(
853 &self,
854 addr: u64,
855 src: *const u8,
856 len: usize,
857 ) -> Result<(), GuestMemoryBackingError> {
858 unsafe { self.as_ref().write_fallback(addr, src, len) }
860 }
861
862 fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
863 self.as_ref().fill_fallback(addr, val, len)
864 }
865
866 fn compare_exchange_fallback(
867 &self,
868 addr: u64,
869 current: &mut [u8],
870 new: &[u8],
871 ) -> Result<bool, GuestMemoryBackingError> {
872 self.as_ref().compare_exchange_fallback(addr, current, new)
873 }
874
875 fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
876 self.as_ref().expose_va(address, len)
877 }
878
879 fn base_iova(&self) -> Option<u64> {
880 self.as_ref().base_iova()
881 }
882
883 fn sharing(&self) -> Option<GuestMemorySharing> {
884 self.as_ref().sharing()
885 }
886}
887
888unsafe impl GuestMemoryAccess for sparse_mmap::SparseMapping {
890 fn mapping(&self) -> Option<NonNull<u8>> {
891 NonNull::new(self.as_ptr().cast())
892 }
893
894 fn max_address(&self) -> u64 {
895 self.len() as u64
896 }
897}
898
899struct GuestMemoryAccessRange {
901 base: Arc<GuestMemoryInner>,
902 offset: u64,
903 len: u64,
904 region: usize,
905}
906
907impl GuestMemoryAccessRange {
908 fn adjust_range(&self, address: u64, len: u64) -> Result<u64, GuestMemoryBackingError> {
909 if address <= self.len && len <= self.len - address {
910 Ok(self.offset + address)
911 } else {
912 Err(GuestMemoryBackingError::new(
913 GuestMemoryErrorKind::OutOfRange,
914 address,
915 OutOfRange,
916 ))
917 }
918 }
919}
920
921unsafe impl GuestMemoryAccess for GuestMemoryAccessRange {
923 fn mapping(&self) -> Option<NonNull<u8>> {
924 let region = &self.base.regions[self.region];
925 region.mapping.and_then(|mapping| {
926 let offset = self.offset & self.base.region_def.region_mask;
927 assert!(region.len >= offset + self.len);
929 NonNull::new(unsafe { mapping.0.as_ptr().add(offset as usize) })
932 })
933 }
934
935 fn max_address(&self) -> u64 {
936 self.len
937 }
938
939 #[cfg(feature = "bitmap")]
940 fn access_bitmap(&self) -> Option<BitmapInfo> {
941 let region = &self.base.regions[self.region];
942 region.bitmaps.map(|bitmaps| {
943 let offset = self.offset & self.base.region_def.region_mask;
944 let bit_offset = region.bitmap_start as u64 + offset / PAGE_SIZE64;
945 let [read_bitmap, write_bitmap] = bitmaps.map(|SendPtrU8(ptr)| {
946 NonNull::new(unsafe { ptr.as_ptr().add((bit_offset / 8) as usize) }).unwrap()
949 });
950 let bitmap_start = (bit_offset % 8) as u8;
951 BitmapInfo {
952 read_bitmap,
953 write_bitmap,
954 bit_offset: bitmap_start,
955 }
956 })
957 }
958
959 fn subrange(
960 &self,
961 offset: u64,
962 len: u64,
963 _allow_preemptive_locking: bool,
964 ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
965 let address = self.adjust_range(offset, len)?;
966 Ok(Some(GuestMemory::new(
967 self.base.debug_name.clone(),
968 GuestMemoryAccessRange {
969 base: self.base.clone(),
970 offset: address,
971 len,
972 region: self.region,
973 },
974 )))
975 }
976
977 fn page_fault(
978 &self,
979 address: u64,
980 len: usize,
981 write: bool,
982 bitmap_failure: bool,
983 ) -> PageFaultAction {
984 let address = self
985 .adjust_range(address, len as u64)
986 .expect("the caller should have validated the range was in the mapping");
987
988 self.base
989 .imp
990 .page_fault(address, len, write, bitmap_failure)
991 }
992
993 unsafe fn write_fallback(
994 &self,
995 address: u64,
996 src: *const u8,
997 len: usize,
998 ) -> Result<(), GuestMemoryBackingError> {
999 let address = self.adjust_range(address, len as u64)?;
1000 unsafe { self.base.imp.write_fallback(address, src, len) }
1002 }
1003
1004 fn fill_fallback(
1005 &self,
1006 address: u64,
1007 val: u8,
1008 len: usize,
1009 ) -> Result<(), GuestMemoryBackingError> {
1010 let address = self.adjust_range(address, len as u64)?;
1011 self.base.imp.fill_fallback(address, val, len)
1012 }
1013
1014 fn compare_exchange_fallback(
1015 &self,
1016 addr: u64,
1017 current: &mut [u8],
1018 new: &[u8],
1019 ) -> Result<bool, GuestMemoryBackingError> {
1020 let address = self.adjust_range(addr, new.len() as u64)?;
1021 self.base
1022 .imp
1023 .compare_exchange_fallback(address, current, new)
1024 }
1025
1026 unsafe fn read_fallback(
1027 &self,
1028 address: u64,
1029 dest: *mut u8,
1030 len: usize,
1031 ) -> Result<(), GuestMemoryBackingError> {
1032 let address = self.adjust_range(address, len as u64)?;
1033 unsafe { self.base.imp.read_fallback(address, dest, len) }
1035 }
1036
1037 fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
1038 let address = self.adjust_range(address, len)?;
1039 self.base.imp.expose_va(address, len)
1040 }
1041
1042 fn base_iova(&self) -> Option<u64> {
1043 let region = &self.base.regions[self.region];
1044 Some(region.base_iova? + (self.offset & self.base.region_def.region_mask))
1045 }
1046}
1047
1048fn create_memory_subrange(
1051 base: Arc<GuestMemoryInner>,
1052 offset: u64,
1053 len: u64,
1054 _allow_preemptive_locking: bool,
1055) -> Result<GuestMemory, GuestMemoryBackingError> {
1056 let (_, _, region) = base.region(offset, len)?;
1057 Ok(GuestMemory::new(
1058 base.debug_name.clone(),
1059 GuestMemoryAccessRange {
1060 base,
1061 offset,
1062 len,
1063 region,
1064 },
1065 ))
1066}
1067
1068struct MultiRegionGuestMemoryAccess<T> {
1069 imps: Vec<Option<T>>,
1070 region_def: RegionDefinition,
1071}
1072
1073impl<T> MultiRegionGuestMemoryAccess<T> {
1074 fn region(&self, gpa: u64, len: u64) -> Result<(&T, u64), GuestMemoryBackingError> {
1075 let (i, offset) = self.region_def.region(gpa, len)?;
1076 let imp = self.imps[i].as_ref().ok_or(GuestMemoryBackingError::new(
1077 GuestMemoryErrorKind::OutOfRange,
1078 gpa,
1079 OutOfRange,
1080 ))?;
1081 Ok((imp, offset))
1082 }
1083}
1084
1085impl<T: GuestMemoryAccess> DynGuestMemoryAccess for MultiRegionGuestMemoryAccess<T> {
1087 fn subrange(
1088 &self,
1089 offset: u64,
1090 len: u64,
1091 allow_preemptive_locking: bool,
1092 ) -> Result<Option<GuestMemory>, GuestMemoryBackingError> {
1093 let (region, offset_in_region) = self.region(offset, len)?;
1094 region.subrange(offset_in_region, len, allow_preemptive_locking)
1095 }
1096
1097 unsafe fn read_fallback(
1098 &self,
1099 addr: u64,
1100 dest: *mut u8,
1101 len: usize,
1102 ) -> Result<(), GuestMemoryBackingError> {
1103 let (region, offset_in_region) = self.region(addr, len as u64)?;
1104 unsafe { region.read_fallback(offset_in_region, dest, len) }
1106 }
1107
1108 unsafe fn write_fallback(
1109 &self,
1110 addr: u64,
1111 src: *const u8,
1112 len: usize,
1113 ) -> Result<(), GuestMemoryBackingError> {
1114 let (region, offset_in_region) = self.region(addr, len as u64)?;
1115 unsafe { region.write_fallback(offset_in_region, src, len) }
1117 }
1118
1119 fn fill_fallback(&self, addr: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
1120 let (region, offset_in_region) = self.region(addr, len as u64)?;
1121 region.fill_fallback(offset_in_region, val, len)
1122 }
1123
1124 fn compare_exchange_fallback(
1125 &self,
1126 addr: u64,
1127 current: &mut [u8],
1128 new: &[u8],
1129 ) -> Result<bool, GuestMemoryBackingError> {
1130 let (region, offset_in_region) = self.region(addr, new.len() as u64)?;
1131 region.compare_exchange_fallback(offset_in_region, current, new)
1132 }
1133
1134 fn expose_va(&self, address: u64, len: u64) -> Result<(), GuestMemoryBackingError> {
1135 let (region, offset_in_region) = self.region(address, len)?;
1136 region.expose_va(offset_in_region, len)
1137 }
1138
1139 fn page_fault(
1140 &self,
1141 address: u64,
1142 len: usize,
1143 write: bool,
1144 bitmap_failure: bool,
1145 ) -> PageFaultAction {
1146 match self.region(address, len as u64) {
1147 Ok((region, offset_in_region)) => {
1148 region.page_fault(offset_in_region, len, write, bitmap_failure)
1149 }
1150 Err(err) => PageFaultAction::Fail(PageFaultError {
1151 kind: err.kind,
1152 err: err.err,
1153 }),
1154 }
1155 }
1156
1157 fn lock_gpns(&self, gpns: &[u64]) -> Result<bool, GuestMemoryBackingError> {
1158 let mut ret = false;
1159 for gpn in gpns {
1160 let (region, offset_in_region) = self.region(gpn * PAGE_SIZE64, PAGE_SIZE64)?;
1161 ret |= region.lock_gpns(&[offset_in_region / PAGE_SIZE64])?;
1162 }
1163 Ok(ret)
1164 }
1165
1166 fn unlock_gpns(&self, gpns: &[u64]) {
1167 for gpn in gpns {
1168 let (region, offset_in_region) = self.region(gpn * PAGE_SIZE64, PAGE_SIZE64).unwrap();
1169 region.unlock_gpns(&[offset_in_region / PAGE_SIZE64]);
1170 }
1171 }
1172
1173 fn sharing(&self) -> Option<GuestMemorySharing> {
1174 None
1180 }
1181}
1182
1183#[derive(Debug, Clone, Inspect)]
1189#[inspect(skip)]
1190pub struct GuestMemory {
1191 inner: Arc<GuestMemoryInner>,
1192}
1193
1194struct GuestMemoryInner<T: ?Sized = dyn DynGuestMemoryAccess> {
1195 region_def: RegionDefinition,
1196 regions: Vec<MemoryRegion>,
1197 debug_name: Arc<str>,
1198 allocated: bool,
1199 supports_locking: bool,
1202 imp: T,
1203}
1204
1205impl<T: ?Sized> Debug for GuestMemoryInner<T> {
1206 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1207 f.debug_struct("GuestMemoryInner")
1208 .field("region_def", &self.region_def)
1209 .field("regions", &self.regions)
1210 .finish()
1211 }
1212}
1213
1214#[derive(Debug, Copy, Clone, Default)]
1215struct MemoryRegion {
1216 mapping: Option<SendPtrU8>,
1217 #[cfg(feature = "bitmap")]
1218 bitmaps: Option<[SendPtrU8; 2]>,
1219 #[cfg(feature = "bitmap")]
1220 bitmap_start: u8,
1221 len: u64,
1222 base_iova: Option<u64>,
1223}
1224
1225#[derive(Debug, Copy, Clone, PartialEq, Eq)]
1230pub enum AccessType {
1231 Read = 0,
1233 Write = 1,
1235}
1236
1237#[derive(Debug, Copy, Clone)]
1249struct SendPtrU8(NonNull<u8>);
1250
1251unsafe impl Send for SendPtrU8 {}
1253unsafe impl Sync for SendPtrU8 {}
1255
1256impl MemoryRegion {
1257 fn new(imp: &impl GuestMemoryAccess) -> Self {
1258 #[cfg(feature = "bitmap")]
1259 let (bitmaps, bitmap_start) = {
1260 let bitmap_info = imp.access_bitmap();
1261 let bitmaps = bitmap_info
1262 .as_ref()
1263 .map(|bm| [SendPtrU8(bm.read_bitmap), SendPtrU8(bm.write_bitmap)]);
1264 let bitmap_start = bitmap_info.map_or(0, |bi| bi.bit_offset);
1265 (bitmaps, bitmap_start)
1266 };
1267 Self {
1268 mapping: imp.mapping().map(SendPtrU8),
1269 #[cfg(feature = "bitmap")]
1270 bitmaps,
1271 #[cfg(feature = "bitmap")]
1272 bitmap_start,
1273 len: imp.max_address(),
1274 base_iova: imp.base_iova(),
1275 }
1276 }
1277
1278 unsafe fn check_access(
1284 &self,
1285 access_type: AccessType,
1286 offset: u64,
1287 len: u64,
1288 ) -> Result<(), u64> {
1289 debug_assert!(self.len >= offset + len);
1290 #[cfg(not(feature = "bitmap"))]
1291 let _ = access_type;
1292
1293 #[cfg(feature = "bitmap")]
1294 if len == 0 {
1295 return Ok(());
1296 } else if let Some(bitmaps) = &self.bitmaps {
1297 let SendPtrU8(bitmap) = bitmaps[access_type as usize];
1298 let start = offset / PAGE_SIZE64;
1299 let end = (offset + len - 1) / PAGE_SIZE64;
1300 for gpn in start..=end {
1303 let bit_offset = self.bitmap_start as u64 + gpn;
1304 let bit = unsafe {
1307 (*bitmap
1308 .as_ptr()
1309 .cast_const()
1310 .cast::<AtomicU8>()
1311 .add(bit_offset as usize / 8))
1312 .load(std::sync::atomic::Ordering::Relaxed)
1313 & (1 << (bit_offset % 8))
1314 };
1315 if bit == 0 {
1316 return Err((gpn * PAGE_SIZE64).saturating_sub(offset));
1317 }
1318 }
1319 }
1320
1321 Ok(())
1322 }
1323}
1324
1325impl Default for GuestMemory {
1327 fn default() -> Self {
1328 Self::empty()
1329 }
1330}
1331
1332struct Empty;
1333
1334unsafe impl GuestMemoryAccess for Empty {
1336 fn mapping(&self) -> Option<NonNull<u8>> {
1337 None
1338 }
1339
1340 fn max_address(&self) -> u64 {
1341 0
1342 }
1343
1344 fn supports_locking(&self) -> bool {
1345 true
1348 }
1349}
1350
1351#[derive(Debug, Error)]
1352pub enum MultiRegionError {
1353 #[error("region size {0:#x} is not a power of 2")]
1354 NotPowerOfTwo(u64),
1355 #[error("region size {0:#x} is smaller than a page")]
1356 RegionSizeTooSmall(u64),
1357 #[error(
1358 "too many regions ({region_count}) for region size {region_size:#x}; max is {max_region_count}"
1359 )]
1360 TooManyRegions {
1361 region_count: usize,
1362 max_region_count: usize,
1363 region_size: u64,
1364 },
1365 #[error("backing size {backing_size:#x} is too large for region size {region_size:#x}")]
1366 BackingTooLarge { backing_size: u64, region_size: u64 },
1367}
1368
1369#[cfg(feature = "bitmap")]
1377pub fn rcu() -> minircu::RcuDomain {
1378 minircu::global()
1380}
1381
1382impl GuestMemory {
1383 pub fn new(debug_name: impl Into<Arc<str>>, imp: impl GuestMemoryAccess) -> Self {
1388 if imp.mapping().is_some() && !cfg!(miri) {
1393 trycopy::initialize_try_copy();
1394 }
1395 Self::new_inner(debug_name.into(), imp, false)
1396 }
1397
1398 fn new_inner(debug_name: Arc<str>, imp: impl GuestMemoryAccess, allocated: bool) -> Self {
1399 let regions = vec![MemoryRegion::new(&imp)];
1400 let supports_locking = imp.supports_locking();
1401 Self {
1402 inner: Arc::new(GuestMemoryInner {
1403 imp,
1404 debug_name,
1405 region_def: RegionDefinition {
1406 invalid_mask: 1 << 63,
1407 region_mask: !0 >> 1,
1408 region_bits: 63, },
1410 regions,
1411 allocated,
1412 supports_locking,
1413 }),
1414 }
1415 }
1416
1417 pub fn new_multi_region(
1433 debug_name: impl Into<Arc<str>>,
1434 region_size: u64,
1435 mut imps: Vec<Option<impl GuestMemoryAccess>>,
1436 ) -> Result<Self, MultiRegionError> {
1437 trycopy::initialize_try_copy();
1439
1440 if !region_size.is_power_of_two() {
1441 return Err(MultiRegionError::NotPowerOfTwo(region_size));
1442 }
1443 if region_size < PAGE_SIZE64 {
1444 return Err(MultiRegionError::RegionSizeTooSmall(region_size));
1445 }
1446 let region_bits = region_size.trailing_zeros();
1447
1448 let max_region_count = 1 << (63 - region_bits);
1449
1450 let region_count = imps.len().next_power_of_two();
1451 if region_count > max_region_count {
1452 return Err(MultiRegionError::TooManyRegions {
1453 region_count,
1454 max_region_count,
1455 region_size,
1456 });
1457 }
1458
1459 let valid_bits = region_bits + region_count.trailing_zeros();
1460 assert!(valid_bits < 64);
1461 let invalid_mask = !0 << valid_bits;
1462
1463 let mut regions = vec![MemoryRegion::default(); region_count];
1464 for (imp, region) in imps.iter().zip(&mut regions) {
1465 let Some(imp) = imp else { continue };
1466 let backing_size = imp.max_address();
1467 if backing_size > region_size {
1468 return Err(MultiRegionError::BackingTooLarge {
1469 backing_size,
1470 region_size,
1471 });
1472 }
1473 *region = MemoryRegion::new(imp);
1474 }
1475
1476 let region_def = RegionDefinition {
1477 invalid_mask,
1478 region_mask: region_size - 1,
1479 region_bits,
1480 };
1481
1482 imps.resize_with(region_count, || None);
1483 let supports_locking = imps
1485 .iter()
1486 .flatten()
1487 .all(GuestMemoryAccess::supports_locking);
1488 let imp = MultiRegionGuestMemoryAccess { imps, region_def };
1489
1490 let inner = GuestMemoryInner {
1491 debug_name: debug_name.into(),
1492 region_def,
1493 regions,
1494 imp,
1495 allocated: false,
1496 supports_locking,
1497 };
1498
1499 Ok(Self {
1500 inner: Arc::new(inner),
1501 })
1502 }
1503
1504 pub fn allocate(size: usize) -> Self {
1514 Self::new_inner("heap".into(), AlignedHeapMemory::new(size), true)
1515 }
1516
1517 pub fn into_inner_buf(self) -> Result<AlignedHeapMemory, Self> {
1523 if !self.inner.allocated {
1524 return Err(self);
1525 }
1526 let inner = unsafe {
1529 Arc::<GuestMemoryInner<AlignedHeapMemory>>::from_raw(Arc::into_raw(self.inner).cast())
1530 };
1531 let inner = Arc::try_unwrap(inner).map_err(|inner| Self { inner })?;
1532 Ok(inner.imp)
1533 }
1534
1535 pub fn inner_buf(&self) -> Option<&[AtomicU8]> {
1538 if !self.inner.allocated {
1539 return None;
1540 }
1541 let inner = unsafe { &*core::ptr::from_ref(&self.inner.imp).cast::<AlignedHeapMemory>() };
1544 Some(inner)
1545 }
1546
1547 pub fn inner_buf_mut(&mut self) -> Option<&mut [u8]> {
1551 if !self.inner.allocated {
1552 return None;
1553 }
1554 let inner = Arc::get_mut(&mut self.inner)?;
1555 let imp = unsafe { &mut *core::ptr::from_mut(&mut inner.imp).cast::<AlignedHeapMemory>() };
1558 Some(imp.as_mut())
1559 }
1560
1561 pub fn empty() -> Self {
1563 GuestMemory::new("empty", Empty)
1564 }
1565
1566 fn wrap_err(
1567 &self,
1568 gpa_len: Option<(u64, u64)>,
1569 op: GuestMemoryOperation,
1570 err: GuestMemoryBackingError,
1571 ) -> GuestMemoryError {
1572 let range = gpa_len.map(|(gpa, len)| gpa..gpa.wrapping_add(len));
1573 GuestMemoryError::new(&self.inner.debug_name, range, op, err)
1574 }
1575
1576 fn with_op<T>(
1577 &self,
1578 gpa_len: Option<(u64, u64)>,
1579 op: GuestMemoryOperation,
1580 f: impl FnOnce() -> Result<T, GuestMemoryBackingError>,
1581 ) -> Result<T, GuestMemoryError> {
1582 f().map_err(|err| self.wrap_err(gpa_len, op, err))
1583 }
1584
1585 pub fn subrange(
1590 &self,
1591 offset: u64,
1592 len: u64,
1593 allow_preemptive_locking: bool,
1594 ) -> Result<GuestMemory, GuestMemoryError> {
1595 self.with_op(Some((offset, len)), GuestMemoryOperation::Subrange, || {
1596 if let Some(guest_memory) =
1597 self.inner
1598 .imp
1599 .subrange(offset, len, allow_preemptive_locking)?
1600 {
1601 Ok(guest_memory)
1602 } else {
1603 create_memory_subrange(self.inner.clone(), offset, len, allow_preemptive_locking)
1604 }
1605 })
1606 }
1607
1608 pub fn lockable_subrange(
1610 &self,
1611 offset: u64,
1612 len: u64,
1613 ) -> Result<GuestMemory, GuestMemoryError> {
1614 self.subrange(offset, len, true)
1616 }
1617
1618 pub fn full_mapping(&self) -> Option<(*mut u8, usize)> {
1623 if let [region] = self.inner.regions.as_slice() {
1624 #[cfg(feature = "bitmap")]
1625 if region.bitmaps.is_some() {
1626 return None;
1627 }
1628 region
1629 .mapping
1630 .map(|SendPtrU8(ptr)| (ptr.as_ptr(), region.len as usize))
1631 } else {
1632 None
1633 }
1634 }
1635
1636 pub fn iova(&self, gpa: u64) -> Option<u64> {
1639 let (region, offset, _) = self.inner.region(gpa, 1).ok()?;
1640 Some(region.base_iova? + offset)
1641 }
1642
1643 pub fn sharing(&self) -> Option<GuestMemorySharing> {
1646 self.inner.imp.sharing()
1647 }
1648
1649 pub fn supports_locking(&self) -> bool {
1658 self.inner.supports_locking
1659 }
1660
1661 fn mapping_range(
1666 &self,
1667 access_type: AccessType,
1668 gpa: u64,
1669 len: usize,
1670 ) -> Result<Option<*mut u8>, GuestMemoryBackingError> {
1671 let (region, offset, _) = self.inner.region(gpa, len as u64)?;
1672 if let Some(SendPtrU8(ptr)) = region.mapping {
1673 loop {
1674 let fault_offset = unsafe {
1676 match region.check_access(access_type, offset, len as u64) {
1677 Ok(()) => return Ok(Some(ptr.as_ptr().add(offset as usize))),
1678 Err(n) => n,
1679 }
1680 };
1681
1682 match self.inner.imp.page_fault(
1684 gpa + fault_offset,
1685 len - fault_offset as usize,
1686 access_type == AccessType::Write,
1687 true,
1688 ) {
1689 PageFaultAction::Fail(err) => {
1690 return Err(GuestMemoryBackingError::new(
1691 err.kind,
1692 gpa + fault_offset,
1693 err.err,
1694 ));
1695 }
1696 PageFaultAction::Retry => {}
1697 PageFaultAction::Fallback => break,
1698 }
1699 }
1700 }
1701 Ok(None)
1702 }
1703
1704 fn run_on_mapping<T, P>(
1711 &self,
1712 access_type: AccessType,
1713 gpa: u64,
1714 len: usize,
1715 mut param: P,
1716 mut f: impl FnMut(&mut P, *mut u8) -> Result<T, trycopy::MemoryError>,
1717 fallback: impl FnOnce(&mut P) -> Result<T, GuestMemoryBackingError>,
1718 ) -> Result<T, GuestMemoryBackingError> {
1719 let op = || {
1720 let Some(mapping) = self.mapping_range(access_type, gpa, len)? else {
1721 return fallback(&mut param);
1722 };
1723
1724 loop {
1726 match f(&mut param, mapping) {
1727 Ok(t) => return Ok(t),
1728 Err(fault) => {
1729 match self.inner.imp.page_fault(
1730 gpa + fault.offset() as u64,
1731 len - fault.offset(),
1732 access_type == AccessType::Write,
1733 false,
1734 ) {
1735 PageFaultAction::Fail(err) => {
1736 return Err(GuestMemoryBackingError::new(
1737 err.kind,
1738 gpa + fault.offset() as u64,
1739 err.err,
1740 ));
1741 }
1742 PageFaultAction::Retry => {}
1743 PageFaultAction::Fallback => return fallback(&mut param),
1744 }
1745 }
1746 }
1747 }
1748 };
1749 #[cfg(feature = "bitmap")]
1753 return rcu().run(op);
1754 #[cfg(not(feature = "bitmap"))]
1755 op()
1756 }
1757
1758 unsafe fn write_ptr(
1762 &self,
1763 gpa: u64,
1764 src: *const u8,
1765 len: usize,
1766 ) -> Result<(), GuestMemoryBackingError> {
1767 if len == 0 {
1768 return Ok(());
1769 }
1770 self.run_on_mapping(
1771 AccessType::Write,
1772 gpa,
1773 len,
1774 (),
1775 |(), dest| {
1776 unsafe { trycopy::try_copy(src, dest, len) }
1780 },
1781 |()| {
1782 unsafe { self.inner.imp.write_fallback(gpa, src, len) }
1785 },
1786 )
1787 }
1788
1789 pub fn write_at(&self, gpa: u64, src: &[u8]) -> Result<(), GuestMemoryError> {
1791 self.with_op(
1792 Some((gpa, src.len() as u64)),
1793 GuestMemoryOperation::Write,
1794 || self.write_at_inner(gpa, src),
1795 )
1796 }
1797
1798 fn write_at_inner(&self, gpa: u64, src: &[u8]) -> Result<(), GuestMemoryBackingError> {
1799 unsafe { self.write_ptr(gpa, src.as_ptr(), src.len()) }
1801 }
1802
1803 pub fn write_from_atomic(&self, gpa: u64, src: &[AtomicU8]) -> Result<(), GuestMemoryError> {
1805 self.with_op(
1806 Some((gpa, src.len() as u64)),
1807 GuestMemoryOperation::Write,
1808 || {
1809 unsafe { self.write_ptr(gpa, src.as_ptr().cast(), src.len()) }
1811 },
1812 )
1813 }
1814
1815 pub fn fill_at(&self, gpa: u64, val: u8, len: usize) -> Result<(), GuestMemoryError> {
1817 self.with_op(Some((gpa, len as u64)), GuestMemoryOperation::Fill, || {
1818 self.fill_at_inner(gpa, val, len)
1819 })
1820 }
1821
1822 fn fill_at_inner(&self, gpa: u64, val: u8, len: usize) -> Result<(), GuestMemoryBackingError> {
1823 if len == 0 {
1824 return Ok(());
1825 }
1826 self.run_on_mapping(
1827 AccessType::Write,
1828 gpa,
1829 len,
1830 (),
1831 |(), dest| {
1832 unsafe { trycopy::try_write_bytes(dest, val, len) }
1834 },
1835 |()| self.inner.imp.fill_fallback(gpa, val, len),
1836 )
1837 }
1838
1839 unsafe fn read_ptr(
1844 &self,
1845 gpa: u64,
1846 dest: *mut u8,
1847 len: usize,
1848 ) -> Result<(), GuestMemoryBackingError> {
1849 if len == 0 {
1850 return Ok(());
1851 }
1852 self.run_on_mapping(
1853 AccessType::Read,
1854 gpa,
1855 len,
1856 (),
1857 |(), src| {
1858 unsafe { trycopy::try_copy(src, dest, len) }
1862 },
1863 |()| {
1864 unsafe { self.inner.imp.read_fallback(gpa, dest, len) }
1867 },
1868 )
1869 }
1870
1871 fn read_at_inner(&self, gpa: u64, dest: &mut [u8]) -> Result<(), GuestMemoryBackingError> {
1872 unsafe { self.read_ptr(gpa, dest.as_mut_ptr(), dest.len()) }
1874 }
1875
1876 pub fn read_at(&self, gpa: u64, dest: &mut [u8]) -> Result<(), GuestMemoryError> {
1878 self.with_op(
1879 Some((gpa, dest.len() as u64)),
1880 GuestMemoryOperation::Read,
1881 || self.read_at_inner(gpa, dest),
1882 )
1883 }
1884
1885 pub fn read_to_atomic(&self, gpa: u64, dest: &[AtomicU8]) -> Result<(), GuestMemoryError> {
1887 self.with_op(
1888 Some((gpa, dest.len() as u64)),
1889 GuestMemoryOperation::Read,
1890 || unsafe { self.read_ptr(gpa, dest.as_ptr() as *mut u8, dest.len()) },
1892 )
1893 }
1894
1895 pub fn write_plain<T: IntoBytes + Immutable + KnownLayout>(
1907 &self,
1908 gpa: u64,
1909 b: &T,
1910 ) -> Result<(), GuestMemoryError> {
1911 let len = size_of::<T>();
1913 self.with_op(Some((gpa, len as u64)), GuestMemoryOperation::Write, || {
1914 self.run_on_mapping(
1915 AccessType::Write,
1916 gpa,
1917 len,
1918 (),
1919 |(), dest| {
1920 unsafe { trycopy::try_write_volatile(dest.cast(), b) }
1923 },
1924 |()| {
1925 unsafe {
1927 self.inner
1928 .imp
1929 .write_fallback(gpa, b.as_bytes().as_ptr(), len)
1930 }
1931 },
1932 )
1933 })
1934 }
1935
1936 pub fn compare_exchange<T: IntoBytes + FromBytes + Immutable + KnownLayout + Copy>(
1938 &self,
1939 gpa: u64,
1940 current: T,
1941 new: T,
1942 ) -> Result<Result<T, T>, GuestMemoryError> {
1943 const {
1944 assert!(matches!(size_of::<T>(), 1 | 2 | 4 | 8));
1945 assert!(align_of::<T>() >= size_of::<T>());
1946 };
1947 let len = size_of_val(&new);
1948 self.with_op(
1949 Some((gpa, len as u64)),
1950 GuestMemoryOperation::CompareExchange,
1951 || {
1952 self.run_on_mapping(
1954 AccessType::Write,
1955 gpa,
1956 len,
1957 (),
1958 |(), dest| {
1959 unsafe { trycopy::try_compare_exchange(dest.cast(), current, new) }
1962 },
1963 |()| {
1964 let mut current = current;
1965 let success = self.inner.imp.compare_exchange_fallback(
1966 gpa,
1967 current.as_mut_bytes(),
1968 new.as_bytes(),
1969 )?;
1970
1971 Ok(if success { Ok(new) } else { Err(current) })
1972 },
1973 )
1974 },
1975 )
1976 }
1977
1978 pub fn read_plain<T: FromBytes + Immutable + KnownLayout>(
1990 &self,
1991 gpa: u64,
1992 ) -> Result<T, GuestMemoryError> {
1993 self.with_op(
1994 Some((gpa, size_of::<T>() as u64)),
1995 GuestMemoryOperation::Read,
1996 || self.read_plain_inner(gpa),
1997 )
1998 }
1999
2000 fn read_plain_inner<T: FromBytes + Immutable + KnownLayout>(
2001 &self,
2002 gpa: u64,
2003 ) -> Result<T, GuestMemoryBackingError> {
2004 let len = size_of::<T>();
2005 self.run_on_mapping(
2006 AccessType::Read,
2007 gpa,
2008 len,
2009 (),
2010 |(), src| {
2011 unsafe { trycopy::try_read_volatile(src.cast::<T>()) }
2014 },
2015 |()| {
2016 let mut obj = std::mem::MaybeUninit::<T>::zeroed();
2017 unsafe {
2020 self.inner
2021 .imp
2022 .read_fallback(gpa, obj.as_mut_ptr().cast(), len)?;
2023 }
2024 Ok(unsafe { obj.assume_init() })
2026 },
2027 )
2028 }
2029
2030 fn probe_page_for_lock(
2031 &self,
2032 access: AccessType,
2033 with_kernel_access: bool,
2034 gpa: u64,
2035 ) -> Result<*const AtomicU8, GuestMemoryBackingError> {
2036 let (region, offset, _) = self.inner.region(gpa, 1)?;
2037 let Some(SendPtrU8(ptr)) = region.mapping else {
2038 return Err(GuestMemoryBackingError::other(gpa, NotLockable));
2039 };
2040 if with_kernel_access {
2042 self.inner.imp.expose_va(gpa, 1)?;
2043 }
2044 match access {
2054 AccessType::Read => {
2055 self.read_plain_inner::<u8>(gpa)?;
2056 }
2057 AccessType::Write => {
2058 self.probe_mapped_page_writable(gpa)?;
2059 }
2060 }
2061 let page = unsafe { ptr.as_ptr().add(offset as usize) };
2064 Ok(page.cast())
2065 }
2066
2067 fn probe_mapped_page_writable(&self, gpa: u64) -> Result<(), GuestMemoryBackingError> {
2087 self.run_on_mapping(
2088 AccessType::Write,
2089 gpa,
2090 1,
2091 (),
2092 |(), dest| {
2093 unsafe { trycopy::try_compare_exchange::<u8>(dest.cast(), 0, 0).map(|_| ()) }
2095 },
2096 |()| {
2097 Err(GuestMemoryBackingError::other(gpa, NotLockable))
2103 },
2104 )
2105 }
2106
2107 pub fn lock_gpns(
2116 &self,
2117 access: AccessType,
2118 with_kernel_access: bool,
2119 gpns: &[u64],
2120 ) -> Result<LockedPages, GuestMemoryError> {
2121 self.with_op(None, GuestMemoryOperation::Lock, || {
2122 if !self.inner.supports_locking {
2123 let gpa = gpns.first().map_or(0, |&gpn| gpn.wrapping_mul(PAGE_SIZE64));
2124 return Err(GuestMemoryBackingError::other(gpa, NotLockable));
2125 }
2126 let mut pages = Vec::with_capacity(gpns.len());
2127 for &gpn in gpns {
2128 let gpa = gpn_to_gpa(gpn).map_err(GuestMemoryBackingError::gpn)?;
2129 let page = self.probe_page_for_lock(access, with_kernel_access, gpa)?;
2130 pages.push(PagePtr(page));
2131 }
2132 let store_gpns = self.inner.imp.lock_gpns(gpns)?;
2133 Ok(LockedPages {
2134 pages: pages.into_boxed_slice(),
2135 gpns: store_gpns.then(|| gpns.to_vec().into_boxed_slice()),
2136 mem: self.inner.clone(),
2137 })
2138 })
2139 }
2140
2141 pub fn probe_gpns(&self, gpns: &[u64]) -> Result<(), GuestMemoryError> {
2142 self.with_op(None, GuestMemoryOperation::Probe, || {
2143 for &gpn in gpns {
2144 self.read_plain_inner::<u8>(
2145 gpn_to_gpa(gpn).map_err(GuestMemoryBackingError::gpn)?,
2146 )?;
2147 }
2148 Ok(())
2149 })
2150 }
2151
2152 pub fn probe_gpa_readable(&self, gpa: u64) -> Result<(), GuestMemoryErrorKind> {
2154 let mut b = [0];
2155 self.read_at_inner(gpa, &mut b).map_err(|err| err.kind)
2156 }
2157
2158 pub fn probe_gpa_writable(&self, gpa: u64) -> Result<(), GuestMemoryErrorKind> {
2160 let _ = self
2161 .compare_exchange(gpa, 0u8, 0)
2162 .map_err(|err| err.kind())?;
2163 Ok(())
2164 }
2165
2166 fn dangerous_access_pre_locked_memory(&self, gpa: u64, len: usize) -> &[AtomicU8] {
2178 let addr = self
2179 .mapping_range(AccessType::Write, gpa, len)
2180 .unwrap()
2181 .unwrap();
2182 unsafe { std::slice::from_raw_parts(addr.cast(), len) }
2187 }
2188
2189 fn op_range<F: FnMut(u64, Range<usize>) -> Result<(), GuestMemoryBackingError>>(
2190 &self,
2191 op: GuestMemoryOperation,
2192 range: &PagedRange<'_>,
2193 mut f: F,
2194 ) -> Result<(), GuestMemoryError> {
2195 self.with_op(None, op, || {
2196 let gpns = range.gpns();
2197 let offset = range.offset();
2198
2199 let mut byte_index = 0;
2203 let mut len = range.len();
2204 let mut page = 0;
2205 if !offset.is_multiple_of(PAGE_SIZE) {
2206 let head_len = std::cmp::min(len, PAGE_SIZE - (offset % PAGE_SIZE));
2207 let addr = gpn_to_gpa(gpns[page]).map_err(GuestMemoryBackingError::gpn)?
2208 + offset as u64 % PAGE_SIZE64;
2209 f(addr, byte_index..byte_index + head_len)?;
2210 byte_index += head_len;
2211 len -= head_len;
2212 page += 1;
2213 }
2214 while len >= PAGE_SIZE {
2215 f(
2216 gpn_to_gpa(gpns[page]).map_err(GuestMemoryBackingError::gpn)?,
2217 byte_index..byte_index + PAGE_SIZE,
2218 )?;
2219 byte_index += PAGE_SIZE;
2220 len -= PAGE_SIZE;
2221 page += 1;
2222 }
2223 if len > 0 {
2224 f(
2225 gpn_to_gpa(gpns[page]).map_err(GuestMemoryBackingError::gpn)?,
2226 byte_index..byte_index + len,
2227 )?;
2228 }
2229
2230 Ok(())
2231 })
2232 }
2233
2234 pub fn write_range(&self, range: &PagedRange<'_>, data: &[u8]) -> Result<(), GuestMemoryError> {
2235 assert!(data.len() == range.len());
2236 self.op_range(GuestMemoryOperation::Write, range, move |addr, r| {
2237 self.write_at_inner(addr, &data[r])
2238 })
2239 }
2240
2241 pub fn fill_range(&self, range: &PagedRange<'_>, val: u8) -> Result<(), GuestMemoryError> {
2242 self.op_range(GuestMemoryOperation::Fill, range, move |addr, r| {
2243 self.fill_at_inner(addr, val, r.len())
2244 })
2245 }
2246
2247 pub fn zero_range(&self, range: &PagedRange<'_>) -> Result<(), GuestMemoryError> {
2248 self.op_range(GuestMemoryOperation::Fill, range, move |addr, r| {
2249 self.fill_at_inner(addr, 0, r.len())
2250 })
2251 }
2252
2253 pub fn read_range(
2254 &self,
2255 range: &PagedRange<'_>,
2256 data: &mut [u8],
2257 ) -> Result<(), GuestMemoryError> {
2258 assert!(data.len() == range.len());
2259 self.op_range(GuestMemoryOperation::Read, range, move |addr, r| {
2260 self.read_at_inner(addr, &mut data[r])
2261 })
2262 }
2263
2264 pub fn write_range_from_atomic(
2265 &self,
2266 range: &PagedRange<'_>,
2267 data: &[AtomicU8],
2268 ) -> Result<(), GuestMemoryError> {
2269 assert!(data.len() == range.len());
2270 self.op_range(GuestMemoryOperation::Write, range, move |addr, r| {
2271 let src = &data[r];
2272 unsafe { self.write_ptr(addr, src.as_ptr().cast(), src.len()) }
2274 })
2275 }
2276
2277 pub fn read_range_to_atomic(
2278 &self,
2279 range: &PagedRange<'_>,
2280 data: &[AtomicU8],
2281 ) -> Result<(), GuestMemoryError> {
2282 assert!(data.len() == range.len());
2283 self.op_range(GuestMemoryOperation::Read, range, move |addr, r| {
2284 let dest = &data[r];
2285 unsafe { self.read_ptr(addr, dest.as_ptr().cast_mut().cast(), dest.len()) }
2287 })
2288 }
2289
2290 pub fn lock_range<'a, T: LockedRange<'a>>(
2302 &'a self,
2303 access: AccessType,
2304 paged_range: PagedRange<'_>,
2305 mut locked_range: T,
2306 ) -> Result<LockedRangeImpl<'a, T>, GuestMemoryError> {
2307 self.with_op(None, GuestMemoryOperation::Lock, || {
2308 let gpns = paged_range.gpns();
2309 if !self.inner.supports_locking {
2310 let gpa = gpns.first().map_or(0, |&gpn| gpn.wrapping_mul(PAGE_SIZE64));
2311 return Err(GuestMemoryBackingError::other(gpa, NotLockable));
2312 }
2313 for &gpn in gpns {
2314 let gpa = gpn_to_gpa(gpn).map_err(GuestMemoryBackingError::gpn)?;
2315 self.probe_page_for_lock(access, true, gpa)?;
2316 }
2317 for range in paged_range.ranges() {
2318 let range = range.map_err(GuestMemoryBackingError::gpn)?;
2319 locked_range.push_sub_range(
2320 self.dangerous_access_pre_locked_memory(range.start, range.len() as usize),
2321 );
2322 }
2323 let store_gpns = self.inner.imp.lock_gpns(paged_range.gpns())?;
2324 Ok(LockedRangeImpl {
2325 mem: &self.inner,
2326 gpns: store_gpns.then(|| paged_range.gpns().to_vec().into_boxed_slice()),
2327 inner: locked_range,
2328 })
2329 })
2330 }
2331}
2332
2333#[derive(Debug, Error)]
2334#[error("invalid guest page number {0:#x}")]
2335pub struct InvalidGpn(u64);
2336
2337fn gpn_to_gpa(gpn: u64) -> Result<u64, InvalidGpn> {
2338 gpn.checked_mul(PAGE_SIZE64).ok_or(InvalidGpn(gpn))
2339}
2340
2341#[derive(Debug, Copy, Clone, Default)]
2342struct RegionDefinition {
2343 invalid_mask: u64,
2344 region_mask: u64,
2345 region_bits: u32,
2346}
2347
2348impl RegionDefinition {
2349 fn region(&self, gpa: u64, len: u64) -> Result<(usize, u64), GuestMemoryBackingError> {
2350 if (gpa | len) & self.invalid_mask != 0 {
2351 return Err(GuestMemoryBackingError::new(
2352 GuestMemoryErrorKind::OutOfRange,
2353 gpa,
2354 OutOfRange,
2355 ));
2356 }
2357 let offset = gpa & self.region_mask;
2358 if offset.wrapping_add(len) & !self.region_mask != 0 {
2359 return Err(GuestMemoryBackingError::new(
2360 GuestMemoryErrorKind::OutOfRange,
2361 gpa,
2362 OutOfRange,
2363 ));
2364 }
2365 let index = (gpa >> self.region_bits) as usize;
2366 Ok((index, offset))
2367 }
2368}
2369
2370impl GuestMemoryInner {
2371 fn region(
2372 &self,
2373 gpa: u64,
2374 len: u64,
2375 ) -> Result<(&MemoryRegion, u64, usize), GuestMemoryBackingError> {
2376 let (index, offset) = self.region_def.region(gpa, len)?;
2377 let region = &self.regions[index];
2378 if offset + len > region.len {
2379 return Err(GuestMemoryBackingError::new(
2380 GuestMemoryErrorKind::OutOfRange,
2381 gpa,
2382 OutOfRange,
2383 ));
2384 }
2385 Ok((&self.regions[index], offset, index))
2386 }
2387}
2388
2389pub struct LockedPages {
2390 pages: Box<[PagePtr]>,
2391 gpns: Option<Box<[u64]>>,
2392 mem: Arc<GuestMemoryInner>,
2394}
2395
2396impl Drop for LockedPages {
2397 fn drop(&mut self) {
2398 if let Some(gpns) = &self.gpns {
2399 self.mem.imp.unlock_gpns(gpns);
2400 }
2401 }
2402}
2403
2404impl Debug for LockedPages {
2405 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2406 f.debug_struct("LockedPages")
2407 .field("page_count", &self.pages.len())
2408 .finish()
2409 }
2410}
2411
2412#[derive(Copy, Clone, Debug)]
2413struct PagePtr(#[expect(dead_code)] *const AtomicU8);
2415
2416unsafe impl Send for PagePtr {}
2419unsafe impl Sync for PagePtr {}
2421
2422pub type Page = [AtomicU8; PAGE_SIZE];
2423
2424impl LockedPages {
2425 #[inline]
2426 pub fn pages(&self) -> &[&Page] {
2427 unsafe { std::slice::from_raw_parts(self.pages.as_ptr().cast::<&Page>(), self.pages.len()) }
2431 }
2432}
2433
2434impl<'a> AsRef<[&'a Page]> for &'a LockedPages {
2435 fn as_ref(&self) -> &[&'a Page] {
2436 self.pages()
2437 }
2438}
2439
2440pub trait LockedRange<'a> {
2445 fn push_sub_range(&mut self, sub_range: &'a [AtomicU8]);
2447}
2448
2449pub struct LockedRangeImpl<'a, T: LockedRange<'a>> {
2450 mem: &'a GuestMemoryInner,
2451 gpns: Option<Box<[u64]>>,
2452 inner: T,
2453}
2454
2455impl<'a, T: LockedRange<'a>> LockedRangeImpl<'a, T> {
2456 pub fn get(&self) -> &T {
2457 &self.inner
2458 }
2459
2460 pub fn get_mut(&mut self) -> &mut T {
2461 &mut self.inner
2462 }
2463}
2464
2465impl<'a, T: LockedRange<'a>> Drop for LockedRangeImpl<'a, T> {
2466 fn drop(&mut self) {
2467 if let Some(gpns) = &self.gpns {
2468 self.mem.imp.unlock_gpns(gpns);
2469 }
2470 }
2471}
2472
2473#[derive(Debug, Error)]
2474pub enum AccessError {
2475 #[error("memory access error")]
2476 Memory(#[from] GuestMemoryError),
2477 #[error("out of range: {0:#x} < {1:#x}")]
2478 OutOfRange(usize, usize),
2479 #[error("write attempted to read-only memory")]
2480 ReadOnly,
2481}
2482
2483pub trait MemoryRead {
2484 fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError>;
2485 fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError>;
2486 fn len(&self) -> usize;
2487
2488 fn read_plain<T: IntoBytes + FromBytes + Immutable + KnownLayout>(
2489 &mut self,
2490 ) -> Result<T, AccessError> {
2491 let mut value: T = FromZeros::new_zeroed();
2492 self.read(value.as_mut_bytes())?;
2493 Ok(value)
2494 }
2495
2496 fn read_n<T: IntoBytes + FromBytes + Immutable + KnownLayout + Copy>(
2497 &mut self,
2498 len: usize,
2499 ) -> Result<Vec<T>, AccessError> {
2500 let mut value = vec![FromZeros::new_zeroed(); len];
2501 self.read(value.as_mut_bytes())?;
2502 Ok(value)
2503 }
2504
2505 fn read_all(&mut self) -> Result<Vec<u8>, AccessError> {
2506 let mut value = vec![0; self.len()];
2507 self.read(&mut value)?;
2508 Ok(value)
2509 }
2510
2511 fn limit(self, len: usize) -> Limit<Self>
2512 where
2513 Self: Sized,
2514 {
2515 let len = len.min(self.len());
2516 Limit { inner: self, len }
2517 }
2518}
2519
2520pub trait MemoryWrite {
2522 fn write(&mut self, data: &[u8]) -> Result<(), AccessError>;
2523 fn zero(&mut self, len: usize) -> Result<(), AccessError> {
2524 self.fill(0, len)
2525 }
2526 fn fill(&mut self, val: u8, len: usize) -> Result<(), AccessError>;
2527
2528 fn len(&self) -> usize;
2530
2531 fn limit(self, len: usize) -> Limit<Self>
2532 where
2533 Self: Sized,
2534 {
2535 let len = len.min(self.len());
2536 Limit { inner: self, len }
2537 }
2538}
2539
2540impl MemoryRead for &'_ [u8] {
2541 fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError> {
2542 if self.len() < data.len() {
2543 return Err(AccessError::OutOfRange(self.len(), data.len()));
2544 }
2545 let (source, rest) = self.split_at(data.len());
2546 data.copy_from_slice(source);
2547 *self = rest;
2548 Ok(self)
2549 }
2550
2551 fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError> {
2552 if self.len() < len {
2553 return Err(AccessError::OutOfRange(self.len(), len));
2554 }
2555 *self = &self[len..];
2556 Ok(self)
2557 }
2558
2559 fn len(&self) -> usize {
2560 <[u8]>::len(self)
2561 }
2562}
2563
2564impl MemoryWrite for &mut [u8] {
2565 fn write(&mut self, data: &[u8]) -> Result<(), AccessError> {
2566 if self.len() < data.len() {
2567 return Err(AccessError::OutOfRange(self.len(), data.len()));
2568 }
2569 let (dest, rest) = std::mem::take(self).split_at_mut(data.len());
2570 dest.copy_from_slice(data);
2571 *self = rest;
2572 Ok(())
2573 }
2574
2575 fn fill(&mut self, val: u8, len: usize) -> Result<(), AccessError> {
2576 if self.len() < len {
2577 return Err(AccessError::OutOfRange(self.len(), len));
2578 }
2579 let (dest, rest) = std::mem::take(self).split_at_mut(len);
2580 dest.fill(val);
2581 *self = rest;
2582 Ok(())
2583 }
2584
2585 fn len(&self) -> usize {
2586 <[u8]>::len(self)
2587 }
2588}
2589
2590#[derive(Debug, Clone)]
2591pub struct Limit<T> {
2592 inner: T,
2593 len: usize,
2594}
2595
2596impl<T: MemoryRead> MemoryRead for Limit<T> {
2597 fn read(&mut self, data: &mut [u8]) -> Result<&mut Self, AccessError> {
2598 let len = data.len();
2599 if len > self.len {
2600 return Err(AccessError::OutOfRange(self.len, len));
2601 }
2602 self.inner.read(data)?;
2603 self.len -= len;
2604 Ok(self)
2605 }
2606
2607 fn skip(&mut self, len: usize) -> Result<&mut Self, AccessError> {
2608 if len > self.len {
2609 return Err(AccessError::OutOfRange(self.len, len));
2610 }
2611 self.inner.skip(len)?;
2612 self.len -= len;
2613 Ok(self)
2614 }
2615
2616 fn len(&self) -> usize {
2617 self.len
2618 }
2619}
2620
2621impl<T: MemoryWrite> MemoryWrite for Limit<T> {
2622 fn write(&mut self, data: &[u8]) -> Result<(), AccessError> {
2623 let len = data.len();
2624 if len > self.len {
2625 return Err(AccessError::OutOfRange(self.len, len));
2626 }
2627 self.inner.write(data)?;
2628 self.len -= len;
2629 Ok(())
2630 }
2631
2632 fn fill(&mut self, val: u8, len: usize) -> Result<(), AccessError> {
2633 if len > self.len {
2634 return Err(AccessError::OutOfRange(self.len, len));
2635 }
2636 self.inner.fill(val, len)?;
2637 self.len -= len;
2638 Ok(())
2639 }
2640
2641 fn len(&self) -> usize {
2642 self.len
2643 }
2644}
2645
2646pub trait MappableGuestMemory: Send + Sync {
2649 fn map_to_guest(&mut self, gpa: u64, writable: bool) -> io::Result<()>;
2655
2656 fn unmap_from_guest(&mut self);
2657}
2658
2659pub trait MappedMemoryRegion: Send + Sync {
2662 fn map(
2666 &self,
2667 offset: usize,
2668 section: &dyn AsMappableRef,
2669 file_offset: u64,
2670 len: usize,
2671 writable: bool,
2672 ) -> io::Result<()>;
2673
2674 fn unmap(&self, offset: usize, len: usize) -> io::Result<()>;
2676}
2677
2678pub trait MemoryMapper: Send + Sync {
2680 fn new_region(
2685 &self,
2686 len: usize,
2687 debug_name: String,
2688 ) -> io::Result<(Box<dyn MappableGuestMemory>, Arc<dyn MappedMemoryRegion>)>;
2689}
2690
2691pub trait DoorbellRegistration: Send + Sync {
2693 fn register_doorbell(
2695 &self,
2696 guest_address: u64,
2697 value: Option<u64>,
2698 length: Option<u32>,
2699 event: &Event,
2700 ) -> io::Result<Box<dyn Send + Sync>>;
2701}
2702
2703pub trait MapRom: Send + Sync {
2705 fn map_rom(&self, gpa: u64, offset: u64, len: u64) -> io::Result<Box<dyn UnmapRom>>;
2709
2710 fn len(&self) -> u64;
2712}
2713
2714pub trait UnmapRom: Send + Sync {
2716 fn unmap_rom(self);
2718}
2719
2720#[cfg(test)]
2721#[expect(clippy::undocumented_unsafe_blocks)]
2722mod tests {
2723 use crate::GuestMemory;
2724 use crate::PAGE_SIZE64;
2725 use crate::PageFaultAction;
2726 use crate::PageFaultError;
2727
2728 use sparse_mmap::SparseMapping;
2729 use std::ptr::NonNull;
2730 use std::sync::Arc;
2731 use thiserror::Error;
2732
2733 pub struct GuestMemoryMapping {
2738 mapping: SparseMapping,
2739 #[cfg(feature = "bitmap")]
2740 bitmap: Option<Vec<u8>>,
2741 }
2742
2743 unsafe impl crate::GuestMemoryAccess for GuestMemoryMapping {
2744 fn mapping(&self) -> Option<NonNull<u8>> {
2745 NonNull::new(self.mapping.as_ptr().cast())
2746 }
2747
2748 fn max_address(&self) -> u64 {
2749 self.mapping.len() as u64
2750 }
2751
2752 #[cfg(feature = "bitmap")]
2753 fn access_bitmap(&self) -> Option<crate::BitmapInfo> {
2754 self.bitmap.as_ref().map(|bm| crate::BitmapInfo {
2755 read_bitmap: NonNull::new(bm.as_ptr().cast_mut()).unwrap(),
2756 write_bitmap: NonNull::new(bm.as_ptr().cast_mut()).unwrap(),
2757 bit_offset: 0,
2758 })
2759 }
2760 }
2761
2762 const PAGE_SIZE: usize = 4096;
2763 const SIZE_1MB: usize = 1048576;
2764
2765 fn create_test_mapping() -> GuestMemoryMapping {
2772 let mapping = SparseMapping::new(SIZE_1MB * 4).unwrap();
2773 mapping.alloc(0, SIZE_1MB).unwrap();
2774 mapping.alloc(2 * SIZE_1MB, SIZE_1MB).unwrap();
2775 mapping
2776 .alloc(3 * SIZE_1MB + PAGE_SIZE, SIZE_1MB - PAGE_SIZE)
2777 .unwrap();
2778
2779 GuestMemoryMapping {
2780 mapping,
2781 #[cfg(feature = "bitmap")]
2782 bitmap: None,
2783 }
2784 }
2785
2786 #[test]
2787 fn test_basic_read_write() {
2788 let mapping = create_test_mapping();
2789 let gm = GuestMemory::new("test", mapping);
2790
2791 let addr = 0;
2793 let result = gm.read_plain::<u8>(addr);
2794 assert_eq!(result.unwrap(), 0);
2795
2796 let write_buffer = [1, 2, 3, 4, 5];
2798 let mut read_buffer = [0; 5];
2799 gm.write_at(0, &write_buffer).unwrap();
2800 gm.read_at(0, &mut read_buffer).unwrap();
2801 assert_eq!(write_buffer, read_buffer);
2802 assert_eq!(gm.read_plain::<u8>(0).unwrap(), 1);
2803 assert_eq!(gm.read_plain::<u8>(1).unwrap(), 2);
2804 assert_eq!(gm.read_plain::<u8>(2).unwrap(), 3);
2805 assert_eq!(gm.read_plain::<u8>(3).unwrap(), 4);
2806 assert_eq!(gm.read_plain::<u8>(4).unwrap(), 5);
2807
2808 let addr = 2 * SIZE_1MB as u64;
2810 let write_buffer: Vec<u8> = (0..PAGE_SIZE).map(|x| x as u8).collect();
2811 let mut read_buffer: Vec<u8> = (0..PAGE_SIZE).map(|_| 0).collect();
2812 gm.write_at(addr, write_buffer.as_slice()).unwrap();
2813 gm.read_at(addr, read_buffer.as_mut_slice()).unwrap();
2814 assert_eq!(write_buffer, read_buffer);
2815
2816 let write_buffer: Vec<u8> = (0..SIZE_1MB).map(|x| x as u8).collect();
2818 let mut read_buffer: Vec<u8> = (0..SIZE_1MB).map(|_| 0).collect();
2819 gm.write_at(addr, write_buffer.as_slice()).unwrap();
2820 gm.read_at(addr, read_buffer.as_mut_slice()).unwrap();
2821 assert_eq!(write_buffer, read_buffer);
2822
2823 let addr = SIZE_1MB as u64;
2825 let result = gm.read_plain::<u8>(addr);
2826 assert!(result.is_err());
2827 }
2828
2829 #[test]
2830 fn test_multi() {
2831 let len = SIZE_1MB * 4;
2832 let mapping = SparseMapping::new(len).unwrap();
2833 mapping.alloc(0, len).unwrap();
2834 let mapping = Arc::new(GuestMemoryMapping {
2835 mapping,
2836 #[cfg(feature = "bitmap")]
2837 bitmap: None,
2838 });
2839 let region_len = 1 << 30;
2840 let gm = GuestMemory::new_multi_region(
2841 "test",
2842 region_len,
2843 vec![Some(mapping.clone()), None, Some(mapping.clone())],
2844 )
2845 .unwrap();
2846
2847 let mut b = [0];
2848 let len = len as u64;
2849 gm.read_at(0, &mut b).unwrap();
2850 gm.read_at(len, &mut b).unwrap_err();
2851 gm.read_at(region_len, &mut b).unwrap_err();
2852 gm.read_at(2 * region_len, &mut b).unwrap();
2853 gm.read_at(2 * region_len + len, &mut b).unwrap_err();
2854 gm.read_at(3 * region_len, &mut b).unwrap_err();
2855 }
2856
2857 #[cfg(feature = "bitmap")]
2858 #[test]
2859 fn test_bitmap() {
2860 let len = PAGE_SIZE * 4;
2861 let mapping = SparseMapping::new(len).unwrap();
2862 mapping.alloc(0, len).unwrap();
2863 let bitmap = vec![0b0101];
2864 let mapping = Arc::new(GuestMemoryMapping {
2865 mapping,
2866 bitmap: Some(bitmap),
2867 });
2868 let gm = GuestMemory::new("test", mapping);
2869
2870 gm.read_plain::<[u8; 1]>(0).unwrap();
2871 gm.read_plain::<[u8; 1]>(PAGE_SIZE64 - 1).unwrap();
2872 gm.read_plain::<[u8; 2]>(PAGE_SIZE64 - 1).unwrap_err();
2873 gm.read_plain::<[u8; 1]>(PAGE_SIZE64).unwrap_err();
2874 gm.read_plain::<[u8; 1]>(PAGE_SIZE64 * 2).unwrap();
2875 gm.read_plain::<[u8; PAGE_SIZE * 2]>(0).unwrap_err();
2876 }
2877
2878 struct FaultingMapping {
2879 mapping: SparseMapping,
2880 }
2881
2882 #[derive(Debug, Error)]
2883 #[error("fault")]
2884 struct Fault;
2885
2886 unsafe impl crate::GuestMemoryAccess for FaultingMapping {
2887 fn mapping(&self) -> Option<NonNull<u8>> {
2888 NonNull::new(self.mapping.as_ptr().cast())
2889 }
2890
2891 fn max_address(&self) -> u64 {
2892 self.mapping.len() as u64
2893 }
2894
2895 fn page_fault(
2896 &self,
2897 address: u64,
2898 _len: usize,
2899 write: bool,
2900 bitmap_failure: bool,
2901 ) -> PageFaultAction {
2902 assert!(!bitmap_failure);
2903 let qlen = self.mapping.len() as u64 / 4;
2904 if address < qlen || address >= 3 * qlen {
2905 return PageFaultAction::Fail(PageFaultError::other(Fault));
2906 }
2907 let page_address = (address as usize) & !(PAGE_SIZE - 1);
2908 if address >= 2 * qlen {
2909 if write {
2910 return PageFaultAction::Fail(PageFaultError::other(Fault));
2911 }
2912 self.mapping.map_zero(page_address, PAGE_SIZE).unwrap();
2913 } else {
2914 self.mapping.alloc(page_address, PAGE_SIZE).unwrap();
2915 }
2916 PageFaultAction::Retry
2917 }
2918 }
2919
2920 impl FaultingMapping {
2921 fn new(len: usize) -> Self {
2922 let mapping = SparseMapping::new(len).unwrap();
2923 FaultingMapping { mapping }
2924 }
2925 }
2926
2927 #[test]
2928 fn test_fault() {
2929 let len = PAGE_SIZE * 4;
2930 let mapping = FaultingMapping::new(len);
2931 let gm = GuestMemory::new("test", mapping);
2932
2933 gm.write_plain::<u8>(0, &0).unwrap_err();
2934 gm.read_plain::<u8>(PAGE_SIZE64 - 1).unwrap_err();
2935 gm.read_plain::<u8>(PAGE_SIZE64).unwrap();
2936 gm.write_plain::<u8>(PAGE_SIZE64, &0).unwrap();
2937 gm.write_plain::<u16>(PAGE_SIZE64 * 3 - 1, &0).unwrap_err();
2938 gm.read_plain::<u16>(PAGE_SIZE64 * 3 - 1).unwrap_err();
2939 gm.read_plain::<u8>(PAGE_SIZE64 * 3 - 1).unwrap();
2940 gm.write_plain::<u8>(PAGE_SIZE64 * 3 - 1, &0).unwrap_err();
2941 }
2942
2943 #[cfg(feature = "bitmap")]
2944 #[test]
2945 fn test_zero_length_access_at_offset_zero() {
2946 let len = PAGE_SIZE * 4;
2952 let mapping = SparseMapping::new(len).unwrap();
2953 mapping.alloc(0, len).unwrap();
2954 let bitmap = vec![0b0000]; let mapping = Arc::new(GuestMemoryMapping {
2956 mapping,
2957 bitmap: Some(bitmap),
2958 });
2959 let gm = GuestMemory::new("test", mapping);
2960
2961 gm.read_plain::<()>(0).unwrap();
2965 gm.write_plain::<()>(0, &()).unwrap();
2966 }
2967
2968 #[test]
2969 fn test_allocated() {
2970 let mut gm = GuestMemory::allocate(0x10000);
2971 let pattern = [0x42; 0x10000];
2972 gm.write_at(0, &pattern).unwrap();
2973 assert_eq!(gm.inner_buf_mut().unwrap(), &pattern);
2974 gm.inner_buf().unwrap();
2975 let gm2 = gm.clone();
2976 assert!(gm.inner_buf_mut().is_none());
2977 gm.inner_buf().unwrap();
2978 let mut gm = gm.into_inner_buf().unwrap_err();
2979 drop(gm2);
2980 assert_eq!(gm.inner_buf_mut().unwrap(), &pattern);
2981 gm.into_inner_buf().unwrap();
2982 }
2983
2984 struct ToggleLockMapping {
2988 mapping: SparseMapping,
2989 lockable: bool,
2990 }
2991
2992 impl ToggleLockMapping {
2993 fn new(size: usize, lockable: bool) -> Self {
2994 let mapping = SparseMapping::new(size).unwrap();
2995 mapping.alloc(0, size).unwrap();
2996 Self { mapping, lockable }
2997 }
2998 }
2999
3000 unsafe impl crate::GuestMemoryAccess for ToggleLockMapping {
3002 fn mapping(&self) -> Option<NonNull<u8>> {
3003 NonNull::new(self.mapping.as_ptr().cast())
3004 }
3005
3006 fn max_address(&self) -> u64 {
3007 self.mapping.len() as u64
3008 }
3009
3010 fn supports_locking(&self) -> bool {
3011 self.lockable
3012 }
3013 }
3014
3015 #[test]
3016 fn test_supports_locking() {
3017 let gm = GuestMemory::allocate(0x10000);
3019 assert!(gm.supports_locking());
3020
3021 let gm = GuestMemory::new("nolock", ToggleLockMapping::new(SIZE_1MB, false));
3026 assert!(!gm.supports_locking());
3027 assert!(gm.lock_gpns(crate::AccessType::Write, false, &[0]).is_err());
3028
3029 let gm = GuestMemory::new_multi_region(
3032 "multi-lockable",
3033 SIZE_1MB as u64,
3034 vec![
3035 Some(ToggleLockMapping::new(SIZE_1MB / 2, true)),
3036 Some(ToggleLockMapping::new(SIZE_1MB / 2, true)),
3037 ],
3038 )
3039 .unwrap();
3040 assert!(gm.supports_locking());
3041
3042 let gm = GuestMemory::new_multi_region(
3043 "multi-mixed",
3044 SIZE_1MB as u64,
3045 vec![
3046 Some(ToggleLockMapping::new(SIZE_1MB / 2, true)),
3047 Some(ToggleLockMapping::new(SIZE_1MB / 2, false)),
3048 ],
3049 )
3050 .unwrap();
3051 assert!(!gm.supports_locking());
3052 }
3053}