diff --git a/Cargo.lock b/Cargo.lock index a8fb59ef0..64feaad67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,6 +656,7 @@ dependencies = [ "hypervisor", "libc", "log", + "thiserror", "versionize", "versionize_derive", "vfio-bindings", diff --git a/pci/Cargo.toml b/pci/Cargo.toml index 2511aee79..b034757bc 100644 --- a/pci/Cargo.toml +++ b/pci/Cargo.toml @@ -5,13 +5,14 @@ authors = ["Samuel Ortiz "] edition = "2018" [dependencies] -anyhow = "1.0" +anyhow = "1.0.42" byteorder = "1.4.3" hypervisor = { path = "../hypervisor" } vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "master" } vmm-sys-util = ">=0.3.1" libc = "0.2.98" log = "0.4.14" +thiserror = "1.0.26" versionize = "0.1.6" versionize_derive = "0.1.4" vm-allocator = { path = "../vm-allocator" } diff --git a/pci/src/vfio.rs b/pci/src/vfio.rs index e710c3b05..7abbabf55 100644 --- a/pci/src/vfio.rs +++ b/pci/src/vfio.rs @@ -9,13 +9,15 @@ use crate::{ PciDevice, PciDeviceError, PciHeaderType, PciSubclass, MSIX_TABLE_ENTRY_SIZE, }; use byteorder::{ByteOrder, LittleEndian}; +use hypervisor::HypervisorVmError; use std::any::Any; +use std::io; use std::os::unix::io::AsRawFd; use std::ptr::null_mut; use std::sync::{Arc, Barrier}; -use std::{fmt, io, result}; +use thiserror::Error; use vfio_bindings::bindings::vfio::*; -use vfio_ioctls::{VfioContainer, VfioDevice, VfioError, VfioIrq}; +use vfio_ioctls::{VfioContainer, VfioDevice, VfioIrq}; use vm_allocator::SystemAllocator; use vm_device::interrupt::{ InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig, @@ -24,50 +26,22 @@ use vm_device::BusDevice; use vm_memory::{Address, GuestAddress, GuestUsize}; use vmm_sys_util::eventfd::EventFd; -#[derive(Debug)] +#[derive(Debug, Error)] pub enum VfioPciError { - AllocateGsi, - DmaMap(VfioError), - DmaUnmap(VfioError), - EnableIntx(VfioError), - EnableMsi(VfioError), - EnableMsix(VfioError), - EventFd(io::Error), - InterruptSourceGroupCreate(io::Error), - IrqFd(hypervisor::HypervisorVmError), - MapRegionGuest(anyhow::Error), + #[error("Failed to DMA map: {0}")] + DmaMap(#[source] vfio_ioctls::VfioError), + #[error("Failed to DMA unmap: {0}")] + DmaUnmap(#[source] vfio_ioctls::VfioError), + #[error("Failed to enable INTx: {0}")] + EnableIntx(#[source] VfioError), + #[error("Failed to enable MSI: {0}")] + EnableMsi(#[source] VfioError), + #[error("Failed to enable MSI-x: {0}")] + EnableMsix(#[source] VfioError), + #[error("Failed to map VFIO PCI region into guest: {0}")] + MapRegionGuest(#[source] HypervisorVmError), + #[error("Failed to notifier's eventfd")] MissingNotifier, - MsiNotConfigured, - MsixNotConfigured, - NewVfioPciDevice, - SetGsiRouting(hypervisor::HypervisorVmError), -} -pub type Result = std::result::Result; - -impl fmt::Display for VfioPciError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - VfioPciError::AllocateGsi => write!(f, "failed to allocate GSI"), - VfioPciError::DmaMap(e) => write!(f, "failed to DMA map: {}", e), - VfioPciError::DmaUnmap(e) => write!(f, "failed to DMA unmap: {}", e), - VfioPciError::EnableIntx(e) => write!(f, "failed to enable INTx: {}", e), - VfioPciError::EnableMsi(e) => write!(f, "failed to enable MSI: {}", e), - VfioPciError::EnableMsix(e) => write!(f, "failed to enable MSI-X: {}", e), - VfioPciError::EventFd(e) => write!(f, "failed to create eventfd: {}", e), - VfioPciError::InterruptSourceGroupCreate(e) => { - write!(f, "failed to create interrupt source group: {}", e) - } - VfioPciError::IrqFd(e) => write!(f, "failed to register irqfd: {}", e), - VfioPciError::MapRegionGuest(e) => { - write!(f, "failed to map VFIO PCI region into guest: {}", e) - } - VfioPciError::MissingNotifier => write!(f, "failed to notifier's eventfd"), - VfioPciError::MsiNotConfigured => write!(f, "MSI interrupt not yet configured"), - VfioPciError::MsixNotConfigured => write!(f, "MSI-X interrupt not yet configured"), - VfioPciError::NewVfioPciDevice => write!(f, "failed to create VFIO PCI device"), - VfioPciError::SetGsiRouting(e) => write!(f, "failed to set GSI routes: {}", e), - } - } } #[derive(Copy, Clone)] @@ -244,6 +218,11 @@ pub struct MmioRegion { pub(crate) host_addr: Option, pub(crate) mmap_size: Option, } +#[derive(Debug, Error)] +pub enum VfioError { + #[error("Kernel VFIO error: {0}")] + KernelVfio(#[source] vfio_ioctls::VfioError), +} pub(crate) trait Vfio { fn read_config_byte(&self, offset: u32) -> u8 { @@ -277,19 +256,19 @@ pub(crate) trait Vfio { self.region_write(VFIO_PCI_CONFIG_REGION_INDEX, offset.into(), data) } - fn enable_msi(&self, fds: Vec<&EventFd>) -> std::result::Result<(), VfioError> { + fn enable_msi(&self, fds: Vec<&EventFd>) -> Result<(), VfioError> { self.enable_irq(VFIO_PCI_MSI_IRQ_INDEX, fds) } - fn disable_msi(&self) -> std::result::Result<(), VfioError> { + fn disable_msi(&self) -> Result<(), VfioError> { self.disable_irq(VFIO_PCI_MSI_IRQ_INDEX) } - fn enable_msix(&self, fds: Vec<&EventFd>) -> std::result::Result<(), VfioError> { + fn enable_msix(&self, fds: Vec<&EventFd>) -> Result<(), VfioError> { self.enable_irq(VFIO_PCI_MSIX_IRQ_INDEX, fds) } - fn disable_msix(&self) -> std::result::Result<(), VfioError> { + fn disable_msix(&self) -> Result<(), VfioError> { self.disable_irq(VFIO_PCI_MSIX_IRQ_INDEX) } @@ -305,19 +284,15 @@ pub(crate) trait Vfio { unimplemented!() } - fn enable_irq( - &self, - _irq_index: u32, - _event_fds: Vec<&EventFd>, - ) -> std::result::Result<(), VfioError> { + fn enable_irq(&self, _irq_index: u32, _event_fds: Vec<&EventFd>) -> Result<(), VfioError> { unimplemented!() } - fn disable_irq(&self, _irq_index: u32) -> std::result::Result<(), VfioError> { + fn disable_irq(&self, _irq_index: u32) -> Result<(), VfioError> { unimplemented!() } - fn unmask_irq(&self, _irq_index: u32) -> std::result::Result<(), VfioError> { + fn unmask_irq(&self, _irq_index: u32) -> Result<(), VfioError> { unimplemented!() } } @@ -345,20 +320,22 @@ impl Vfio for VfioDeviceWrapper { self.device.get_irq_info(irq_index).copied() } - fn enable_irq( - &self, - irq_index: u32, - event_fds: Vec<&EventFd>, - ) -> std::result::Result<(), VfioError> { - self.device.enable_irq(irq_index, event_fds) + fn enable_irq(&self, irq_index: u32, event_fds: Vec<&EventFd>) -> Result<(), VfioError> { + self.device + .enable_irq(irq_index, event_fds) + .map_err(VfioError::KernelVfio) } - fn disable_irq(&self, irq_index: u32) -> std::result::Result<(), VfioError> { - self.device.disable_irq(irq_index) + fn disable_irq(&self, irq_index: u32) -> Result<(), VfioError> { + self.device + .disable_irq(irq_index) + .map_err(VfioError::KernelVfio) } - fn unmask_irq(&self, irq_index: u32) -> std::result::Result<(), VfioError> { - self.device.unmask_irq(irq_index) + fn unmask_irq(&self, irq_index: u32) -> Result<(), VfioError> { + self.device + .unmask_irq(irq_index) + .map_err(VfioError::KernelVfio) } } @@ -373,8 +350,7 @@ impl VfioCommon { &mut self, allocator: &mut SystemAllocator, vfio_wrapper: &dyn Vfio, - ) -> std::result::Result, PciDeviceError> - { + ) -> Result, PciDeviceError> { let mut ranges = Vec::new(); let mut bar_id = VFIO_PCI_BAR0_REGION_INDEX as u32; @@ -537,7 +513,7 @@ impl VfioCommon { pub(crate) fn free_bars( &mut self, allocator: &mut SystemAllocator, - ) -> std::result::Result<(), PciDeviceError> { + ) -> Result<(), PciDeviceError> { for region in self.mmio_regions.iter() { match region.type_ { PciBarRegionType::IoRegion => { @@ -652,7 +628,7 @@ impl VfioCommon { } } - pub(crate) fn enable_intx(&mut self, wrapper: &dyn Vfio) -> Result<()> { + pub(crate) fn enable_intx(&mut self, wrapper: &dyn Vfio) -> Result<(), VfioPciError> { if let Some(intx) = &mut self.interrupt.intx { if !intx.enabled { if let Some(eventfd) = intx.interrupt_source_group.notifier(0) { @@ -682,7 +658,7 @@ impl VfioCommon { } } - pub(crate) fn enable_msi(&self, wrapper: &dyn Vfio) -> Result<()> { + pub(crate) fn enable_msi(&self, wrapper: &dyn Vfio) -> Result<(), VfioPciError> { if let Some(msi) = &self.interrupt.msi { let mut irq_fds: Vec = Vec::new(); for i in 0..msi.cfg.num_enabled_vectors() { @@ -707,7 +683,7 @@ impl VfioCommon { } } - pub(crate) fn enable_msix(&self, wrapper: &dyn Vfio) -> Result<()> { + pub(crate) fn enable_msix(&self, wrapper: &dyn Vfio) -> Result<(), VfioPciError> { if let Some(msix) = &self.interrupt.msix { let mut irq_fds: Vec = Vec::new(); for i in 0..msix.bar.table_entries.len() { @@ -736,7 +712,7 @@ impl VfioCommon { &mut self, legacy_interrupt_group: Option>, wrapper: &dyn Vfio, - ) -> Result<()> { + ) -> Result<(), VfioPciError> { if let Some(irq_info) = wrapper.get_irq_info(VFIO_PCI_INTX_IRQ_INDEX) { if irq_info.count == 0 { // A count of 0 means the INTx IRQ is not supported, therefore @@ -762,7 +738,7 @@ impl VfioCommon { offset: u64, data: &[u8], wrapper: &dyn Vfio, - ) -> Result<()> { + ) -> Result<(), VfioPciError> { match self.interrupt.update_msi(offset, data) { Some(InterruptUpdateAction::EnableMsi) => { // Disable INTx before we can enable MSI @@ -785,7 +761,7 @@ impl VfioCommon { offset: u64, data: &[u8], wrapper: &dyn Vfio, - ) -> Result<()> { + ) -> Result<(), VfioPciError> { match self.interrupt.update_msix(offset, data) { Some(InterruptUpdateAction::EnableMsix) => { // Disable INTx before we can enable MSI-X @@ -973,7 +949,7 @@ impl VfioPciDevice { msi_interrupt_manager: &Arc>, legacy_interrupt_group: Option>, iommu_attached: bool, - ) -> Result { + ) -> Result { let device = Arc::new(device); device.reset(); @@ -1029,7 +1005,11 @@ impl VfioPciDevice { /// * `vm` - The VM object. It is used to set the VFIO MMIO regions /// as user memory regions. /// * `mem_slot` - The closure to return a memory slot. - pub fn map_mmio_regions(&mut self, vm: &Arc, mem_slot: F) -> Result<()> + pub fn map_mmio_regions( + &mut self, + vm: &Arc, + mem_slot: F, + ) -> Result<(), VfioPciError> where F: Fn() -> u32, { @@ -1088,7 +1068,7 @@ impl VfioPciDevice { ); vm.create_user_memory_region(mem_region) - .map_err(|e| VfioPciError::MapRegionGuest(e.into()))?; + .map_err(VfioPciError::MapRegionGuest)?; // Update the region with memory mapped info. region.mem_slot = Some(slot); @@ -1133,7 +1113,7 @@ impl VfioPciDevice { } } - pub fn dma_map(&self, iova: u64, size: u64, user_addr: u64) -> Result<()> { + pub fn dma_map(&self, iova: u64, size: u64, user_addr: u64) -> Result<(), VfioPciError> { if !self.iommu_attached { self.container .vfio_dma_map(iova, size, user_addr) @@ -1143,7 +1123,7 @@ impl VfioPciDevice { Ok(()) } - pub fn dma_unmap(&self, iova: u64, size: u64) -> Result<()> { + pub fn dma_unmap(&self, iova: u64, size: u64) -> Result<(), VfioPciError> { if !self.iommu_attached { self.container .vfio_dma_unmap(iova, size) @@ -1213,15 +1193,11 @@ impl PciDevice for VfioPciDevice { fn allocate_bars( &mut self, allocator: &mut SystemAllocator, - ) -> std::result::Result, PciDeviceError> - { + ) -> Result, PciDeviceError> { self.common.allocate_bars(allocator, &self.vfio_wrapper) } - fn free_bars( - &mut self, - allocator: &mut SystemAllocator, - ) -> std::result::Result<(), PciDeviceError> { + fn free_bars(&mut self, allocator: &mut SystemAllocator) -> Result<(), PciDeviceError> { self.common.free_bars(allocator) } @@ -1259,7 +1235,7 @@ impl PciDevice for VfioPciDevice { .write_bar(base, offset, data, &self.vfio_wrapper) } - fn move_bar(&mut self, old_base: u64, new_base: u64) -> result::Result<(), io::Error> { + fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), io::Error> { for region in self.common.mmio_regions.iter_mut() { if region.start.raw_value() == old_base { region.start = GuestAddress(new_base);