vfio: Fix Memory BAR alignment

The IO BAR alignment was already set to 4 bytes, this patch simply added
a comment for it.

The Memory BAR alignment was also set to the right value, but it was not
explained why 0x1000 was needed, and also why 0x10 could sometimes be
used as correct alignment.
A Memory BAR must be aligned at least on 16 bytes since the first 4 bits
are dedicated to some specific information about the BAR itself. But in
case a BAR is identified as mappable from VFIO, this means our VMM might
memory map it into the VMM address space, and set KVM accordingly using
the ioctl KVM_SET_USER_MEMORY_REGION. In case of KVM, we have to take
into account that it expects addresses to be page aligned, which means
4K in this case.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2019-07-24 21:45:10 -07:00 committed by Rob Bradford
parent d92d797896
commit e18052120a

View File

@ -767,6 +767,7 @@ impl PciDevice for VfioPciDevice {
let first_bit = lsb_size.trailing_zeros(); let first_bit = lsb_size.trailing_zeros();
region_size = 2u64.pow(first_bit); region_size = 2u64.pow(first_bit);
// We need to allocate a guest PIO address range for that BAR. // We need to allocate a guest PIO address range for that BAR.
// The address needs to be 4 bytes aligned.
bar_addr = allocator bar_addr = allocator
.allocate_io_addresses(None, region_size, Some(0x4)) .allocate_io_addresses(None, region_size, Some(0x4))
.ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?; .ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?;
@ -798,13 +799,24 @@ impl PciDevice for VfioPciDevice {
region_size = 2u64.pow(first_bit); region_size = 2u64.pow(first_bit);
// We need to allocate a guest MMIO address range for that BAR. // We need to allocate a guest MMIO address range for that BAR.
// In case the BAR is mappable directly, this means it might be
// set as KVM user memory region, which expects to deal with 4K
// pages. Therefore, the aligment has to be set accordingly.
let bar_alignment =
if self.device.get_region_flags(bar_id) & VFIO_REGION_INFO_FLAG_MMAP != 0 {
// 4K alignment
0x1000
} else {
// Default 16 bytes alignment
0x10
};
if is_64bit_bar { if is_64bit_bar {
bar_addr = allocator bar_addr = allocator
.allocate_mmio_addresses(None, region_size, Some(0x1000)) .allocate_mmio_addresses(None, region_size, Some(bar_alignment))
.ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?; .ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?;
} else { } else {
bar_addr = allocator bar_addr = allocator
.allocate_mmio_hole_addresses(None, region_size, Some(0x1000)) .allocate_mmio_hole_addresses(None, region_size, Some(bar_alignment))
.ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?; .ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?;
} }
} }