Skip to content

Commit e04a8ec

Browse files
authored
vfio_assigned_device: dynamic IOMMU mapping for P2P DMA (#3367)
VFIO device assignment needs peer-to-peer DMA between assigned devices — one device must be able to DMA into another device's BAR. The old VFIO container manager snapshot guest RAM at creation time via GuestMemory::full_mapping() and programmed a static set of IOMMU identity mappings, so device BARs (which are mapped dynamically as the guest configures them) were never visible to the IOMMU. Introduce a DmaTarget trait in the region manager that receives incremental sub-mapping events (map_dma / unmap_dma) as regions are enabled, disabled, or modified. VFIO containers register themselves as DMA mapper consumers via a new DmaMapperClient, and the region manager replays all existing active sub-mappings on registration, then sends live updates as the memory map evolves. This means device BAR mappings are now programmed into every VFIO container's IOMMU as they appear, enabling P2P DMA between assigned devices. The region manager maintains the VaMapper lifecycle for backends that need host VAs (VFIO type1's pin_user_pages), controlled by a needs_va flag at registration. This also sets up the abstraction for future iommufd support, which maps from fd+offset directly and won't need a VaMapper at all.
1 parent 29b0996 commit e04a8ec

12 files changed

Lines changed: 654 additions & 88 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8704,6 +8704,7 @@ dependencies = [
87048704
"chipset_device",
87058705
"guestmem",
87068706
"inspect",
8707+
"membacking",
87078708
"memory_range",
87088709
"mesh",
87098710
"pal_async",

openvmm/membacking/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ mod sys {
8888
/// On Unix, this is an empty (uninhabitable) enum.
8989
pub type RemoteProcess = sys::RemoteProcess;
9090

91+
pub use mapping_manager::Mappable;
9192
pub use memory_manager::DeviceMemoryMapper;
9293
pub use memory_manager::GuestMemoryBuilder;
9394
pub use memory_manager::GuestMemoryClient;
@@ -97,3 +98,6 @@ pub use memory_manager::PartitionAttachError;
9798
pub use memory_manager::RamVisibility;
9899
pub use memory_manager::RamVisibilityControl;
99100
pub use memory_manager::SharedMemoryBacking;
101+
pub use region_manager::DmaMapperClient;
102+
pub use region_manager::DmaMapperHandle;
103+
pub use region_manager::DmaTarget;

openvmm/membacking/src/mapping_manager/va_mapper.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ use std::sync::Arc;
4444
use std::thread::JoinHandle;
4545
use thiserror::Error;
4646

47+
/// A virtual address space mapper for guest memory.
48+
///
49+
/// Maintains a reserved VA range and maps file-backed or anonymous memory
50+
/// into it as directed by the mapping manager.
4751
pub struct VaMapper {
4852
inner: Arc<MapperInner>,
4953
process: Option<RemoteProcess>,
@@ -259,14 +263,17 @@ impl VaMapper {
259263
self.inner.request_mapping(range, false).await
260264
}
261265

266+
/// Returns the base pointer of the VA reservation.
262267
pub fn as_ptr(&self) -> *mut u8 {
263268
self.inner.mapping.as_ptr().cast()
264269
}
265270

271+
/// Returns the length of the VA reservation in bytes.
266272
pub fn len(&self) -> usize {
267273
self.inner.mapping.len()
268274
}
269275

276+
/// Returns the remote process, if this mapper maps into a remote process.
270277
pub fn process(&self) -> Option<&RemoteProcess> {
271278
self.process.as_ref()
272279
}

openvmm/membacking/src/memory_manager/device_memory.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,10 @@ impl MappableGuestMemory for DeviceMemoryControl {
158158
MemoryRange::try_from(gpa..gpa.wrapping_add(self.0.len as u64))
159159
.map_err(|err| io::Error::new(io::ErrorKind::InvalidInput, err))?,
160160
DEVICE_PRIORITY,
161-
false, // device memory cannot currently be a DMA target
161+
false, // not a DMA target: excludes device BARs from
162+
// GuestMemorySharing (vhost-user). IOMMU consumers
163+
// get notified of these mappings via the DmaMapper
164+
// path regardless of this flag.
162165
)
163166
.await
164167
.map_err(io::Error::other)?;

openvmm/membacking/src/memory_manager/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,11 @@ impl GuestMemoryManager {
455455
DeviceMemoryMapper::new(self.region_manager.client().clone())
456456
}
457457

458+
/// Returns a client for registering DMA mappers (VFIO, iommufd).
459+
pub fn dma_mapper_client(&self) -> crate::region_manager::DmaMapperClient {
460+
crate::region_manager::DmaMapperClient::new(self.region_manager.client())
461+
}
462+
458463
/// Returns an object for manipulating the visibility state of different RAM
459464
/// regions.
460465
pub fn ram_visibility_control(&self) -> RamVisibilityControl {

0 commit comments

Comments
 (0)