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