vfio: pci: Add support for expansion ROM BAR

Relying on the newly added code in the pci crate, the vfio crate can now
properly expose an expansion ROM BAR if the device has one.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf
2019-07-30 07:42:07 -07:00
committed by Samuel Ortiz
parent d217089b54
commit d18c8d4c8c

View File

@@ -728,14 +728,18 @@ impl PciDevice for VfioPciDevice {
// We're not saving the BAR address to restore it, because we // We're not saving the BAR address to restore it, because we
// are going to allocate a guest address for each BAR and write // are going to allocate a guest address for each BAR and write
// that new address back. // that new address back.
while bar_id < VFIO_PCI_ROM_REGION_INDEX { while bar_id < VFIO_PCI_CONFIG_REGION_INDEX {
let mut lsb_size: u32 = 0xffff_ffff; let mut lsb_size: u32 = 0xffff_ffff;
let mut msb_size = 0; let mut msb_size = 0;
let mut region_size: u64; let mut region_size: u64;
let bar_addr: GuestAddress; let bar_addr: GuestAddress;
// Read the BAR size (Starts by all 1s to the BAR) // Read the BAR size (Starts by all 1s to the BAR)
let bar_offset = PCI_CONFIG_BAR_OFFSET + bar_id * 4; let bar_offset = if bar_id == VFIO_PCI_ROM_REGION_INDEX {
(PCI_ROM_EXP_BAR_INDEX * 4) as u32
} else {
PCI_CONFIG_BAR_OFFSET + bar_id * 4
};
self.vfio_pci_configuration self.vfio_pci_configuration
.write_config_dword(lsb_size, bar_offset); .write_config_dword(lsb_size, bar_offset);
@@ -750,15 +754,23 @@ impl PciDevice for VfioPciDevice {
} }
// Is this an IO BAR? // Is this an IO BAR?
let io_bar = match lsb_flag & PCI_CONFIG_IO_BAR { let io_bar = if bar_id != VFIO_PCI_ROM_REGION_INDEX {
PCI_CONFIG_IO_BAR => true, match lsb_flag & PCI_CONFIG_IO_BAR {
_ => false, PCI_CONFIG_IO_BAR => true,
_ => false,
}
} else {
false
}; };
// Is this a 64-bit BAR? // Is this a 64-bit BAR?
let is_64bit_bar = match lsb_flag & PCI_CONFIG_MEMORY_BAR_64BIT { let is_64bit_bar = if bar_id != VFIO_PCI_ROM_REGION_INDEX {
PCI_CONFIG_MEMORY_BAR_64BIT => true, match lsb_flag & PCI_CONFIG_MEMORY_BAR_64BIT {
_ => false, PCI_CONFIG_MEMORY_BAR_64BIT => true,
_ => false,
}
} else {
false
}; };
// By default, the region type is 32 bits memory BAR. // By default, the region type is 32 bits memory BAR.
@@ -810,14 +822,15 @@ impl PciDevice for VfioPciDevice {
// In case the BAR is mappable directly, this means it might be // In case the BAR is mappable directly, this means it might be
// set as KVM user memory region, which expects to deal with 4K // set as KVM user memory region, which expects to deal with 4K
// pages. Therefore, the aligment has to be set accordingly. // pages. Therefore, the aligment has to be set accordingly.
let bar_alignment = let bar_alignment = if (bar_id == VFIO_PCI_ROM_REGION_INDEX)
if self.device.get_region_flags(bar_id) & VFIO_REGION_INFO_FLAG_MMAP != 0 { || (self.device.get_region_flags(bar_id) & VFIO_REGION_INFO_FLAG_MMAP != 0)
// 4K alignment {
0x1000 // 4K alignment
} else { 0x1000
// Default 16 bytes alignment } else {
0x10 // 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(bar_alignment)) .allocate_mmio_addresses(None, region_size, Some(bar_alignment))
@@ -829,16 +842,28 @@ impl PciDevice for VfioPciDevice {
} }
} }
let reg_idx = if bar_id == VFIO_PCI_ROM_REGION_INDEX {
PCI_ROM_EXP_BAR_INDEX
} else {
bar_id as usize
};
// We can now build our BAR configuration block. // We can now build our BAR configuration block.
let config = PciBarConfiguration::default() let config = PciBarConfiguration::default()
.set_register_index(bar_id as usize) .set_register_index(reg_idx)
.set_address(bar_addr.raw_value()) .set_address(bar_addr.raw_value())
.set_size(region_size) .set_size(region_size)
.set_region_type(region_type); .set_region_type(region_type);
self.configuration if bar_id == VFIO_PCI_ROM_REGION_INDEX {
.add_pci_bar(&config) self.configuration
.map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?; .add_pci_rom_bar(&config, lsb_flag & 0x1)
.map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
} else {
self.configuration
.add_pci_bar(&config)
.map_err(|e| PciDeviceError::IoRegistrationFailed(bar_addr.raw_value(), e))?;
}
ranges.push((bar_addr, region_size, region_type)); ranges.push((bar_addr, region_size, region_type));
self.mmio_regions.push(MmioRegion { self.mmio_regions.push(MmioRegion {
@@ -864,7 +889,9 @@ impl PciDevice for VfioPciDevice {
// When the guest wants to write to a BAR, we trap it into // When the guest wants to write to a BAR, we trap it into
// our local configuration space. We're not reprogramming // our local configuration space. We're not reprogramming
// VFIO device. // VFIO device.
if reg_idx >= PCI_CONFIG_BAR0_INDEX && reg_idx < PCI_CONFIG_BAR0_INDEX + BAR_NUMS { if (reg_idx >= PCI_CONFIG_BAR0_INDEX && reg_idx < PCI_CONFIG_BAR0_INDEX + BAR_NUMS)
|| reg_idx == PCI_ROM_EXP_BAR_INDEX
{
// We keep our local cache updated with the BARs. // We keep our local cache updated with the BARs.
// We'll read it back from there when the guest is asking // We'll read it back from there when the guest is asking
// for BARs (see read_config_register()). // for BARs (see read_config_register()).
@@ -902,16 +929,12 @@ impl PciDevice for VfioPciDevice {
// from our local configuration space. We want the guest to // from our local configuration space. We want the guest to
// use that and not the VFIO device BARs as it does not map // use that and not the VFIO device BARs as it does not map
// with the guest address space. // with the guest address space.
if reg_idx >= PCI_CONFIG_BAR0_INDEX && reg_idx < PCI_CONFIG_BAR0_INDEX + BAR_NUMS { if (reg_idx >= PCI_CONFIG_BAR0_INDEX && reg_idx < PCI_CONFIG_BAR0_INDEX + BAR_NUMS)
|| reg_idx == PCI_ROM_EXP_BAR_INDEX
{
return self.configuration.read_reg(reg_idx); return self.configuration.read_reg(reg_idx);
} }
// Since the ROM expansion BAR is not yet handled by the code, it is
// more proper to expose it to the guest as being disabled.
if reg_idx == PCI_ROM_EXP_BAR_INDEX {
return 0;
}
// Since we don't support INTx (only MSI and MSI-X), we should not // Since we don't support INTx (only MSI and MSI-X), we should not
// expose an invalid Interrupt Pin to the guest. By using a specific // expose an invalid Interrupt Pin to the guest. By using a specific
// mask in case the register being read correspond to the interrupt // mask in case the register being read correspond to the interrupt