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 , IoMemorySliceIterator ,
1718 Result as GuestMemoryResult ,
1819} ;
19- use crate :: { bitmap, GuestAddress , GuestMemory , IoMemory , Permissions , VolatileSlice } ;
20+ use crate :: {
21+ Address , GuestAddress , GuestMemory , GuestMemoryRegion , GuestUsize , IoMemory , Permissions ,
22+ VolatileSlice ,
23+ } ;
2024use rangemap:: RangeMap ;
2125use std:: cmp;
22- use std:: fmt:: Debug ;
26+ use std:: fmt:: { self , Debug } ;
2327use std:: num:: Wrapping ;
2428use std:: ops:: { Deref , Range } ;
2529use std:: sync:: Arc ;
@@ -182,7 +186,15 @@ pub struct IotlbFails {
182186/// The underlying [`GuestMemory`] is basically the physical memory, and the [`Iommu`] translates
183187/// the I/O virtual address space that `IommuMemory` provides into that underlying physical address
184188/// space.
185- #[ derive( Debug , Default ) ]
189+ ///
190+ /// Note on memory write tracking (“logging”):
191+ /// - When the IOMMU is disabled ([`IommuMemory::set_iommu_enabled()`]), writes to memory are
192+ /// tracked by the underlying [`GuestMemory`] in its bitmap(s).
193+ /// - When it is enabled, they are instead tracked in the [`IommuMemory`]’s dirty bitmap; the
194+ /// offset in the bitmap is calculated from the write’s IOVA.
195+ ///
196+ /// Therefore, this type should only be used when this is the desired behavior (IOVA-based memory
197+ /// write logging when IOMMU is used).
186198pub struct IommuMemory < M : GuestMemory , I : Iommu > {
187199 /// Physical memory
188200 inner : M ,
@@ -191,6 +203,8 @@ pub struct IommuMemory<M: GuestMemory, I: Iommu> {
191203 /// Whether the IOMMU is even to be used or not; disabling it makes this a pass-through to
192204 /// `inner`.
193205 use_iommu : bool ,
206+ /// Dirty bitmap to use for IOVA accesses
207+ bitmap : Arc < <M :: R as GuestMemoryRegion >:: B > ,
194208}
195209
196210impl IommuMapping {
@@ -354,27 +368,36 @@ impl TryFrom<Range<u64>> for IovaRange {
354368
355369impl < M : GuestMemory , I : Iommu > IommuMemory < M , I > {
356370 /// Create a new `IommuMemory` instance.
357- pub fn new ( inner : M , iommu : I , use_iommu : bool ) -> Self {
371+ pub fn new ( inner : M , iommu : I , use_iommu : bool , bitmap : < Self as IoMemory > :: Bitmap ) -> Self {
358372 IommuMemory {
359373 inner,
360374 iommu : Arc :: new ( iommu) ,
361375 use_iommu,
376+ bitmap : Arc :: new ( bitmap) ,
362377 }
363378 }
364379
365380 /// Create a new version of `self` with the underlying physical memory replaced.
366381 ///
367- /// Note that the inner `Arc` reference to the IOMMU is cloned, i.e. both the existing and the
368- /// new `IommuMemory` object will share an IOMMU instance . (The `use_iommu` flag however is
369- /// copied, so is independent between the two instances.)
382+ /// Note that the inner `Arc` references to the IOMMU and bitmap are cloned, i.e. both the
383+ /// existing and the new `IommuMemory` object will share the IOMMU and bitmap instances . (The
384+ /// `use_iommu` flag however is copied, so is independent between the two instances.)
370385 pub fn inner_replaced ( & self , inner : M ) -> Self {
371386 IommuMemory {
372387 inner,
373388 iommu : Arc :: clone ( & self . iommu ) ,
374389 use_iommu : self . use_iommu ,
390+ bitmap : Arc :: clone ( & self . bitmap ) ,
375391 }
376392 }
377393
394+ /// Return a reference to the IOVA address space's dirty bitmap.
395+ ///
396+ /// This bitmap tracks write accesses done while the IOMMU is enabled.
397+ pub fn bitmap ( & self ) -> & Arc < <Self as IoMemory >:: Bitmap > {
398+ & self . bitmap
399+ }
400+
378401 /// Enable or disable the IOMMU.
379402 ///
380403 /// Disabling the IOMMU switches to pass-through mode, where every access is done directly on
@@ -400,12 +423,42 @@ impl<M: GuestMemory + Clone, I: Iommu> Clone for IommuMemory<M, I> {
400423 inner : self . inner . clone ( ) ,
401424 iommu : Arc :: clone ( & self . iommu ) ,
402425 use_iommu : self . use_iommu ,
426+ bitmap : Arc :: clone ( & self . bitmap ) ,
427+ }
428+ }
429+ }
430+
431+ impl < M : GuestMemory + Debug , I : Iommu > Debug for IommuMemory < M , I >
432+ where
433+ <M :: R as GuestMemoryRegion >:: B : Debug ,
434+ {
435+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
436+ f. debug_struct ( "IommuMemory" )
437+ . field ( "inner" , & self . inner )
438+ . field ( "iommu" , & self . iommu )
439+ . field ( "use_iommu" , & self . use_iommu )
440+ . field ( "bitmap" , & self . bitmap )
441+ . finish ( )
442+ }
443+ }
444+
445+ impl < M : GuestMemory + Default , I : Iommu + Default > Default for IommuMemory < M , I >
446+ where
447+ <M :: R as GuestMemoryRegion >:: B : Default ,
448+ {
449+ fn default ( ) -> Self {
450+ IommuMemory {
451+ inner : Default :: default ( ) ,
452+ iommu : Default :: default ( ) ,
453+ use_iommu : Default :: default ( ) ,
454+ bitmap : Default :: default ( ) ,
403455 }
404456 }
405457}
406458
407459impl < M : GuestMemory , I : Iommu > IoMemory for IommuMemory < M , I > {
408460 type PhysicalMemory = M ;
461+ type Bitmap = <M :: R as GuestMemoryRegion >:: B ;
409462
410463 fn check_range ( & self , addr : GuestAddress , count : usize , access : Permissions ) -> bool {
411464 if !self . use_iommu {
@@ -424,7 +477,7 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
424477 addr : GuestAddress ,
425478 count : usize ,
426479 access : Permissions ,
427- ) -> GuestMemoryResult < impl IoMemorySliceIterator < ' a , bitmap:: MS < ' a , M > > > {
480+ ) -> GuestMemoryResult < impl IoMemorySliceIterator < ' a , bitmap:: BS < ' a , Self :: Bitmap > > > {
428481 if self . use_iommu {
429482 IommuMemorySliceIterator :: virt ( self , addr, count, access)
430483 . map_err ( GuestMemoryError :: IommuError )
@@ -445,8 +498,11 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
445498/// Iterates over [`VolatileSlice`]s that together form an area in an `IommuMemory`.
446499///
447500/// Returned by [`IommuMemory::get_slices()`]
448- #[ derive( Debug ) ]
449501pub struct IommuMemorySliceIterator < ' a , M : GuestMemory , I : Iommu + ' a > {
502+ /// Current IOVA (needed to access the right slice of the IOVA space dirty bitmap)
503+ iova : GuestAddress ,
504+ /// IOVA space dirty bitmap
505+ bitmap : Option < & ' a <M :: R as GuestMemoryRegion >:: B > ,
450506 /// Underlying physical memory (i.e. not the `IommuMemory`)
451507 phys_mem : & ' a M ,
452508 /// IOMMU translation result (i.e. remaining physical regions to visit)
@@ -463,6 +519,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
463519 /// the underlying physical memory for the given address range.
464520 fn phys ( mem : & ' a IommuMemory < M , I > , addr : GuestAddress , count : usize ) -> Self {
465521 IommuMemorySliceIterator {
522+ iova : addr,
523+ bitmap : None ,
466524 phys_mem : & mem. inner ,
467525 translation : None ,
468526 current_translated_iter : Some ( mem. inner . get_slices ( addr, count) ) ,
@@ -481,6 +539,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
481539 ) -> Result < Self , Error > {
482540 let translation = mem. iommu . translate ( addr, count, access) ?;
483541 Ok ( IommuMemorySliceIterator {
542+ iova : addr,
543+ bitmap : Some ( mem. bitmap . as_ref ( ) ) ,
484544 phys_mem : & mem. inner ,
485545 translation : Some ( translation) ,
486546 current_translated_iter : None ,
@@ -512,7 +572,22 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
512572 . as_mut ( )
513573 . and_then ( |iter| iter. next ( ) )
514574 {
515- return Some ( item) ;
575+ let mut item = match item {
576+ Ok ( item) => item,
577+ Err ( err) => return Some ( Err ( err) ) ,
578+ } ;
579+
580+ if let Some ( bitmap) = self . bitmap . as_ref ( ) {
581+ let bitmap_slice = bitmap. slice_at ( self . iova . 0 as usize ) ;
582+ item = item. replace_bitmap ( bitmap_slice) ;
583+ }
584+
585+ self . iova = match self . iova . overflowing_add ( item. len ( ) as GuestUsize ) {
586+ ( x @ GuestAddress ( 0 ) , _) | ( x, false ) => x,
587+ ( _, true ) => return Some ( Err ( GuestMemoryError :: GuestAddressOverflow ) ) ,
588+ } ;
589+
590+ return Some ( Ok ( item) ) ;
516591 }
517592
518593 let next_mapping = self . translation . as_mut ( ) ?. next ( ) ?;
@@ -546,3 +621,19 @@ impl<'a, M: GuestMemory, I: Iommu> IoMemorySliceIterator<'a, bitmap::MS<'a, M>>
546621 for IommuMemorySliceIterator < ' a , M , I >
547622{
548623}
624+
625+ impl < ' a , M : GuestMemory + Debug , I : Iommu > Debug for IommuMemorySliceIterator < ' a , M , I >
626+ where
627+ I :: IotlbGuard < ' a > : Debug ,
628+ <M :: R as GuestMemoryRegion >:: B : Debug ,
629+ {
630+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
631+ f. debug_struct ( "IommuMemorySliceIterator" )
632+ . field ( "iova" , & self . iova )
633+ . field ( "bitmap" , & self . bitmap )
634+ . field ( "phys_mem" , & self . phys_mem )
635+ . field ( "translation" , & self . translation )
636+ . field ( "current_translated_iter" , & self . current_translated_iter )
637+ . finish ( )
638+ }
639+ }
0 commit comments