diff --git a/Cargo.lock b/Cargo.lock index 204cb9de9..cad65f236 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1449,6 +1449,7 @@ dependencies = [ "serde_derive", "serde_json", "thiserror", + "vfio-ioctls", "vm-memory", "vmm-sys-util", ] diff --git a/vm-device/Cargo.toml b/vm-device/Cargo.toml index 81dd3a11c..e27890129 100644 --- a/vm-device/Cargo.toml +++ b/vm-device/Cargo.toml @@ -10,6 +10,7 @@ thiserror = "1.0" serde = {version = ">=1.0.27", features = ["rc"] } serde_derive = ">=1.0.27" serde_json = ">=1.0.9" +vfio-ioctls = { git = "https://github.com/cloud-hypervisor/vfio-ioctls", branch = "ch" } vm-memory = { version = "0.5.0", features = ["backend-mmap"] } vmm-sys-util = ">=0.3.1" diff --git a/vm-device/src/dma_mapping/mod.rs b/vm-device/src/dma_mapping/mod.rs new file mode 100644 index 000000000..62b5ceb1c --- /dev/null +++ b/vm-device/src/dma_mapping/mod.rs @@ -0,0 +1,17 @@ +// Copyright © 2021 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause + +pub mod vfio; + +/// Trait meant for triggering the DMA mapping update related to an external +/// device not managed fully through virtio. It is dedicated to virtio-iommu +/// in order to trigger the map update anytime the mapping is updated from the +/// guest. +pub trait ExternalDmaMapping: Send + Sync { + /// Map a memory range + fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error>; + + /// Unmap a memory range + fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error>; +} diff --git a/vm-device/src/dma_mapping/vfio.rs b/vm-device/src/dma_mapping/vfio.rs new file mode 100644 index 000000000..5ed7f5168 --- /dev/null +++ b/vm-device/src/dma_mapping/vfio.rs @@ -0,0 +1,73 @@ +// Copyright © 2021 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause + +use crate::dma_mapping::ExternalDmaMapping; +use std::io; +use std::sync::Arc; +use vfio_ioctls::VfioContainer; +use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemory}; + +/// This structure implements the ExternalDmaMapping trait. It is meant to +/// be used when the caller tries to provide a way to update the mappings +/// associated with a specific VFIO container. +pub struct VfioDmaMapping { + container: Arc, + memory: Arc, +} + +impl VfioDmaMapping { + /// Create a DmaMapping object. + /// + /// # Parameters + /// * `container`: VFIO container object. + /// * `memory·: guest memory to mmap. + pub fn new(container: Arc, memory: Arc) -> Self { + VfioDmaMapping { container, memory } + } +} + +impl ExternalDmaMapping for VfioDmaMapping { + fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), io::Error> { + let mem = self.memory.memory(); + let guest_addr = GuestAddress(gpa); + let user_addr = if mem.check_range(guest_addr, size as usize) { + mem.get_host_address(guest_addr).unwrap() as u64 + } else { + return Err(io::Error::new( + io::ErrorKind::Other, + format!( + "failed to convert guest address 0x{:x} into \ + host user virtual address", + gpa + ), + )); + }; + + self.container + .vfio_dma_map(iova, size, user_addr) + .map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!( + "failed to map memory for VFIO container, \ + iova 0x{:x}, gpa 0x{:x}, size 0x{:x}: {:?}", + iova, gpa, size, e + ), + ) + }) + } + + fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), io::Error> { + self.container.vfio_dma_unmap(iova, size).map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!( + "failed to unmap memory for VFIO container, \ + iova 0x{:x}, size 0x{:x}: {:?}", + iova, size, e + ), + ) + }) + } +} diff --git a/vm-device/src/lib.rs b/vm-device/src/lib.rs index 90e72e84b..f5977a161 100644 --- a/vm-device/src/lib.rs +++ b/vm-device/src/lib.rs @@ -10,6 +10,7 @@ extern crate vm_memory; use std::io; mod bus; +pub mod dma_mapping; pub mod interrupt; pub use self::bus::{Bus, BusDevice, Error as BusError};