From e18052120a27d6bb133308f9c0a7ce9c2f797996 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Wed, 24 Jul 2019 21:45:10 -0700 Subject: [PATCH] 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 --- vfio/src/vfio_pci.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 3fa671ab9..86e9a4c35 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -767,6 +767,7 @@ impl PciDevice for VfioPciDevice { let first_bit = lsb_size.trailing_zeros(); region_size = 2u64.pow(first_bit); // We need to allocate a guest PIO address range for that BAR. + // The address needs to be 4 bytes aligned. bar_addr = allocator .allocate_io_addresses(None, region_size, Some(0x4)) .ok_or_else(|| PciDeviceError::IoAllocationFailed(region_size))?; @@ -798,13 +799,24 @@ impl PciDevice for VfioPciDevice { region_size = 2u64.pow(first_bit); // 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 { 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))?; } else { 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))?; } }