12
12
//! IOTLB misses require sending a notification to the front-end and awaiting a reply that supplies
13
13
//! the desired mapping.
14
14
15
+ use crate :: bitmap:: { self , Bitmap } ;
15
16
use crate :: guest_memory:: {
16
17
Error as GuestMemoryError , GuestMemorySliceIterator , Result as GuestMemoryResult ,
17
18
} ;
18
19
use crate :: {
19
- bitmap, GuestAddress , GuestMemory , IoMemory , MemoryRegionAddress , Permissions , VolatileSlice ,
20
+ Address , GuestAddress , GuestMemory , GuestMemoryRegion , GuestUsize , IoMemory ,
21
+ MemoryRegionAddress , Permissions , VolatileSlice ,
20
22
} ;
21
23
use rangemap:: RangeMap ;
22
24
use std:: cmp;
23
- use std:: fmt:: Debug ;
25
+ use std:: fmt:: { self , Debug } ;
24
26
use std:: num:: Wrapping ;
25
27
use std:: ops:: { Deref , Range } ;
26
28
use std:: sync:: Arc ;
@@ -183,7 +185,15 @@ pub struct IotlbFails {
183
185
/// The underlying [`GuestMemory`] is basically the physical memory, and the [`Iommu`] translates
184
186
/// the I/O virtual address space that `IommuMemory` provides into that underlying physical address
185
187
/// 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).
187
197
pub struct IommuMemory < M : GuestMemory , I : Iommu > {
188
198
/// Physical memory
189
199
inner : M ,
@@ -192,6 +202,8 @@ pub struct IommuMemory<M: GuestMemory, I: Iommu> {
192
202
/// Whether the IOMMU is even to be used or not; disabling it makes this a pass-through to
193
203
/// `inner`.
194
204
use_iommu : bool ,
205
+ /// Dirty bitmap to use for IOVA accesses
206
+ bitmap : Arc < <M :: R as GuestMemoryRegion >:: B > ,
195
207
}
196
208
197
209
impl IommuMapping {
@@ -355,27 +367,36 @@ impl TryFrom<Range<u64>> for IovaRange {
355
367
356
368
impl < M : GuestMemory , I : Iommu > IommuMemory < M , I > {
357
369
/// 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 {
359
371
IommuMemory {
360
372
inner,
361
373
iommu : Arc :: new ( iommu) ,
362
374
use_iommu,
375
+ bitmap : Arc :: new ( bitmap) ,
363
376
}
364
377
}
365
378
366
379
/// Create a new version of `self` with the underlying physical memory replaced.
367
380
///
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.)
371
384
pub fn inner_replaced ( & self , inner : M ) -> Self {
372
385
IommuMemory {
373
386
inner,
374
387
iommu : Arc :: clone ( & self . iommu ) ,
375
388
use_iommu : self . use_iommu ,
389
+ bitmap : Arc :: clone ( & self . bitmap ) ,
376
390
}
377
391
}
378
392
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
+
379
400
/// Enable or disable the IOMMU.
380
401
///
381
402
/// 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> {
401
422
inner : self . inner . clone ( ) ,
402
423
iommu : Arc :: clone ( & self . iommu ) ,
403
424
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 ( ) ,
404
454
}
405
455
}
406
456
}
407
457
408
458
impl < M : GuestMemory , I : Iommu > IoMemory for IommuMemory < M , I > {
409
459
type PhysicalMemory = M ;
460
+ type Bitmap = <M :: R as GuestMemoryRegion >:: B ;
410
461
411
462
fn range_accessible ( & self , addr : GuestAddress , count : usize , access : Permissions ) -> bool {
412
463
if !self . use_iommu {
@@ -459,7 +510,13 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
459
510
460
511
if handled == 0 {
461
512
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 {
463
520
return Err ( GuestMemoryError :: CallbackOutOfRange ) ;
464
521
}
465
522
@@ -480,7 +537,7 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
480
537
count : usize ,
481
538
access : Permissions ,
482
539
) -> GuestMemoryResult <
483
- impl Iterator < Item = GuestMemoryResult < VolatileSlice < ' a , bitmap:: MS < ' a , M > > > > ,
540
+ impl Iterator < Item = GuestMemoryResult < VolatileSlice < ' a , bitmap:: BS < ' a , Self :: Bitmap > > > > ,
484
541
> {
485
542
if self . use_iommu {
486
543
IommuMemorySliceIterator :: virt ( self , addr, count, access)
@@ -502,8 +559,11 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
502
559
/// Iterates over [`VolatileSlice`]s that together form an area in an `IommuMemory`.
503
560
///
504
561
/// Returned by [`IommuMemory::get_slices()`]
505
- #[ derive( Debug ) ]
506
562
pub 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 > ,
507
567
/// Underlying physical memory (i.e. not the `IommuMemory`)
508
568
phys_mem : & ' a M ,
509
569
/// IOMMU translation result (i.e. remaining physical regions to visit)
@@ -520,6 +580,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
520
580
/// the underlying physical memory for the given address range.
521
581
fn phys ( mem : & ' a IommuMemory < M , I > , addr : GuestAddress , count : usize ) -> Self {
522
582
IommuMemorySliceIterator {
583
+ iova : addr,
584
+ bitmap : None ,
523
585
phys_mem : & mem. inner ,
524
586
translation : None ,
525
587
current_translated_iter : Some ( mem. inner . get_slices ( addr, count) ) ,
@@ -538,6 +600,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
538
600
) -> Result < Self , Error > {
539
601
let translation = mem. iommu . translate ( addr, count, access) ?;
540
602
Ok ( IommuMemorySliceIterator {
603
+ iova : addr,
604
+ bitmap : Some ( mem. bitmap . as_ref ( ) ) ,
541
605
phys_mem : & mem. inner ,
542
606
translation : Some ( translation) ,
543
607
current_translated_iter : None ,
@@ -569,7 +633,22 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
569
633
. as_mut ( )
570
634
. and_then ( |iter| iter. next ( ) )
571
635
{
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) ) ;
573
652
}
574
653
575
654
let next_mapping = self . translation . as_mut ( ) ?. next ( ) ?;
@@ -598,3 +677,19 @@ impl<'a, M: GuestMemory, I: Iommu> Iterator for IommuMemorySliceIterator<'a, M,
598
677
}
599
678
}
600
679
}
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