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 , IoMemorySliceIterator ,
17
18
Result as GuestMemoryResult ,
18
19
} ;
19
- use crate :: { bitmap, GuestAddress , GuestMemory , IoMemory , Permissions , VolatileSlice } ;
20
+ use crate :: {
21
+ Address , GuestAddress , GuestMemory , GuestMemoryRegion , GuestUsize , IoMemory , Permissions ,
22
+ VolatileSlice ,
23
+ } ;
20
24
use rangemap:: RangeMap ;
21
25
use std:: cmp;
22
- use std:: fmt:: Debug ;
26
+ use std:: fmt:: { self , Debug } ;
23
27
use std:: num:: Wrapping ;
24
28
use std:: ops:: { Deref , Range } ;
25
29
use std:: sync:: Arc ;
@@ -182,7 +186,15 @@ pub struct IotlbFails {
182
186
/// The underlying [`GuestMemory`] is basically the physical memory, and the [`Iommu`] translates
183
187
/// the I/O virtual address space that `IommuMemory` provides into that underlying physical address
184
188
/// 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).
186
198
pub struct IommuMemory < M : GuestMemory , I : Iommu > {
187
199
/// Physical memory
188
200
inner : M ,
@@ -191,6 +203,8 @@ pub struct IommuMemory<M: GuestMemory, I: Iommu> {
191
203
/// Whether the IOMMU is even to be used or not; disabling it makes this a pass-through to
192
204
/// `inner`.
193
205
use_iommu : bool ,
206
+ /// Dirty bitmap to use for IOVA accesses
207
+ bitmap : Arc < <M :: R as GuestMemoryRegion >:: B > ,
194
208
}
195
209
196
210
impl IommuMapping {
@@ -354,27 +368,36 @@ impl TryFrom<Range<u64>> for IovaRange {
354
368
355
369
impl < M : GuestMemory , I : Iommu > IommuMemory < M , I > {
356
370
/// 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 {
358
372
IommuMemory {
359
373
inner,
360
374
iommu : Arc :: new ( iommu) ,
361
375
use_iommu,
376
+ bitmap : Arc :: new ( bitmap) ,
362
377
}
363
378
}
364
379
365
380
/// Create a new version of `self` with the underlying physical memory replaced.
366
381
///
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.)
370
385
pub fn inner_replaced ( & self , inner : M ) -> Self {
371
386
IommuMemory {
372
387
inner,
373
388
iommu : Arc :: clone ( & self . iommu ) ,
374
389
use_iommu : self . use_iommu ,
390
+ bitmap : Arc :: clone ( & self . bitmap ) ,
375
391
}
376
392
}
377
393
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
+
378
401
/// Enable or disable the IOMMU.
379
402
///
380
403
/// 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> {
400
423
inner : self . inner . clone ( ) ,
401
424
iommu : Arc :: clone ( & self . iommu ) ,
402
425
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 ( ) ,
403
455
}
404
456
}
405
457
}
406
458
407
459
impl < M : GuestMemory , I : Iommu > IoMemory for IommuMemory < M , I > {
408
460
type PhysicalMemory = M ;
461
+ type Bitmap = <M :: R as GuestMemoryRegion >:: B ;
409
462
410
463
fn check_range ( & self , addr : GuestAddress , count : usize , access : Permissions ) -> bool {
411
464
if !self . use_iommu {
@@ -424,7 +477,7 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
424
477
addr : GuestAddress ,
425
478
count : usize ,
426
479
access : Permissions ,
427
- ) -> GuestMemoryResult < impl IoMemorySliceIterator < ' a , bitmap:: MS < ' a , M > > > {
480
+ ) -> GuestMemoryResult < impl IoMemorySliceIterator < ' a , bitmap:: BS < ' a , Self :: Bitmap > > > {
428
481
if self . use_iommu {
429
482
IommuMemorySliceIterator :: virt ( self , addr, count, access)
430
483
. map_err ( GuestMemoryError :: IommuError )
@@ -445,8 +498,11 @@ impl<M: GuestMemory, I: Iommu> IoMemory for IommuMemory<M, I> {
445
498
/// Iterates over [`VolatileSlice`]s that together form an area in an `IommuMemory`.
446
499
///
447
500
/// Returned by [`IommuMemory::get_slices()`]
448
- #[ derive( Debug ) ]
449
501
pub 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 > ,
450
506
/// Underlying physical memory (i.e. not the `IommuMemory`)
451
507
phys_mem : & ' a M ,
452
508
/// IOMMU translation result (i.e. remaining physical regions to visit)
@@ -463,6 +519,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
463
519
/// the underlying physical memory for the given address range.
464
520
fn phys ( mem : & ' a IommuMemory < M , I > , addr : GuestAddress , count : usize ) -> Self {
465
521
IommuMemorySliceIterator {
522
+ iova : addr,
523
+ bitmap : None ,
466
524
phys_mem : & mem. inner ,
467
525
translation : None ,
468
526
current_translated_iter : Some ( mem. inner . get_slices ( addr, count) ) ,
@@ -481,6 +539,8 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
481
539
) -> Result < Self , Error > {
482
540
let translation = mem. iommu . translate ( addr, count, access) ?;
483
541
Ok ( IommuMemorySliceIterator {
542
+ iova : addr,
543
+ bitmap : Some ( mem. bitmap . as_ref ( ) ) ,
484
544
phys_mem : & mem. inner ,
485
545
translation : Some ( translation) ,
486
546
current_translated_iter : None ,
@@ -512,7 +572,22 @@ impl<'a, M: GuestMemory, I: Iommu> IommuMemorySliceIterator<'a, M, I> {
512
572
. as_mut ( )
513
573
. and_then ( |iter| iter. next ( ) )
514
574
{
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) ) ;
516
591
}
517
592
518
593
let next_mapping = self . translation . as_mut ( ) ?. next ( ) ?;
@@ -546,3 +621,19 @@ impl<'a, M: GuestMemory, I: Iommu> IoMemorySliceIterator<'a, bitmap::MS<'a, M>>
546
621
for IommuMemorySliceIterator < ' a , M , I >
547
622
{
548
623
}
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