xref: /cloud-hypervisor/pci/src/vfio_user.rs (revision a3692144f0970f8d3f8ef3f8123d6a60ae982771)
19254b74cSRob Bradford // Copyright © 2021 Intel Corporation
29254b74cSRob Bradford //
39254b74cSRob Bradford // SPDX-License-Identifier: Apache-2.0
49254b74cSRob Bradford //
59254b74cSRob Bradford 
69254b74cSRob Bradford use std::any::Any;
79254b74cSRob Bradford use std::os::unix::prelude::AsRawFd;
89254b74cSRob Bradford use std::ptr::null_mut;
99254b74cSRob Bradford use std::sync::{Arc, Barrier, Mutex};
1088a9f799SRob Bradford 
1188a9f799SRob Bradford use hypervisor::HypervisorVmError;
129254b74cSRob Bradford use thiserror::Error;
139254b74cSRob Bradford use vfio_bindings::bindings::vfio::*;
149254b74cSRob Bradford use vfio_ioctls::VfioIrq;
159254b74cSRob Bradford use vfio_user::{Client, Error as VfioUserError};
1681f8a27eSRob Bradford use vm_allocator::{AddressAllocator, MemorySlotAllocator, SystemAllocator};
1743365adeSRob Bradford use vm_device::dma_mapping::ExternalDmaMapping;
189254b74cSRob Bradford use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
196e084572SSebastien Boeuf use vm_device::{BusDevice, Resource};
209254b74cSRob Bradford use vm_memory::bitmap::AtomicBitmap;
2143365adeSRob Bradford use vm_memory::{
2243365adeSRob Bradford     Address, GuestAddress, GuestAddressSpace, GuestMemory, GuestMemoryRegion, GuestRegionMmap,
2343365adeSRob Bradford };
24f48b05eeSSebastien Boeuf use vm_migration::{Migratable, MigratableError, Pausable, Snapshot, Snapshottable, Transportable};
259254b74cSRob Bradford use vmm_sys_util::eventfd::EventFd;
269254b74cSRob Bradford 
2788a9f799SRob Bradford use crate::vfio::{UserMemoryRegion, Vfio, VfioCommon, VfioError, VFIO_COMMON_ID};
2861e57e1cSRuoqing He use crate::{
2961e57e1cSRuoqing He     BarReprogrammingParams, PciBarConfiguration, PciBdf, PciDevice, PciDeviceError, PciSubclass,
3061e57e1cSRuoqing He     VfioPciError,
3161e57e1cSRuoqing He };
3288a9f799SRob Bradford 
339254b74cSRob Bradford pub struct VfioUserPciDevice {
345264d545SSebastien Boeuf     id: String,
359254b74cSRob Bradford     vm: Arc<dyn hypervisor::Vm>,
369254b74cSRob Bradford     client: Arc<Mutex<Client>>,
379254b74cSRob Bradford     common: VfioCommon,
3881f8a27eSRob Bradford     memory_slot_allocator: MemorySlotAllocator,
399254b74cSRob Bradford }
409254b74cSRob Bradford 
419254b74cSRob Bradford #[derive(Error, Debug)]
429254b74cSRob Bradford pub enum VfioUserPciDeviceError {
43*a3692144SPhilipp Schuster     #[error("Client error")]
449254b74cSRob Bradford     Client(#[source] VfioUserError),
45*a3692144SPhilipp Schuster     #[error("Failed to map VFIO PCI region into guest")]
469254b74cSRob Bradford     MapRegionGuest(#[source] HypervisorVmError),
47*a3692144SPhilipp Schuster     #[error("Failed to DMA map")]
489254b74cSRob Bradford     DmaMap(#[source] VfioUserError),
49*a3692144SPhilipp Schuster     #[error("Failed to DMA unmap")]
509254b74cSRob Bradford     DmaUnmap(#[source] VfioUserError),
51*a3692144SPhilipp Schuster     #[error("Failed to initialize legacy interrupts")]
529254b74cSRob Bradford     InitializeLegacyInterrupts(#[source] VfioPciError),
53*a3692144SPhilipp Schuster     #[error("Failed to create VfioCommon")]
54d6bf1f5eSSebastien Boeuf     CreateVfioCommon(#[source] VfioPciError),
559254b74cSRob Bradford }
569254b74cSRob Bradford 
579254b74cSRob Bradford #[derive(Copy, Clone)]
589254b74cSRob Bradford enum PciVfioUserSubclass {
599254b74cSRob Bradford     VfioUserSubclass = 0xff,
609254b74cSRob Bradford }
619254b74cSRob Bradford 
629254b74cSRob Bradford impl PciSubclass for PciVfioUserSubclass {
get_register_value(&self) -> u8639254b74cSRob Bradford     fn get_register_value(&self) -> u8 {
649254b74cSRob Bradford         *self as u8
659254b74cSRob Bradford     }
669254b74cSRob Bradford }
679254b74cSRob Bradford 
689254b74cSRob Bradford impl VfioUserPciDevice {
6981ba70a4SSebastien Boeuf     #[allow(clippy::too_many_arguments)]
new( id: String, vm: &Arc<dyn hypervisor::Vm>, client: Arc<Mutex<Client>>, msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>, legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>, bdf: PciBdf, memory_slot_allocator: MemorySlotAllocator, snapshot: Option<Snapshot>, ) -> Result<Self, VfioUserPciDeviceError>709254b74cSRob Bradford     pub fn new(
715264d545SSebastien Boeuf         id: String,
729254b74cSRob Bradford         vm: &Arc<dyn hypervisor::Vm>,
73e9d67dc4SRob Bradford         client: Arc<Mutex<Client>>,
74eb6daa2fSSebastien Boeuf         msi_interrupt_manager: Arc<dyn InterruptManager<GroupConfig = MsiIrqGroupConfig>>,
759254b74cSRob Bradford         legacy_interrupt_group: Option<Arc<dyn InterruptSourceGroup>>,
761db77185SMichael Zhao         bdf: PciBdf,
7781f8a27eSRob Bradford         memory_slot_allocator: MemorySlotAllocator,
78cc3706afSSebastien Boeuf         snapshot: Option<Snapshot>,
799254b74cSRob Bradford     ) -> Result<Self, VfioUserPciDeviceError> {
80e9d67dc4SRob Bradford         let resettable = client.lock().unwrap().resettable();
81e9d67dc4SRob Bradford         if resettable {
82e9d67dc4SRob Bradford             client
83e9d67dc4SRob Bradford                 .lock()
84e9d67dc4SRob Bradford                 .unwrap()
85e9d67dc4SRob Bradford                 .reset()
86e9d67dc4SRob Bradford                 .map_err(VfioUserPciDeviceError::Client)?;
879254b74cSRob Bradford         }
889254b74cSRob Bradford 
899254b74cSRob Bradford         let vfio_wrapper = VfioUserClientWrapper {
909254b74cSRob Bradford             client: client.clone(),
919254b74cSRob Bradford         };
929254b74cSRob Bradford 
93d6bf1f5eSSebastien Boeuf         let common = VfioCommon::new(
94eb6daa2fSSebastien Boeuf             msi_interrupt_manager,
95e6aa792cSSebastien Boeuf             legacy_interrupt_group,
96d6bf1f5eSSebastien Boeuf             Arc::new(vfio_wrapper) as Arc<dyn Vfio>,
97d6bf1f5eSSebastien Boeuf             &PciVfioUserSubclass::VfioUserSubclass,
98d6bf1f5eSSebastien Boeuf             bdf,
99cc3706afSSebastien Boeuf             vm_migration::snapshot_from_id(snapshot.as_ref(), VFIO_COMMON_ID),
100b750c332SThomas Barrett             None,
101d6bf1f5eSSebastien Boeuf         )
102d6bf1f5eSSebastien Boeuf         .map_err(VfioUserPciDeviceError::CreateVfioCommon)?;
1039254b74cSRob Bradford 
1049254b74cSRob Bradford         Ok(Self {
1055264d545SSebastien Boeuf             id,
1069254b74cSRob Bradford             vm: vm.clone(),
1079254b74cSRob Bradford             client,
1089254b74cSRob Bradford             common,
10981f8a27eSRob Bradford             memory_slot_allocator,
1109254b74cSRob Bradford         })
1119254b74cSRob Bradford     }
1120d7328daSBo Chen 
map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError>11381ba70a4SSebastien Boeuf     pub fn map_mmio_regions(&mut self) -> Result<(), VfioUserPciDeviceError> {
1140d7328daSBo Chen         for mmio_region in &mut self.common.mmio_regions {
1150d7328daSBo Chen             let region_flags = self
1160d7328daSBo Chen                 .client
1170d7328daSBo Chen                 .lock()
1180d7328daSBo Chen                 .unwrap()
1190d7328daSBo Chen                 .region(mmio_region.index)
1200d7328daSBo Chen                 .unwrap()
1210d7328daSBo Chen                 .flags;
1220d7328daSBo Chen             let file_offset = self
1230d7328daSBo Chen                 .client
1240d7328daSBo Chen                 .lock()
1250d7328daSBo Chen                 .unwrap()
1260d7328daSBo Chen                 .region(mmio_region.index)
1270d7328daSBo Chen                 .unwrap()
1280d7328daSBo Chen                 .file_offset
1290d7328daSBo Chen                 .clone();
1300d7328daSBo Chen 
13125a38b25SBo Chen             let sparse_areas = self
13225a38b25SBo Chen                 .client
13325a38b25SBo Chen                 .lock()
13425a38b25SBo Chen                 .unwrap()
13525a38b25SBo Chen                 .region(mmio_region.index)
13625a38b25SBo Chen                 .unwrap()
13725a38b25SBo Chen                 .sparse_areas
13825a38b25SBo Chen                 .clone();
13925a38b25SBo Chen 
1400d7328daSBo Chen             if region_flags & VFIO_REGION_INFO_FLAG_MMAP != 0 {
1410d7328daSBo Chen                 let mut prot = 0;
1420d7328daSBo Chen                 if region_flags & VFIO_REGION_INFO_FLAG_READ != 0 {
1430d7328daSBo Chen                     prot |= libc::PROT_READ;
1440d7328daSBo Chen                 }
1450d7328daSBo Chen                 if region_flags & VFIO_REGION_INFO_FLAG_WRITE != 0 {
1460d7328daSBo Chen                     prot |= libc::PROT_WRITE;
1470d7328daSBo Chen                 }
1480d7328daSBo Chen 
1495bd7a1f0SBo Chen                 let mmaps = if sparse_areas.is_empty() {
1505bd7a1f0SBo Chen                     vec![vfio_region_sparse_mmap_area {
1515bd7a1f0SBo Chen                         offset: 0,
1525bd7a1f0SBo Chen                         size: mmio_region.length,
1535bd7a1f0SBo Chen                     }]
1545bd7a1f0SBo Chen                 } else {
1555bd7a1f0SBo Chen                     sparse_areas
1565bd7a1f0SBo Chen                 };
1575bd7a1f0SBo Chen 
1585bd7a1f0SBo Chen                 for s in mmaps.iter() {
159c5bd8cabSWei Liu                     // SAFETY: FFI call with correct arguments
1600d7328daSBo Chen                     let host_addr = unsafe {
1610d7328daSBo Chen                         libc::mmap(
1620d7328daSBo Chen                             null_mut(),
1635bd7a1f0SBo Chen                             s.size as usize,
1640d7328daSBo Chen                             prot,
1650d7328daSBo Chen                             libc::MAP_SHARED,
1660d7328daSBo Chen                             file_offset.as_ref().unwrap().file().as_raw_fd(),
1675bd7a1f0SBo Chen                             file_offset.as_ref().unwrap().start() as libc::off_t
1685bd7a1f0SBo Chen                                 + s.offset as libc::off_t,
1690d7328daSBo Chen                         )
1700d7328daSBo Chen                     };
1710d7328daSBo Chen 
172a64ba04eSJinank Jain                     if std::ptr::eq(host_addr, libc::MAP_FAILED) {
1730d7328daSBo Chen                         error!(
1740d7328daSBo Chen                             "Could not mmap regions, error:{}",
1750d7328daSBo Chen                             std::io::Error::last_os_error()
1760d7328daSBo Chen                         );
1770d7328daSBo Chen                         continue;
1780d7328daSBo Chen                     }
1790d7328daSBo Chen 
1805bd7a1f0SBo Chen                     let user_memory_region = UserMemoryRegion {
18181f8a27eSRob Bradford                         slot: self.memory_slot_allocator.next_memory_slot(),
18225a38b25SBo Chen                         start: mmio_region.start.0 + s.offset,
18325a38b25SBo Chen                         size: s.size,
1845bd7a1f0SBo Chen                         host_addr: host_addr as u64,
18525a38b25SBo Chen                     };
186bf39146cSBo Chen 
18706f57abdSBo Chen                     mmio_region.user_memory_regions.push(user_memory_region);
18806f57abdSBo Chen 
18981ba70a4SSebastien Boeuf                     let mem_region = self.vm.make_user_memory_region(
190bf39146cSBo Chen                         user_memory_region.slot,
191bf39146cSBo Chen                         user_memory_region.start,
192bf39146cSBo Chen                         user_memory_region.size,
193bf39146cSBo Chen                         user_memory_region.host_addr,
1940d7328daSBo Chen                         false,
1950d7328daSBo Chen                         false,
1960d7328daSBo Chen                     );
1970d7328daSBo Chen 
19881ba70a4SSebastien Boeuf                     self.vm
19981ba70a4SSebastien Boeuf                         .create_user_memory_region(mem_region)
2000d7328daSBo Chen                         .map_err(VfioUserPciDeviceError::MapRegionGuest)?;
201bf39146cSBo Chen                 }
2020d7328daSBo Chen             }
2030d7328daSBo Chen         }
2040d7328daSBo Chen 
2050d7328daSBo Chen         Ok(())
2060d7328daSBo Chen     }
2070d7328daSBo Chen 
unmap_mmio_regions(&mut self)2080d7328daSBo Chen     pub fn unmap_mmio_regions(&mut self) {
2090d7328daSBo Chen         for mmio_region in self.common.mmio_regions.iter() {
210bf39146cSBo Chen             for user_memory_region in mmio_region.user_memory_regions.iter() {
2110d7328daSBo Chen                 // Remove region
2120d7328daSBo Chen                 let r = self.vm.make_user_memory_region(
213bf39146cSBo Chen                     user_memory_region.slot,
214bf39146cSBo Chen                     user_memory_region.start,
215bf39146cSBo Chen                     user_memory_region.size,
216bf39146cSBo Chen                     user_memory_region.host_addr,
2170d7328daSBo Chen                     false,
2180d7328daSBo Chen                     false,
2190d7328daSBo Chen                 );
2200d7328daSBo Chen 
2210d7328daSBo Chen                 if let Err(e) = self.vm.remove_user_memory_region(r) {
2220d7328daSBo Chen                     error!("Could not remove the userspace memory region: {}", e);
2230d7328daSBo Chen                 }
2240d7328daSBo Chen 
2250d6cef45SRob Bradford                 self.memory_slot_allocator
2260d6cef45SRob Bradford                     .free_memory_slot(user_memory_region.slot);
2270d6cef45SRob Bradford 
2285bd7a1f0SBo Chen                 // Remove mmaps
229c5bd8cabSWei Liu                 // SAFETY: FFI call with correct arguments
2305bd7a1f0SBo Chen                 let ret = unsafe {
2315bd7a1f0SBo Chen                     libc::munmap(
2325bd7a1f0SBo Chen                         user_memory_region.host_addr as *mut libc::c_void,
2335bd7a1f0SBo Chen                         user_memory_region.size as usize,
2345bd7a1f0SBo Chen                     )
2355bd7a1f0SBo Chen                 };
2360d7328daSBo Chen                 if ret != 0 {
2370d7328daSBo Chen                     error!(
2380d7328daSBo Chen                         "Could not unmap region {}, error:{}",
2390d7328daSBo Chen                         mmio_region.index,
2400d7328daSBo Chen                         std::io::Error::last_os_error()
2410d7328daSBo Chen                     );
2420d7328daSBo Chen                 }
2430d7328daSBo Chen             }
2440d7328daSBo Chen         }
2450d7328daSBo Chen     }
2460d7328daSBo Chen 
dma_map( &mut self, region: &GuestRegionMmap<AtomicBitmap>, ) -> Result<(), VfioUserPciDeviceError>2470d7328daSBo Chen     pub fn dma_map(
2480d7328daSBo Chen         &mut self,
2490d7328daSBo Chen         region: &GuestRegionMmap<AtomicBitmap>,
2500d7328daSBo Chen     ) -> Result<(), VfioUserPciDeviceError> {
2510d7328daSBo Chen         let (fd, offset) = match region.file_offset() {
2520d7328daSBo Chen             Some(_file_offset) => (_file_offset.file().as_raw_fd(), _file_offset.start()),
2530d7328daSBo Chen             None => return Ok(()),
2540d7328daSBo Chen         };
2550d7328daSBo Chen 
2560d7328daSBo Chen         self.client
2570d7328daSBo Chen             .lock()
2580d7328daSBo Chen             .unwrap()
259a9ec0f33SBo Chen             .dma_map(offset, region.start_addr().raw_value(), region.len(), fd)
2600d7328daSBo Chen             .map_err(VfioUserPciDeviceError::DmaMap)
2610d7328daSBo Chen     }
2620d7328daSBo Chen 
dma_unmap( &mut self, region: &GuestRegionMmap<AtomicBitmap>, ) -> Result<(), VfioUserPciDeviceError>2630d7328daSBo Chen     pub fn dma_unmap(
2640d7328daSBo Chen         &mut self,
2650d7328daSBo Chen         region: &GuestRegionMmap<AtomicBitmap>,
2660d7328daSBo Chen     ) -> Result<(), VfioUserPciDeviceError> {
2670d7328daSBo Chen         self.client
2680d7328daSBo Chen             .lock()
2690d7328daSBo Chen             .unwrap()
270a9ec0f33SBo Chen             .dma_unmap(region.start_addr().raw_value(), region.len())
2710d7328daSBo Chen             .map_err(VfioUserPciDeviceError::DmaUnmap)
2720d7328daSBo Chen     }
2739254b74cSRob Bradford }
2749254b74cSRob Bradford 
2759254b74cSRob Bradford impl BusDevice for VfioUserPciDevice {
read(&mut self, base: u64, offset: u64, data: &mut [u8])2769254b74cSRob Bradford     fn read(&mut self, base: u64, offset: u64, data: &mut [u8]) {
2779254b74cSRob Bradford         self.read_bar(base, offset, data)
2789254b74cSRob Bradford     }
2799254b74cSRob Bradford 
write(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>2809254b74cSRob Bradford     fn write(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
2819254b74cSRob Bradford         self.write_bar(base, offset, data)
2829254b74cSRob Bradford     }
2839254b74cSRob Bradford }
2849254b74cSRob Bradford 
2859254b74cSRob Bradford #[repr(u32)]
2869254b74cSRob Bradford #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
2879254b74cSRob Bradford #[allow(dead_code)]
2889254b74cSRob Bradford enum Regions {
2899254b74cSRob Bradford     Bar0,
2909254b74cSRob Bradford     Bar1,
2919254b74cSRob Bradford     Bar2,
2929254b74cSRob Bradford     Bar3,
2939254b74cSRob Bradford     Bar4,
2949254b74cSRob Bradford     Bar5,
2959254b74cSRob Bradford     Rom,
2969254b74cSRob Bradford     Config,
2979254b74cSRob Bradford     Vga,
2989254b74cSRob Bradford     Migration,
2999254b74cSRob Bradford }
3009254b74cSRob Bradford 
3019254b74cSRob Bradford struct VfioUserClientWrapper {
3029254b74cSRob Bradford     client: Arc<Mutex<Client>>,
3039254b74cSRob Bradford }
3049254b74cSRob Bradford 
3059254b74cSRob Bradford impl Vfio for VfioUserClientWrapper {
region_read(&self, index: u32, offset: u64, data: &mut [u8])3069254b74cSRob Bradford     fn region_read(&self, index: u32, offset: u64, data: &mut [u8]) {
3079254b74cSRob Bradford         self.client
3089254b74cSRob Bradford             .lock()
3099254b74cSRob Bradford             .unwrap()
3109254b74cSRob Bradford             .region_read(index, offset, data)
3119254b74cSRob Bradford             .ok();
3129254b74cSRob Bradford     }
3139254b74cSRob Bradford 
region_write(&self, index: u32, offset: u64, data: &[u8])3149254b74cSRob Bradford     fn region_write(&self, index: u32, offset: u64, data: &[u8]) {
3159254b74cSRob Bradford         self.client
3169254b74cSRob Bradford             .lock()
3179254b74cSRob Bradford             .unwrap()
3189254b74cSRob Bradford             .region_write(index, offset, data)
3199254b74cSRob Bradford             .ok();
3209254b74cSRob Bradford     }
3219254b74cSRob Bradford 
get_irq_info(&self, irq_index: u32) -> Option<VfioIrq>3229254b74cSRob Bradford     fn get_irq_info(&self, irq_index: u32) -> Option<VfioIrq> {
3239254b74cSRob Bradford         self.client
3249254b74cSRob Bradford             .lock()
3259254b74cSRob Bradford             .unwrap()
3269254b74cSRob Bradford             .get_irq_info(irq_index)
3279254b74cSRob Bradford             .ok()
3289254b74cSRob Bradford             .map(|i| VfioIrq {
3299254b74cSRob Bradford                 index: i.index,
3309254b74cSRob Bradford                 flags: i.flags,
3319254b74cSRob Bradford                 count: i.count,
3329254b74cSRob Bradford             })
3339254b74cSRob Bradford     }
3349254b74cSRob Bradford 
enable_irq(&self, irq_index: u32, event_fds: Vec<&EventFd>) -> Result<(), VfioError>3359254b74cSRob Bradford     fn enable_irq(&self, irq_index: u32, event_fds: Vec<&EventFd>) -> Result<(), VfioError> {
3369254b74cSRob Bradford         info!(
3379254b74cSRob Bradford             "Enabling IRQ {:x} number of fds = {:?}",
3389254b74cSRob Bradford             irq_index,
3399254b74cSRob Bradford             event_fds.len()
3409254b74cSRob Bradford         );
3419254b74cSRob Bradford         let fds: Vec<i32> = event_fds.iter().map(|e| e.as_raw_fd()).collect();
3429254b74cSRob Bradford 
3437444c3a0SRob Bradford         // Batch into blocks of 16 fds as sendmsg() has a size limit
3447444c3a0SRob Bradford         let mut sent_fds = 0;
3457444c3a0SRob Bradford         let num_fds = event_fds.len() as u32;
3467444c3a0SRob Bradford         while sent_fds < num_fds {
3477444c3a0SRob Bradford             let remaining_fds = num_fds - sent_fds;
3487444c3a0SRob Bradford             let count = if remaining_fds > 16 {
3497444c3a0SRob Bradford                 16
3507444c3a0SRob Bradford             } else {
3517444c3a0SRob Bradford                 remaining_fds
3527444c3a0SRob Bradford             };
3537444c3a0SRob Bradford 
3549254b74cSRob Bradford             self.client
3559254b74cSRob Bradford                 .lock()
3569254b74cSRob Bradford                 .unwrap()
3579254b74cSRob Bradford                 .set_irqs(
3589254b74cSRob Bradford                     irq_index,
3599254b74cSRob Bradford                     VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER,
3607444c3a0SRob Bradford                     sent_fds,
3617444c3a0SRob Bradford                     count,
3627444c3a0SRob Bradford                     &fds[sent_fds as usize..(sent_fds + count) as usize],
3639254b74cSRob Bradford                 )
3647444c3a0SRob Bradford                 .map_err(VfioError::VfioUser)?;
3657444c3a0SRob Bradford 
3667444c3a0SRob Bradford             sent_fds += count;
3677444c3a0SRob Bradford         }
3687444c3a0SRob Bradford 
3697444c3a0SRob Bradford         Ok(())
3709254b74cSRob Bradford     }
3719254b74cSRob Bradford 
disable_irq(&self, irq_index: u32) -> Result<(), VfioError>3729254b74cSRob Bradford     fn disable_irq(&self, irq_index: u32) -> Result<(), VfioError> {
3739254b74cSRob Bradford         info!("Disabling IRQ {:x}", irq_index);
3749254b74cSRob Bradford         self.client
3759254b74cSRob Bradford             .lock()
3769254b74cSRob Bradford             .unwrap()
3779254b74cSRob Bradford             .set_irqs(
3789254b74cSRob Bradford                 irq_index,
3799254b74cSRob Bradford                 VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER,
3809254b74cSRob Bradford                 0,
3819254b74cSRob Bradford                 0,
3829254b74cSRob Bradford                 &[],
3839254b74cSRob Bradford             )
3849254b74cSRob Bradford             .map_err(VfioError::VfioUser)
3859254b74cSRob Bradford     }
3869254b74cSRob Bradford 
unmask_irq(&self, irq_index: u32) -> Result<(), VfioError>3879254b74cSRob Bradford     fn unmask_irq(&self, irq_index: u32) -> Result<(), VfioError> {
3889254b74cSRob Bradford         info!("Unmasking IRQ {:x}", irq_index);
3899254b74cSRob Bradford         self.client
3909254b74cSRob Bradford             .lock()
3919254b74cSRob Bradford             .unwrap()
3929254b74cSRob Bradford             .set_irqs(
3939254b74cSRob Bradford                 irq_index,
3949254b74cSRob Bradford                 VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
3959254b74cSRob Bradford                 0,
3969254b74cSRob Bradford                 1,
3979254b74cSRob Bradford                 &[],
3989254b74cSRob Bradford             )
3999254b74cSRob Bradford             .map_err(VfioError::VfioUser)
4009254b74cSRob Bradford     }
4019254b74cSRob Bradford }
4029254b74cSRob Bradford 
4039254b74cSRob Bradford impl PciDevice for VfioUserPciDevice {
allocate_bars( &mut self, allocator: &Arc<Mutex<SystemAllocator>>, mmio32_allocator: &mut AddressAllocator, mmio64_allocator: &mut AddressAllocator, resources: Option<Vec<Resource>>, ) -> Result<Vec<PciBarConfiguration>, PciDeviceError>4049254b74cSRob Bradford     fn allocate_bars(
4059254b74cSRob Bradford         &mut self,
4069ef1187fSRob Bradford         allocator: &Arc<Mutex<SystemAllocator>>,
40745b01d59SThomas Barrett         mmio32_allocator: &mut AddressAllocator,
40845b01d59SThomas Barrett         mmio64_allocator: &mut AddressAllocator,
4096e084572SSebastien Boeuf         resources: Option<Vec<Resource>>,
41089218b6dSSebastien Boeuf     ) -> Result<Vec<PciBarConfiguration>, PciDeviceError> {
411cd9d1cf8SRob Bradford         self.common
41245b01d59SThomas Barrett             .allocate_bars(allocator, mmio32_allocator, mmio64_allocator, resources)
4139254b74cSRob Bradford     }
4149254b74cSRob Bradford 
free_bars( &mut self, allocator: &mut SystemAllocator, mmio32_allocator: &mut AddressAllocator, mmio64_allocator: &mut AddressAllocator, ) -> Result<(), PciDeviceError>415cd9d1cf8SRob Bradford     fn free_bars(
416cd9d1cf8SRob Bradford         &mut self,
417cd9d1cf8SRob Bradford         allocator: &mut SystemAllocator,
41845b01d59SThomas Barrett         mmio32_allocator: &mut AddressAllocator,
41945b01d59SThomas Barrett         mmio64_allocator: &mut AddressAllocator,
420cd9d1cf8SRob Bradford     ) -> Result<(), PciDeviceError> {
42145b01d59SThomas Barrett         self.common
42245b01d59SThomas Barrett             .free_bars(allocator, mmio32_allocator, mmio64_allocator)
423e3487c01SRob Bradford     }
424e3487c01SRob Bradford 
as_any_mut(&mut self) -> &mut dyn Any425d99f2942SWei Liu     fn as_any_mut(&mut self) -> &mut dyn Any {
4269254b74cSRob Bradford         self
4279254b74cSRob Bradford     }
4289254b74cSRob Bradford 
write_config_register( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>)4299254b74cSRob Bradford     fn write_config_register(
4309254b74cSRob Bradford         &mut self,
4319254b74cSRob Bradford         reg_idx: usize,
4329254b74cSRob Bradford         offset: u64,
4339254b74cSRob Bradford         data: &[u8],
434aaf86ef2SBo Chen     ) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
4354a99d3dbSSebastien Boeuf         self.common.write_config_register(reg_idx, offset, data)
4369254b74cSRob Bradford     }
4379254b74cSRob Bradford 
read_config_register(&mut self, reg_idx: usize) -> u324389254b74cSRob Bradford     fn read_config_register(&mut self, reg_idx: usize) -> u32 {
4394a99d3dbSSebastien Boeuf         self.common.read_config_register(reg_idx)
4409254b74cSRob Bradford     }
4419254b74cSRob Bradford 
read_bar(&mut self, base: u64, offset: u64, data: &mut [u8])4429254b74cSRob Bradford     fn read_bar(&mut self, base: u64, offset: u64, data: &mut [u8]) {
4434a99d3dbSSebastien Boeuf         self.common.read_bar(base, offset, data)
4449254b74cSRob Bradford     }
4459254b74cSRob Bradford 
write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>>4469254b74cSRob Bradford     fn write_bar(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<Barrier>> {
4474a99d3dbSSebastien Boeuf         self.common.write_bar(base, offset, data)
4489254b74cSRob Bradford     }
4490b5c680dSRob Bradford 
move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error>4500b5c680dSRob Bradford     fn move_bar(&mut self, old_base: u64, new_base: u64) -> Result<(), std::io::Error> {
4510b5c680dSRob Bradford         info!("Moving BAR 0x{:x} -> 0x{:x}", old_base, new_base);
4520b5c680dSRob Bradford         for mmio_region in self.common.mmio_regions.iter_mut() {
4530b5c680dSRob Bradford             if mmio_region.start.raw_value() == old_base {
4540b5c680dSRob Bradford                 mmio_region.start = GuestAddress(new_base);
4550b5c680dSRob Bradford 
456bf39146cSBo Chen                 for user_memory_region in mmio_region.user_memory_regions.iter_mut() {
457bf39146cSBo Chen                     // Remove old region
4580b5c680dSRob Bradford                     let old_region = self.vm.make_user_memory_region(
459bf39146cSBo Chen                         user_memory_region.slot,
460bf39146cSBo Chen                         user_memory_region.start,
461bf39146cSBo Chen                         user_memory_region.size,
462bf39146cSBo Chen                         user_memory_region.host_addr,
4630b5c680dSRob Bradford                         false,
4640b5c680dSRob Bradford                         false,
4650b5c680dSRob Bradford                     );
4660b5c680dSRob Bradford 
4670b5c680dSRob Bradford                     self.vm
4680b5c680dSRob Bradford                         .remove_user_memory_region(old_region)
469ea4693a0SJinank Jain                         .map_err(std::io::Error::other)?;
4700b5c680dSRob Bradford 
471bf39146cSBo Chen                     // Update the user memory region with the correct start address.
472bf39146cSBo Chen                     if new_base > old_base {
473bf39146cSBo Chen                         user_memory_region.start += new_base - old_base;
474bf39146cSBo Chen                     } else {
475bf39146cSBo Chen                         user_memory_region.start -= old_base - new_base;
476bf39146cSBo Chen                     }
477bf39146cSBo Chen 
478bf39146cSBo Chen                     // Insert new region
4790b5c680dSRob Bradford                     let new_region = self.vm.make_user_memory_region(
480bf39146cSBo Chen                         user_memory_region.slot,
481bf39146cSBo Chen                         user_memory_region.start,
482bf39146cSBo Chen                         user_memory_region.size,
483bf39146cSBo Chen                         user_memory_region.host_addr,
4840b5c680dSRob Bradford                         false,
4850b5c680dSRob Bradford                         false,
4860b5c680dSRob Bradford                     );
4870b5c680dSRob Bradford 
4880b5c680dSRob Bradford                     self.vm
4890b5c680dSRob Bradford                         .create_user_memory_region(new_region)
490ea4693a0SJinank Jain                         .map_err(std::io::Error::other)?;
4910b5c680dSRob Bradford                 }
4920b5c680dSRob Bradford                 info!("Moved bar 0x{:x} -> 0x{:x}", old_base, new_base);
4930b5c680dSRob Bradford             }
4940b5c680dSRob Bradford         }
4950b5c680dSRob Bradford 
4960b5c680dSRob Bradford         Ok(())
4970b5c680dSRob Bradford     }
4985264d545SSebastien Boeuf 
id(&self) -> Option<String>4995264d545SSebastien Boeuf     fn id(&self) -> Option<String> {
5005264d545SSebastien Boeuf         Some(self.id.clone())
5015264d545SSebastien Boeuf     }
5029254b74cSRob Bradford }
5039254b74cSRob Bradford 
5049254b74cSRob Bradford impl Drop for VfioUserPciDevice {
drop(&mut self)5059254b74cSRob Bradford     fn drop(&mut self) {
5069254b74cSRob Bradford         self.unmap_mmio_regions();
5079254b74cSRob Bradford 
5089254b74cSRob Bradford         if let Some(msix) = &self.common.interrupt.msix {
5099254b74cSRob Bradford             if msix.bar.enabled() {
5104a99d3dbSSebastien Boeuf                 self.common.disable_msix();
5119254b74cSRob Bradford             }
5129254b74cSRob Bradford         }
5139254b74cSRob Bradford 
5149254b74cSRob Bradford         if let Some(msi) = &self.common.interrupt.msi {
5159254b74cSRob Bradford             if msi.cfg.enabled() {
5164a99d3dbSSebastien Boeuf                 self.common.disable_msi()
5179254b74cSRob Bradford             }
5189254b74cSRob Bradford         }
5199254b74cSRob Bradford 
5209254b74cSRob Bradford         if self.common.interrupt.intx_in_use() {
5214a99d3dbSSebastien Boeuf             self.common.disable_intx();
5229254b74cSRob Bradford         }
523028961acSSebastien Boeuf 
524028961acSSebastien Boeuf         if let Err(e) = self.client.lock().unwrap().shutdown() {
525028961acSSebastien Boeuf             error!("Failed shutting down vfio-user client: {}", e);
526028961acSSebastien Boeuf         }
5279254b74cSRob Bradford     }
5289254b74cSRob Bradford }
52943365adeSRob Bradford 
530f48b05eeSSebastien Boeuf impl Pausable for VfioUserPciDevice {}
531f48b05eeSSebastien Boeuf 
532f48b05eeSSebastien Boeuf impl Snapshottable for VfioUserPciDevice {
id(&self) -> String533f48b05eeSSebastien Boeuf     fn id(&self) -> String {
534f48b05eeSSebastien Boeuf         self.id.clone()
535f48b05eeSSebastien Boeuf     }
536f48b05eeSSebastien Boeuf 
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>537f48b05eeSSebastien Boeuf     fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
538748018acSSebastien Boeuf         let mut vfio_pci_dev_snapshot = Snapshot::default();
539f48b05eeSSebastien Boeuf 
540f48b05eeSSebastien Boeuf         // Snapshot VfioCommon
541748018acSSebastien Boeuf         vfio_pci_dev_snapshot.add_snapshot(self.common.id(), self.common.snapshot()?);
542f48b05eeSSebastien Boeuf 
543f48b05eeSSebastien Boeuf         Ok(vfio_pci_dev_snapshot)
544f48b05eeSSebastien Boeuf     }
545f48b05eeSSebastien Boeuf }
546f48b05eeSSebastien Boeuf impl Transportable for VfioUserPciDevice {}
547f48b05eeSSebastien Boeuf impl Migratable for VfioUserPciDevice {}
548f48b05eeSSebastien Boeuf 
54943365adeSRob Bradford pub struct VfioUserDmaMapping<M: GuestAddressSpace> {
55043365adeSRob Bradford     client: Arc<Mutex<Client>>,
55143365adeSRob Bradford     memory: Arc<M>,
55243365adeSRob Bradford }
55343365adeSRob Bradford 
55443365adeSRob Bradford impl<M: GuestAddressSpace> VfioUserDmaMapping<M> {
new(client: Arc<Mutex<Client>>, memory: Arc<M>) -> Self55543365adeSRob Bradford     pub fn new(client: Arc<Mutex<Client>>, memory: Arc<M>) -> Self {
55643365adeSRob Bradford         Self { client, memory }
55743365adeSRob Bradford     }
55843365adeSRob Bradford }
55943365adeSRob Bradford 
56043365adeSRob Bradford impl<M: GuestAddressSpace + Sync + Send> ExternalDmaMapping for VfioUserDmaMapping<M> {
map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error>56143365adeSRob Bradford     fn map(&self, iova: u64, gpa: u64, size: u64) -> std::result::Result<(), std::io::Error> {
56243365adeSRob Bradford         let mem = self.memory.memory();
56343365adeSRob Bradford         let guest_addr = GuestAddress(gpa);
56443365adeSRob Bradford         let region = mem.find_region(guest_addr);
56543365adeSRob Bradford 
56643365adeSRob Bradford         if let Some(region) = region {
56743365adeSRob Bradford             let file_offset = region.file_offset().unwrap();
56843365adeSRob Bradford             let offset = (GuestAddress(gpa).checked_offset_from(region.start_addr())).unwrap()
56943365adeSRob Bradford                 + file_offset.start();
57043365adeSRob Bradford 
57143365adeSRob Bradford             self.client
57243365adeSRob Bradford                 .lock()
57343365adeSRob Bradford                 .unwrap()
57443365adeSRob Bradford                 .dma_map(offset, iova, size, file_offset.file().as_raw_fd())
575ea4693a0SJinank Jain                 .map_err(|e| std::io::Error::other(format!("Error mapping region: {e}")))
57643365adeSRob Bradford         } else {
577ea4693a0SJinank Jain             Err(std::io::Error::other(format!(
578ea4693a0SJinank Jain                 "Region not found for 0x{gpa:x}"
579ea4693a0SJinank Jain             )))
58043365adeSRob Bradford         }
58143365adeSRob Bradford     }
58243365adeSRob Bradford 
unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error>58343365adeSRob Bradford     fn unmap(&self, iova: u64, size: u64) -> std::result::Result<(), std::io::Error> {
58443365adeSRob Bradford         self.client
58543365adeSRob Bradford             .lock()
58643365adeSRob Bradford             .unwrap()
58743365adeSRob Bradford             .dma_unmap(iova, size)
588ea4693a0SJinank Jain             .map_err(|e| std::io::Error::other(format!("Error unmapping region: {e}")))
58943365adeSRob Bradford     }
59043365adeSRob Bradford }
591