pci, virtio-devices, vmm: Allocate PCI 64-bit bars per segment

Since each segment must have a non-overlapping memory range associated
with it the device memory must be equally divided amongst all segments.
A new allocator is used for each segment to ensure that BARs are
allocated from the correct address ranges. This requires changes to
PciDevice::allocate/free_bars to take that allocator and when
reallocating BARs the correct allocator must be identified from the
ranges.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford
2021-10-15 11:38:06 +01:00
parent a6456b50f3
commit cd9d1cf8fc
6 changed files with 127 additions and 73 deletions

View File

@@ -7,7 +7,7 @@ use std::any::Any;
use std::fmt::{self, Display};
use std::sync::{Arc, Barrier};
use std::{self, io, result};
use vm_allocator::SystemAllocator;
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::BusDevice;
use vm_memory::{GuestAddress, GuestUsize};
@@ -52,12 +52,17 @@ pub trait PciDevice: BusDevice {
fn allocate_bars(
&mut self,
_allocator: &mut SystemAllocator,
_mmio_allocator: &mut AddressAllocator,
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>> {
Ok(Vec::new())
}
/// Frees the PCI BARs previously allocated with a call to allocate_bars().
fn free_bars(&mut self, _allocator: &mut SystemAllocator) -> Result<()> {
fn free_bars(
&mut self,
_allocator: &mut SystemAllocator,
_mmio_allocator: &mut AddressAllocator,
) -> Result<()> {
Ok(())
}

View File

@@ -19,7 +19,7 @@ use std::sync::{Arc, Barrier};
use thiserror::Error;
use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::{VfioContainer, VfioDevice, VfioIrq};
use vm_allocator::SystemAllocator;
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::interrupt::{
InterruptIndex, InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig,
};
@@ -361,6 +361,7 @@ impl VfioCommon {
pub(crate) fn allocate_bars(
&mut self,
allocator: &mut SystemAllocator,
mmio_allocator: &mut AddressAllocator,
vfio_wrapper: &dyn Vfio,
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
let mut ranges = Vec::new();
@@ -458,8 +459,8 @@ impl VfioCommon {
region_size = (!combined_size + 1) as u64;
// BAR allocation must be naturally aligned
bar_addr = allocator
.allocate_mmio_addresses(None, region_size, Some(region_size))
bar_addr = mmio_allocator
.allocate(None, region_size, Some(region_size))
.ok_or(PciDeviceError::IoAllocationFailed(region_size))?;
} else {
// Mask out flag bits (lowest 4 for memory bars)
@@ -526,6 +527,7 @@ impl VfioCommon {
pub(crate) fn free_bars(
&mut self,
allocator: &mut SystemAllocator,
mmio_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> {
for region in self.mmio_regions.iter() {
match region.type_ {
@@ -539,7 +541,7 @@ impl VfioCommon {
allocator.free_mmio_hole_addresses(region.start, region.length);
}
PciBarRegionType::Memory64BitRegion => {
allocator.free_mmio_addresses(region.start, region.length);
mmio_allocator.free(region.start, region.length);
}
}
}
@@ -1293,12 +1295,18 @@ impl PciDevice for VfioPciDevice {
fn allocate_bars(
&mut self,
allocator: &mut SystemAllocator,
mmio_allocator: &mut AddressAllocator,
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
self.common.allocate_bars(allocator, &self.vfio_wrapper)
self.common
.allocate_bars(allocator, mmio_allocator, &self.vfio_wrapper)
}
fn free_bars(&mut self, allocator: &mut SystemAllocator) -> Result<(), PciDeviceError> {
self.common.free_bars(allocator)
fn free_bars(
&mut self,
allocator: &mut SystemAllocator,
mmio_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> {
self.common.free_bars(allocator, mmio_allocator)
}
fn write_config_register(

View File

@@ -18,7 +18,7 @@ use thiserror::Error;
use vfio_bindings::bindings::vfio::*;
use vfio_ioctls::VfioIrq;
use vfio_user::{Client, Error as VfioUserError};
use vm_allocator::SystemAllocator;
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::dma_mapping::ExternalDmaMapping;
use vm_device::interrupt::{InterruptManager, InterruptSourceGroup, MsiIrqGroupConfig};
use vm_device::BusDevice;
@@ -234,12 +234,18 @@ impl PciDevice for VfioUserPciDevice {
fn allocate_bars(
&mut self,
allocator: &mut SystemAllocator,
mmio_allocator: &mut AddressAllocator,
) -> Result<Vec<(GuestAddress, GuestUsize, PciBarRegionType)>, PciDeviceError> {
self.common.allocate_bars(allocator, &self.vfio_wrapper)
self.common
.allocate_bars(allocator, mmio_allocator, &self.vfio_wrapper)
}
fn free_bars(&mut self, allocator: &mut SystemAllocator) -> Result<(), PciDeviceError> {
self.common.free_bars(allocator)
fn free_bars(
&mut self,
allocator: &mut SystemAllocator,
mmio_allocator: &mut AddressAllocator,
) -> Result<(), PciDeviceError> {
self.common.free_bars(allocator, mmio_allocator)
}
fn as_any(&mut self) -> &mut dyn Any {