1212//! IOTLB misses require sending a notification to the front-end and awaiting a reply that supplies
1313//! the desired mapping.
1414
15+ use crate :: bitmap:: { self , Bitmap } ;
1516use crate :: guest_memory:: {
1617 Error as GuestMemoryError , GuestMemorySliceIterator , Result as GuestMemoryResult ,
1718} ;
1819use crate :: {
19- bitmap, GuestAddress , GuestMemory , IoMemory , MemoryRegionAddress , Permissions , VolatileSlice ,
20+ Address , GuestAddress , GuestMemory , GuestMemoryRegion , GuestUsize , IoMemory ,
21+ MemoryRegionAddress , Permissions , VolatileSlice ,
2022} ;
2123use rangemap:: RangeMap ;
2224use std:: cmp;
23- use std:: fmt:: Debug ;
25+ use std:: fmt:: { self , Debug } ;
2426use std:: num:: Wrapping ;
2527use std:: ops:: { Deref , Range } ;
2628use std:: sync:: Arc ;
@@ -183,7 +185,15 @@ pub struct IotlbFails {
183185/// The underlying [`GuestMemory`] is basically the physical memory, and the [`Iommu`] translates
184186/// the I/O virtual address space that `IommuMemory` provides into that underlying physical address
185187/// space.
186- #[ derive( Debug , Default ) ]
188+ ///
189+ /// Note on memory write tracking (“logging”):
190+ /// - When the IOMMU is disabled ([`IommuMemory::set_iommu_enabled()`]), writes to memory are
191+ /// tracked by the underlying [`GuestMemory`] in its bitmap(s).
192+ /// - When it is enabled, they are instead tracked in the [`IommuMemory`]’s dirty bitmap; the
193+ /// offset in the bitmap is calculated from the write’s IOVA.
194+ ///
195+ /// Therefore, this type should only be used when this is the desired behavior (IOVA-based memory
196+ /// write logging when IOMMU is used).
187197pub struct IommuMemory < M : GuestMemory , I : Iommu > {
188198 /// Physical memory
189199 inner : M ,
@@ -192,6 +202,8 @@ pub struct IommuMemory<M: GuestMemory, I: Iommu> {
192202 /// Whether the IOMMU is even to be used or not; disabling it makes this a pass-through to
193203 /// `inner`.
194204 use_iommu : bool ,
205+ /// Dirty bitmap to use for IOVA accesses
206+ bitmap : Arc < <M :: R as GuestMemoryRegion >:: B > ,
195207}
196208
197209impl IommuMapping {
@@ -355,27 +367,36 @@ impl TryFrom<Range<u64>> for IovaRange {
355367
356368impl < M : GuestMemory , I : Iommu > IommuMemory < M , I > {
357369 /// Create a new `IommuMemory` instance.
358- pub fn new ( inner : M , iommu : I , use_iommu : bool ) -> Self {
370+ pub fn new ( inner : M , iommu : I , use_iommu : bool , bitmap : < Self as IoMemory > :: Bitmap ) -> Self {
359371 IommuMemory {
360372 inner,
361373 iommu : Arc :: new ( iommu) ,
362374 use_iommu,
375+ bitmap : Arc :: new ( bitmap) ,
363376 }
364377 }
365378
366379 /// Create a new version of `self` with the underlying physical memory replaced.
367380 ///
368- /// Note that the inner `Arc` reference to the IOMMU is cloned, i.e. both the existing and the
369- /// new `IommuMemory` object will share an IOMMU instance . (The `use_iommu` flag however is
370- /// copied, so is independent between the two instances.)
381+ /// Note that the inner `Arc` references to the IOMMU and bitmap are cloned, i.e. both the
382+ /// existing and the new `IommuMemory` object will share the IOMMU and bitmap instances . (The
383+ /// `use_iommu` flag however is copied, so is independent between the two instances.)
371384 pub fn inner_replaced ( & self , inner : M ) -> Self {
372385 IommuMemory {
373386 inner,
374387 iommu : Arc :: clone ( & self . iommu ) ,
375388 use_iommu : self . use_iommu ,
389+ bitmap : Arc :: clone ( & self . bitmap ) ,
376390 }
377391 }
378392
393+ /// Return a reference to the IOVA address space's dirty bitmap.
394+ ///
395+ /// This bitmap tracks write accesses done while the IOMMU is enabled.
396+ pub fn bitmap ( & self ) -> & Arc < <Self as IoMemory >:: Bitmap > {
397+ & self . bitmap
398+ }
399+
379400 /// Enable or disable the IOMMU.
380401 ///
381402 /// Disabling the IOMMU switches to pass-through mode, where every access is done directly on
@@ -401,12 +422,42 @@ impl<M: GuestMemory + Clone, I: Iommu> Clone for IommuMemory<M, I> {
401422 inner : self . inner . clone ( ) ,
402423 iommu : Arc :: clone ( & self . iommu ) ,
403424 use_iommu : self . use_iommu ,
425+ bitmap : Arc :: clone ( & self . bitmap ) ,
426+ }
427+ }
428+ }
429+
430+ impl < M : GuestMemory + Debug , I : Iommu > Debug for IommuMemory < M , I >
431+ where
432+ <M :: R as GuestMemoryRegion >:: B : Debug ,
433+ {
434+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
435+ f. debug_struct ( "IommuMemory" )
436+ . field ( "inner" , & self . inner )
437+ . field ( "iommu" , & self . iommu )
438+ . field ( "use_iommu" , & self . use_iommu )
439+ . field ( "bitmap" , & self . bitmap )
440+ . finish ( )
441+ }
442+ }
443+
444+ impl < M : GuestMemory + Default , I : Iommu + Default > Default for IommuMemory < M , I >
445+ where
446+ <M :: R as GuestMemoryRegion >:: B : Default ,
447+ {
448+ fn default ( ) -> Self {
449+ IommuMemory {
450+ inner : Default :: default ( ) ,
451+ iommu : Default :: default ( ) ,
452+ use_iommu : Default :: default ( ) ,
453+ bitmap : Default :: default ( ) ,
404454 }
405455 }
406456}
407457
408458impl < M : GuestMemory , I : Iommu > IoMemory for IommuMemory < M , I > {
409459 type PhysicalMemory = M ;
460+ type Bitmap = <M :: R as GuestMemoryRegion >:: B ;
410461
411462 fn range_accessible ( & self , addr : GuestAddress , count : usize , access : Permissions ) -> bool {
412463 if !self . use_iommu {
@@ -459,7 +510,13 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
459510
460511 if handled == 0 {
461512 break ;
462- } else if handled > count {
513+ }
514+
515+ if access. has_write ( ) {
516+ self . bitmap . mark_dirty ( addr. 0 as usize + total, handled) ;
517+ }
518+
519+ if handled > count {
463520 return Err ( GuestMemoryError :: CallbackOutOfRange ) ;
464521 }
465522
@@ -480,7 +537,7 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
480537 count : usize ,
481538 access : Permissions ,
482539 ) -> GuestMemoryResult <
483- impl Iterator < Item = GuestMemoryResult < VolatileSlice < ' a , bitmap:: MS < ' a , M > > > > ,
540+ impl Iterator < Item = GuestMemoryResult < VolatileSlice < ' a , bitmap:: BS < ' a , Self :: Bitmap > > > > ,
484541 > {
485542 if self . use_iommu {
486543 IommuMemorySliceIterator :: virt ( self , addr, count, access)
@@ -502,8 +559,11 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
502559/// Iterates over [`VolatileSlice`]s that together form an area in an `IommuMemory`.
503560///
504561/// Returned by [`IommuMemory::get_slices()`]
505- #[ derive( Debug ) ]
506562pub struct IommuMemorySliceIterator < ' a , M : GuestMemory , I : Iommu + ' a > {
563+ /// Current IOVA (needed to access the right slice of the IOVA space dirty bitmap)
564+ iova : GuestAddress ,
565+ /// IOVA space dirty bitmap
566+ bitmap : Option < & ' a <M :: R as GuestMemoryRegion >:: B > ,
507567 /// Underlying physical memory (i.e. not the `IommuMemory`)
508568 phys_mem : & ' a M ,
509569 /// IOMMU translation result (i.e. remaining physical regions to visit)
@@ -520,6 +580,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
520580 /// the underlying physical memory for the given address range.
521581 fn phys ( mem : & ' a IommuMemory < M , I > , addr : GuestAddress , count : usize ) -> Self {
522582 IommuMemorySliceIterator {
583+ iova : addr,
584+ bitmap : None ,
523585 phys_mem : & mem. inner ,
524586 translation : None ,
525587 current_translated_iter : Some ( mem. inner . get_slices ( addr, count) ) ,
@@ -538,6 +600,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
538600 ) -> Result < Self , Error > {
539601 let translation = mem. iommu . translate ( addr, count, access) ?;
540602 Ok ( IommuMemorySliceIterator {
603+ iova : addr,
604+ bitmap : Some ( mem. bitmap . as_ref ( ) ) ,
541605 phys_mem : & mem. inner ,
542606 translation : Some ( translation) ,
543607 current_translated_iter : None ,
@@ -569,7 +633,22 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
569633 . as_mut ( )
570634 . and_then ( |iter| iter. next ( ) )
571635 {
572- return Some ( item) ;
636+ let mut item = match item {
637+ Ok ( item) => item,
638+ Err ( err) => return Some ( Err ( err) ) ,
639+ } ;
640+
641+ if let Some ( bitmap) = self . bitmap . as_ref ( ) {
642+ let bitmap_slice = bitmap. slice_at ( self . iova . 0 as usize ) ;
643+ item = item. replace_bitmap ( bitmap_slice) ;
644+ }
645+
646+ self . iova = match self . iova . overflowing_add ( item. len ( ) as GuestUsize ) {
647+ ( x @ GuestAddress ( 0 ) , _) | ( x, false ) => x,
648+ ( _, true ) => return Some ( Err ( GuestMemoryError :: GuestAddressOverflow ) ) ,
649+ } ;
650+
651+ return Some ( Ok ( item) ) ;
573652 }
574653
575654 let next_mapping = self . translation . as_mut ( ) ?. next ( ) ?;
@@ -598,3 +677,19 @@ impl<'a, M: GuestMemory, I: Iommu> Iterator for IommuMemorySliceIterator<'a, M,
598677 }
599678 }
600679}
680+
681+ impl < ' a , M : GuestMemory + Debug , I : Iommu > Debug for IommuMemorySliceIterator < ' a , M , I >
682+ where
683+ I :: IotlbGuard < ' a > : Debug ,
684+ <M :: R as GuestMemoryRegion >:: B : Debug ,
685+ {
686+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
687+ f. debug_struct ( "IommuMemorySliceIterator" )
688+ . field ( "iova" , & self . iova )
689+ . field ( "bitmap" , & self . bitmap )
690+ . field ( "phys_mem" , & self . phys_mem )
691+ . field ( "translation" , & self . translation )
692+ . field ( "current_translated_iter" , & self . current_translated_iter )
693+ . finish ( )
694+ }
695+ }
0 commit comments