mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-01 02:55:45 +00:00
vmm, pci: Implement virtio-mem support for vfio-user
Implement the infrastructure that lets a virtio-mem device map the guest memory into the device. This is necessary since with virtio-mem zones memory can be added or removed and the vfio-user device must be informed. Fixes: #3025 Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
e9d67dc405
commit
43365ade2e
@ -26,7 +26,7 @@ pub use self::device::{
|
|||||||
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
pub use self::msi::{msi_num_enabled_vectors, MsiCap, MsiConfig};
|
||||||
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
pub use self::msix::{MsixCap, MsixConfig, MsixTableEntry, MSIX_TABLE_ENTRY_SIZE};
|
||||||
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
pub use self::vfio::{VfioPciDevice, VfioPciError};
|
||||||
pub use self::vfio_user::{VfioUserPciDevice, VfioUserPciDeviceError};
|
pub use self::vfio_user::{VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError};
|
||||||
|
|
||||||
/// PCI has four interrupt pins A->D.
|
/// PCI has four interrupt pins A->D.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -19,10 +19,14 @@ use vfio_bindings::bindings::vfio::*;
|
|||||||
use vfio_ioctls::VfioIrq;
|
use vfio_ioctls::VfioIrq;
|
||||||
use vfio_user::{Client, Error as VfioUserError};
|
use vfio_user::{Client, Error as VfioUserError};
|
||||||
use vm_allocator::SystemAllocator;
|
use vm_allocator::SystemAllocator;
|
||||||
|
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||||
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
|
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
|
||||||
use vm_device::BusDevice;
|
use vm_device::BusDevice;
|
||||||
use vm_memory::bitmap::AtomicBitmap;
|
use vm_memory::bitmap::AtomicBitmap;
|
||||||
use vm_memory::{Address, GuestAddress, GuestMemoryRegion, GuestRegionMmap, GuestUsize};
|
use vm_memory::{
|
||||||
|
Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
|
||||||
|
GuestUsize,
|
||||||
|
};
|
||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
pub struct VfioUserPciDevice {
|
pub struct VfioUserPciDevice {
|
||||||
@ -483,3 +487,57 @@ impl Drop for VfioUserPciDevice {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
|
||||||
|
client: Arc<Mutex<Client>>,
|
||||||
|
memory: Arc<M>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: GuestAddressSpace> VfioUserDmaMapping<M> {
|
||||||
|
pub fn new(client: Arc<Mutex<Client>>, memory: Arc<M>) -> Self {
|
||||||
|
Self { client, memory }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMapping<M> {
|
||||||
|
fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
||||||
|
let mem = self.memory.memory();
|
||||||
|
let guest_addr = GuestAddress(gpa);
|
||||||
|
let region = mem.find_region(guest_addr);
|
||||||
|
|
||||||
|
if let Some(region) = region {
|
||||||
|
let file_offset = region.file_offset().unwrap();
|
||||||
|
let offset = (GuestAddress(gpa).checked_offset_from(region.start_addr())).unwrap()
|
||||||
|
+ file_offset.start();
|
||||||
|
|
||||||
|
self.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.dma_map(offset, iova, size, file_offset.file().as_raw_fd())
|
||||||
|
.map_err(|e| {
|
||||||
|
std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
format!("Error mapping region: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return Err(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
format!("Region not found for 0x{:x}", gpa),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
|
||||||
|
self.client
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.dma_unmap(iova, size)
|
||||||
|
.map_err(|e| {
|
||||||
|
std::io::Error::new(
|
||||||
|
std::io::ErrorKind::Other,
|
||||||
|
format!("Error unmapping region: {}", e),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -123,6 +123,8 @@ fn virtio_mem_thread_rules() -> Vec<(i64, Vec<SeccompRule>)> {
|
|||||||
vec![
|
vec![
|
||||||
(libc::SYS_fallocate, vec![]),
|
(libc::SYS_fallocate, vec![]),
|
||||||
(libc::SYS_ioctl, create_virtio_mem_ioctl_seccomp_rule()),
|
(libc::SYS_ioctl, create_virtio_mem_ioctl_seccomp_rule()),
|
||||||
|
(libc::SYS_recvfrom, vec![]),
|
||||||
|
(libc::SYS_sendmsg, vec![]),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ use libc::{
|
|||||||
};
|
};
|
||||||
use pci::{
|
use pci::{
|
||||||
DeviceRelocation, PciBarRegionType, PciBus, PciConfigMmio, PciDevice, PciRoot, VfioPciDevice,
|
DeviceRelocation, PciBarRegionType, PciBus, PciConfigMmio, PciDevice, PciRoot, VfioPciDevice,
|
||||||
VfioUserPciDevice, VfioUserPciDeviceError,
|
VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError,
|
||||||
};
|
};
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
use pci::{PciConfigIo, PCI_CONFIG_IO_PORT, PCI_CONFIG_IO_PORT_SIZE};
|
||||||
@ -3115,7 +3115,7 @@ impl DeviceManager {
|
|||||||
|
|
||||||
let mut vfio_user_pci_device = VfioUserPciDevice::new(
|
let mut vfio_user_pci_device = VfioUserPciDevice::new(
|
||||||
&self.address_manager.vm,
|
&self.address_manager.vm,
|
||||||
client,
|
client.clone(),
|
||||||
&self.msi_interrupt_manager,
|
&self.msi_interrupt_manager,
|
||||||
legacy_interrupt_group,
|
legacy_interrupt_group,
|
||||||
)
|
)
|
||||||
@ -3127,6 +3127,19 @@ impl DeviceManager {
|
|||||||
})
|
})
|
||||||
.map_err(DeviceManagerError::VfioUserMapRegion)?;
|
.map_err(DeviceManagerError::VfioUserMapRegion)?;
|
||||||
|
|
||||||
|
let memory = self.memory_manager.lock().unwrap().guest_memory();
|
||||||
|
let vfio_user_mapping = Arc::new(VfioUserDmaMapping::new(client, Arc::new(memory)));
|
||||||
|
for virtio_mem_device in self.virtio_mem_devices.iter() {
|
||||||
|
virtio_mem_device
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.add_dma_mapping_handler(
|
||||||
|
VirtioMemMappingSource::Device(pci_device_bdf),
|
||||||
|
vfio_user_mapping.clone(),
|
||||||
|
)
|
||||||
|
.map_err(DeviceManagerError::AddDmaMappingHandlerVirtioMem)?;
|
||||||
|
}
|
||||||
|
|
||||||
for (_, zone) in self.memory_manager.lock().unwrap().memory_zones().iter() {
|
for (_, zone) in self.memory_manager.lock().unwrap().memory_zones().iter() {
|
||||||
for region in zone.regions() {
|
for region in zone.regions() {
|
||||||
vfio_user_pci_device
|
vfio_user_pci_device
|
||||||
@ -3564,6 +3577,7 @@ impl DeviceManager {
|
|||||||
.pci_device_handle
|
.pci_device_handle
|
||||||
.ok_or(DeviceManagerError::MissingPciDevice)?;
|
.ok_or(DeviceManagerError::MissingPciDevice)?;
|
||||||
let (pci_device, bus_device, virtio_device) = match pci_device_handle {
|
let (pci_device, bus_device, virtio_device) = match pci_device_handle {
|
||||||
|
// No need to remove any virtio-mem mapping here as the container outlives all devices
|
||||||
PciDeviceHandle::Vfio(vfio_pci_device) => (
|
PciDeviceHandle::Vfio(vfio_pci_device) => (
|
||||||
Arc::clone(&vfio_pci_device) as Arc<Mutex<dyn PciDevice>>,
|
Arc::clone(&vfio_pci_device) as Arc<Mutex<dyn PciDevice>>,
|
||||||
Arc::clone(&vfio_pci_device) as Arc<Mutex<dyn BusDevice>>,
|
Arc::clone(&vfio_pci_device) as Arc<Mutex<dyn BusDevice>>,
|
||||||
@ -3594,6 +3608,14 @@ impl DeviceManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for virtio_mem_device in self.virtio_mem_devices.iter() {
|
||||||
|
virtio_mem_device
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.remove_dma_mapping_handler(VirtioMemMappingSource::Device(pci_device_bdf))
|
||||||
|
.map_err(DeviceManagerError::RemoveDmaMappingHandlerVirtioMem)?;
|
||||||
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
Arc::clone(&vfio_user_pci_device) as Arc<Mutex<dyn PciDevice>>,
|
Arc::clone(&vfio_user_pci_device) as Arc<Mutex<dyn PciDevice>>,
|
||||||
Arc::clone(&vfio_user_pci_device) as Arc<Mutex<dyn BusDevice>>,
|
Arc::clone(&vfio_user_pci_device) as Arc<Mutex<dyn BusDevice>>,
|
||||||
|
Loading…
Reference in New Issue
Block a user