From e93467a96c0b68d0d16b5c65dc8e0e882a733caa Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Mon, 28 Oct 2019 09:53:13 -0700 Subject: [PATCH] vmm: Implement DeviceRelocation trait By implementing the DeviceRelocation trait for the AddressManager structure, we now have a way to let the PCI BAR reprogramming happen. Signed-off-by: Sebastien Boeuf --- vmm/src/device_manager.rs | 83 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index c04679dbb..5581532d6 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -21,8 +21,8 @@ use libc::{EFD_NONBLOCK, TIOCGWINSZ}; use net_util::Tap; #[cfg(feature = "pci_support")] use pci::{ - InterruptDelivery, InterruptParameters, PciBus, PciConfigIo, PciConfigMmio, PciDevice, - PciInterruptPin, PciRoot, + DeviceRelocation, InterruptDelivery, InterruptParameters, PciBarRegionType, PciBus, + PciConfigIo, PciConfigMmio, PciDevice, PciInterruptPin, PciRoot, }; use qcow::{self, ImageType, QcowFile}; @@ -274,6 +274,83 @@ struct AddressManager { allocator: Arc>, io_bus: Arc, mmio_bus: Arc, + #[cfg(feature = "pci_support")] + vm_fd: Arc, +} + +#[cfg(feature = "pci_support")] +impl DeviceRelocation for AddressManager { + fn move_bar( + &self, + old_base: u64, + new_base: u64, + len: u64, + pci_dev: &mut dyn PciDevice, + region_type: PciBarRegionType, + ) { + match region_type { + PciBarRegionType::IORegion => { + // Update system allocator + self.allocator + .lock() + .unwrap() + .free_io_addresses(GuestAddress(old_base), len as GuestUsize); + self.allocator + .lock() + .unwrap() + .allocate_io_addresses(Some(GuestAddress(new_base)), len as GuestUsize, None) + .unwrap(); + + // Update PIO bus + self.io_bus + .update_range(old_base, len, new_base, len) + .unwrap(); + } + PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => { + // Update system allocator + self.allocator + .lock() + .unwrap() + .free_mmio_addresses(GuestAddress(old_base), len as GuestUsize); + + if region_type == PciBarRegionType::Memory32BitRegion { + self.allocator + .lock() + .unwrap() + .allocate_mmio_hole_addresses( + Some(GuestAddress(new_base)), + len as GuestUsize, + None, + ) + .unwrap(); + } else { + self.allocator + .lock() + .unwrap() + .allocate_mmio_addresses( + Some(GuestAddress(new_base)), + len as GuestUsize, + None, + ) + .unwrap(); + } + + // Update MMIO bus + self.mmio_bus + .update_range(old_base, len, new_base, len) + .unwrap(); + } + } + + for (event, addr, _) in pci_dev.ioeventfds() { + let io_addr = IoEventAddress::Mmio(addr); + self.vm_fd + .register_ioevent(event.as_raw_fd(), &io_addr, NoDatamatch) + .unwrap(); + } + + pci_dev.move_bar(old_base, new_base); + } } pub struct DeviceManager { @@ -452,6 +529,8 @@ impl DeviceManager { allocator: Arc::new(Mutex::new(allocator)), io_bus: Arc::new(io_bus), mmio_bus: Arc::new(mmio_bus), + #[cfg(feature = "pci_support")] + vm_fd: vm_info.vm_fd.clone(), }); if cfg!(feature = "pci_support") {