diff --git a/Cargo.lock b/Cargo.lock index f073e3cf2..91e96a9fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -970,6 +970,7 @@ dependencies = [ "pci 0.1.0", "vfio-bindings 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "vm-allocator 0.1.0", + "vm-device 0.1.0", "vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)", "vmm-sys-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/vfio/Cargo.toml b/vfio/Cargo.toml index 43eb03a92..a6edc54b5 100644 --- a/vfio/Cargo.toml +++ b/vfio/Cargo.toml @@ -13,6 +13,7 @@ log = "0.4.8" pci = { path = "../pci" } vfio-bindings = "0.1.0" vm-allocator = { path = "../vm-allocator" } +vm-device = { path = "../vm-device" } vmm-sys-util = "0.1.1" [dependencies.vm-memory] diff --git a/vfio/src/lib.rs b/vfio/src/lib.rs index c3a0b915c..b2feea786 100644 --- a/vfio/src/lib.rs +++ b/vfio/src/lib.rs @@ -14,6 +14,7 @@ extern crate log; extern crate pci; extern crate vfio_bindings; extern crate vm_allocator; +extern crate vm_device; extern crate vm_memory; #[macro_use] extern crate vmm_sys_util; @@ -24,7 +25,7 @@ mod vfio_pci; use std::mem::size_of; -pub use vfio_device::{VfioDevice, VfioError}; +pub use vfio_device::{VfioContainer, VfioDevice, VfioDmaMapping, VfioError}; pub use vfio_pci::{VfioPciDevice, VfioPciError}; // Returns a `Vec` with a size in bytes at least as large as `size_in_bytes`. diff --git a/vfio/src/vfio_device.rs b/vfio/src/vfio_device.rs index 6230fe0de..dc2df5c81 100644 --- a/vfio/src/vfio_device.rs +++ b/vfio/src/vfio_device.rs @@ -14,11 +14,13 @@ use std::mem; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::os::unix::prelude::FileExt; use std::path::{Path, PathBuf}; +use std::result; use std::sync::{Arc, RwLock}; use std::u32; use vfio_bindings::bindings::vfio::*; use vfio_ioctls::*; -use vm_memory::{Address, GuestMemory, GuestMemoryMmap, GuestMemoryRegion}; +use vm_device::ExternalDmaMapping; +use vm_memory::{Address, GuestAddress, GuestMemory, GuestMemoryMmap, GuestMemoryRegion}; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::ioctl::*; @@ -506,6 +508,68 @@ impl VfioDeviceInfo { } } +/// 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 { + pub fn new(container: Arc, memory: Arc>) -> Self { + VfioDmaMapping { container, memory } + } +} + +impl ExternalDmaMapping for VfioDmaMapping { + fn map(&self, iova: u64, gpa: u64, size: u64) -> result::Result<(), io::Error> { + let user_addr = if let Some(addr) = self + .memory + .read() + .unwrap() + .get_host_address(GuestAddress(gpa)) + { + addr 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) -> 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 + ), + ) + }) + } +} + /// Vfio device for exposing regions which could be read/write to kernel vfio device. pub struct VfioDevice { device: File, diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 74c39308c..2c9059482 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -29,8 +29,8 @@ serde = {version = ">=1.0.27", features = ["rc"] } serde_derive = ">=1.0.27" serde_json = ">=1.0.9" vfio = { path = "../vfio", optional = true } -vm-virtio = { path = "../vm-virtio" } vm-allocator = { path = "../vm-allocator" } +vm-virtio = { path = "../vm-virtio" } vmm-sys-util = "0.1.1" signal-hook = "0.1.10" threadpool = "1.0" diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 0d00f0386..e59387266 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -36,7 +36,7 @@ use std::ptr::null_mut; use std::result; use std::sync::{Arc, Mutex, RwLock}; #[cfg(feature = "pci_support")] -use vfio::{VfioDevice, VfioPciDevice, VfioPciError}; +use vfio::{VfioDevice, VfioDmaMapping, VfioPciDevice, VfioPciError}; use vm_allocator::SystemAllocator; #[cfg(feature = "mmio_support")] use vm_memory::GuestAddress; @@ -998,15 +998,18 @@ impl DeviceManager { // global device ID. let device_id = pci.next_device_id() << 3; - if device_cfg.iommu { - iommu_attached_list.push(device_id); - } - let vfio_device = VfioDevice::new(&device_cfg.path, device_fd.clone(), vm_info.memory.clone()) .map_err(DeviceManagerError::VfioCreate)?; - let _vfio_container = vfio_device.get_container(); + if device_cfg.iommu { + let _vfio_mapping = VfioDmaMapping::new( + vfio_device.get_container(), + Arc::clone(vm_info.memory), + ); + + iommu_attached_list.push(device_id); + } let mut vfio_pci_device = VfioPciDevice::new(vm_info.vm_fd, allocator, vfio_device) .map_err(DeviceManagerError::VfioPciCreate)?;