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:: iter:: FusedIterator ;
2428use std:: num:: Wrapping ;
2529use std:: ops:: { Deref , Range } ;
@@ -183,7 +187,19 @@ pub struct IotlbFails {
183187/// The underlying [`GuestMemory`] is basically the physical memory, and the [`Iommu`] translates
184188/// the I/O virtual address space that `IommuMemory` provides into that underlying physical address
185189/// space.
186- #[ derive( Debug , Default ) ]
190+ ///
191+ /// Note that this type’s implementation of memory write tracking (“logging”) is specific to what
192+ /// is required by vhost-user:
193+ /// - When the IOMMU is disabled ([`IommuMemory::set_iommu_enabled()`]), writes to memory are
194+ /// tracked by the underlying [`GuestMemory`] in its bitmap(s).
195+ /// - When it is enabled, they are instead tracked in the [`IommuMemory`]’s dirty bitmap; the
196+ /// offset in the bitmap is calculated from the write’s IOVA.
197+ ///
198+ /// That is, there are two bitmap levels, one in the underlying [`GuestMemory`], and one in
199+ /// [`IommuMemory`]. The former is used when the IOMMU is disabled, the latter when it is enabled.
200+ ///
201+ /// If you need a different model (e.g. always use the [`GuestMemory`] bitmaps), you should not use
202+ /// this type.
187203pub struct IommuMemory < M : GuestMemory , I : Iommu > {
188204 /// Physical memory
189205 backend : M ,
@@ -192,6 +208,8 @@ pub struct IommuMemory<M: GuestMemory, I: Iommu> {
192208 /// Whether the IOMMU is even to be used or not; disabling it makes this a pass-through to
193209 /// `backend`.
194210 use_iommu : bool ,
211+ /// Dirty bitmap to use for IOVA accesses
212+ bitmap : Arc < <M :: R as GuestMemoryRegion >:: B > ,
195213}
196214
197215impl IommuMapping {
@@ -355,27 +373,36 @@ impl TryFrom<Range<u64>> for IovaRange {
355373
356374impl < M : GuestMemory , I : Iommu > IommuMemory < M , I > {
357375 /// Create a new `IommuMemory` instance.
358- pub fn new ( backend : M , iommu : I , use_iommu : bool ) -> Self {
376+ pub fn new ( backend : M , iommu : I , use_iommu : bool , bitmap : < Self as IoMemory > :: Bitmap ) -> Self {
359377 IommuMemory {
360378 backend,
361379 iommu : Arc :: new ( iommu) ,
362380 use_iommu,
381+ bitmap : Arc :: new ( bitmap) ,
363382 }
364383 }
365384
366385 /// Create a new version of `self` with the underlying physical memory replaced.
367386 ///
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.)
387+ /// Note that the inner `Arc` references to the IOMMU and bitmap are cloned, i.e. both the
388+ /// existing and the new `IommuMemory` object will share the IOMMU and bitmap instances . (The
389+ /// `use_iommu` flag however is copied, so is independent between the two instances.)
371390 pub fn with_replaced_backend ( & self , new_backend : M ) -> Self {
372391 IommuMemory {
373392 backend : new_backend,
374393 iommu : Arc :: clone ( & self . iommu ) ,
375394 use_iommu : self . use_iommu ,
395+ bitmap : Arc :: clone ( & self . bitmap ) ,
376396 }
377397 }
378398
399+ /// Return a reference to the IOVA address space's dirty bitmap.
400+ ///
401+ /// This bitmap tracks write accesses done while the IOMMU is enabled.
402+ pub fn bitmap ( & self ) -> & Arc < <Self as IoMemory >:: Bitmap > {
403+ & self . bitmap
404+ }
405+
379406 /// Enable or disable the IOMMU.
380407 ///
381408 /// Disabling the IOMMU switches to pass-through mode, where every access is done directly on
@@ -409,12 +436,42 @@ impl<M: GuestMemory + Clone, I: Iommu> Clone for IommuMemory<M, I> {
409436 backend : self . backend . clone ( ) ,
410437 iommu : Arc :: clone ( & self . iommu ) ,
411438 use_iommu : self . use_iommu ,
439+ bitmap : Arc :: clone ( & self . bitmap ) ,
440+ }
441+ }
442+ }
443+
444+ impl < M : GuestMemory + Debug , I : Iommu > Debug for IommuMemory < M , I >
445+ where
446+ <M :: R as GuestMemoryRegion >:: B : Debug ,
447+ {
448+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
449+ f. debug_struct ( "IommuMemory" )
450+ . field ( "backend" , & self . backend )
451+ . field ( "iommu" , & self . iommu )
452+ . field ( "use_iommu" , & self . use_iommu )
453+ . field ( "bitmap" , & self . bitmap )
454+ . finish ( )
455+ }
456+ }
457+
458+ impl < M : GuestMemory + Default , I : Iommu + Default > Default for IommuMemory < M , I >
459+ where
460+ <M :: R as GuestMemoryRegion >:: B : Default ,
461+ {
462+ fn default ( ) -> Self {
463+ IommuMemory {
464+ backend : Default :: default ( ) ,
465+ iommu : Default :: default ( ) ,
466+ use_iommu : Default :: default ( ) ,
467+ bitmap : Default :: default ( ) ,
412468 }
413469 }
414470}
415471
416472impl < M : GuestMemory , I : Iommu > IoMemory for IommuMemory < M , I > {
417473 type PhysicalMemory = M ;
474+ type Bitmap = <M :: R as GuestMemoryRegion >:: B ;
418475
419476 fn check_range ( & self , addr : GuestAddress , count : usize , access : Permissions ) -> bool {
420477 if !self . use_iommu {
@@ -434,7 +491,7 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
434491 addr : GuestAddress ,
435492 count : usize ,
436493 access : Permissions ,
437- ) -> GuestMemoryResult < impl IoMemorySliceIterator < ' a , bitmap:: MS < ' a , M > > > {
494+ ) -> GuestMemoryResult < impl IoMemorySliceIterator < ' a , bitmap:: BS < ' a , Self :: Bitmap > > > {
438495 if self . use_iommu {
439496 IommuMemorySliceIterator :: virt ( self , addr, count, access)
440497 . map_err ( GuestMemoryError :: IommuError )
@@ -455,8 +512,11 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
455512/// Iterates over [`VolatileSlice`]s that together form an area in an `IommuMemory`.
456513///
457514/// Returned by [`IommuMemory::get_slices()`]
458- #[ derive( Debug ) ]
459515pub struct IommuMemorySliceIterator < ' a , M : GuestMemory , I : Iommu + ' a > {
516+ /// Current IOVA (needed to access the right slice of the IOVA space dirty bitmap)
517+ iova : GuestAddress ,
518+ /// IOVA space dirty bitmap
519+ bitmap : Option < & ' a <M :: R as GuestMemoryRegion >:: B > ,
460520 /// Underlying physical memory (i.e. not the `IommuMemory`)
461521 phys_mem : & ' a M ,
462522 /// IOMMU translation result (i.e. remaining physical regions to visit)
@@ -473,6 +533,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
473533 /// the underlying physical memory for the given address range.
474534 fn phys ( mem : & ' a IommuMemory < M , I > , addr : GuestAddress , count : usize ) -> Self {
475535 IommuMemorySliceIterator {
536+ iova : addr,
537+ bitmap : None ,
476538 phys_mem : & mem. backend ,
477539 translation : None ,
478540 current_translated_iter : Some ( mem. backend . get_slices ( addr, count) ) ,
@@ -491,6 +553,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
491553 ) -> Result < Self , Error > {
492554 let translation = mem. iommu . translate ( addr, count, access) ?;
493555 Ok ( IommuMemorySliceIterator {
556+ iova : addr,
557+ bitmap : Some ( mem. bitmap . as_ref ( ) ) ,
494558 phys_mem : & mem. backend ,
495559 translation : Some ( translation) ,
496560 current_translated_iter : None ,
@@ -522,7 +586,22 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
522586 . as_mut ( )
523587 . and_then ( |iter| iter. next ( ) )
524588 {
525- return Some ( item) ;
589+ let mut item = match item {
590+ Ok ( item) => item,
591+ Err ( err) => return Some ( Err ( err) ) ,
592+ } ;
593+
594+ if let Some ( bitmap) = self . bitmap . as_ref ( ) {
595+ let bitmap_slice = bitmap. slice_at ( self . iova . 0 as usize ) ;
596+ item = item. replace_bitmap ( bitmap_slice) ;
597+ }
598+
599+ self . iova = match self . iova . overflowing_add ( item. len ( ) as GuestUsize ) {
600+ ( x @ GuestAddress ( 0 ) , _) | ( x, false ) => x,
601+ ( _, true ) => return Some ( Err ( GuestMemoryError :: GuestAddressOverflow ) ) ,
602+ } ;
603+
604+ return Some ( Ok ( item) ) ;
526605 }
527606
528607 let next_mapping = self . translation . as_mut ( ) ?. next ( ) ?;
@@ -563,3 +642,19 @@ impl<'a, M: GuestMemory, I: Iommu> IoMemorySliceIterator<'a, bitmap::MS<'a, M>>
563642 for IommuMemorySliceIterator < ' a , M , I >
564643{
565644}
645+
646+ impl < ' a , M : GuestMemory + Debug , I : Iommu > Debug for IommuMemorySliceIterator < ' a , M , I >
647+ where
648+ I :: IotlbGuard < ' a > : Debug ,
649+ <M :: R as GuestMemoryRegion >:: B : Debug ,
650+ {
651+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
652+ f. debug_struct ( "IommuMemorySliceIterator" )
653+ . field ( "iova" , & self . iova )
654+ . field ( "bitmap" , & self . bitmap )
655+ . field ( "phys_mem" , & self . phys_mem )
656+ . field ( "translation" , & self . translation )
657+ . field ( "current_translated_iter" , & self . current_translated_iter )
658+ . finish ( )
659+ }
660+ }
0 commit comments