mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-07-16 06:07:15 +00:00
pci: vfio: Move {read,write}_config_register() to VfioCommon
These functions are used for the implementation of PciDevice. Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
parent
a5f4d79547
commit
1997152ee1
161
pci/src/vfio.rs
161
pci/src/vfio.rs
@ -866,6 +866,87 @@ impl VfioCommon {
|
|||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn write_config_register(
|
||||||
|
&mut self,
|
||||||
|
reg_idx: usize,
|
||||||
|
offset: u64,
|
||||||
|
data: &[u8],
|
||||||
|
wrapper: &dyn Vfio,
|
||||||
|
) -> Option<Arc<Barrier>> {
|
||||||
|
// When the guest wants to write to a BAR, we trap it into
|
||||||
|
// our local configuration space. We're not reprogramming
|
||||||
|
// VFIO device.
|
||||||
|
if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(®_idx)
|
||||||
|
|| reg_idx == PCI_ROM_EXP_BAR_INDEX
|
||||||
|
{
|
||||||
|
// We keep our local cache updated with the BARs.
|
||||||
|
// We'll read it back from there when the guest is asking
|
||||||
|
// for BARs (see read_config_register()).
|
||||||
|
self.configuration
|
||||||
|
.write_config_register(reg_idx, offset, data);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let reg = (reg_idx * PCI_CONFIG_REGISTER_SIZE) as u64;
|
||||||
|
|
||||||
|
// If the MSI or MSI-X capabilities are accessed, we need to
|
||||||
|
// update our local cache accordingly.
|
||||||
|
// Depending on how the capabilities are modified, this could
|
||||||
|
// trigger a VFIO MSI or MSI-X toggle.
|
||||||
|
if let Some((cap_id, cap_base)) = self.interrupt.accessed(reg) {
|
||||||
|
let cap_offset: u64 = reg - cap_base + offset;
|
||||||
|
match cap_id {
|
||||||
|
PciCapabilityId::MessageSignalledInterrupts => {
|
||||||
|
if let Err(e) = self.update_msi_capabilities(cap_offset, data, wrapper) {
|
||||||
|
error!("Could not update MSI capabilities: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PciCapabilityId::MsiX => {
|
||||||
|
if let Err(e) = self.update_msix_capabilities(cap_offset, data, wrapper) {
|
||||||
|
error!("Could not update MSI-X capabilities: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure to write to the device's PCI config space after MSI/MSI-X
|
||||||
|
// interrupts have been enabled/disabled. In case of MSI, when the
|
||||||
|
// interrupts are enabled through VFIO (using VFIO_DEVICE_SET_IRQS),
|
||||||
|
// the MSI Enable bit in the MSI capability structure found in the PCI
|
||||||
|
// config space is disabled by default. That's why when the guest is
|
||||||
|
// enabling this bit, we first need to enable the MSI interrupts with
|
||||||
|
// VFIO through VFIO_DEVICE_SET_IRQS ioctl, and only after we can write
|
||||||
|
// to the device region to update the MSI Enable bit.
|
||||||
|
wrapper.write_config((reg + offset) as u32, data);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn read_config_register(&mut self, reg_idx: usize, wrapper: &dyn Vfio) -> u32 {
|
||||||
|
// When reading the BARs, we trap it and return what comes
|
||||||
|
// from our local configuration space. We want the guest to
|
||||||
|
// use that and not the VFIO device BARs as it does not map
|
||||||
|
// with the guest address space.
|
||||||
|
if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(®_idx)
|
||||||
|
|| reg_idx == PCI_ROM_EXP_BAR_INDEX
|
||||||
|
{
|
||||||
|
return self.configuration.read_reg(reg_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since we don't support passing multi-functions devices, we should
|
||||||
|
// mask the multi-function bit, bit 7 of the Header Type byte on the
|
||||||
|
// register 3.
|
||||||
|
let mask = if reg_idx == PCI_HEADER_TYPE_REG_INDEX {
|
||||||
|
0xff7f_ffff
|
||||||
|
} else {
|
||||||
|
0xffff_ffff
|
||||||
|
};
|
||||||
|
|
||||||
|
// The config register read comes from the VFIO device itself.
|
||||||
|
wrapper.read_config_dword((reg_idx * 4) as u32) & mask
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// VfioPciDevice represents a VFIO PCI device.
|
/// VfioPciDevice represents a VFIO PCI device.
|
||||||
@ -1150,85 +1231,13 @@ impl PciDevice for VfioPciDevice {
|
|||||||
offset: u64,
|
offset: u64,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
) -> Option<Arc<Barrier>> {
|
) -> Option<Arc<Barrier>> {
|
||||||
// When the guest wants to write to a BAR, we trap it into
|
self.common
|
||||||
// our local configuration space. We're not reprogramming
|
.write_config_register(reg_idx, offset, data, &self.vfio_wrapper)
|
||||||
// VFIO device.
|
|
||||||
if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(®_idx)
|
|
||||||
|| reg_idx == PCI_ROM_EXP_BAR_INDEX
|
|
||||||
{
|
|
||||||
// We keep our local cache updated with the BARs.
|
|
||||||
// We'll read it back from there when the guest is asking
|
|
||||||
// for BARs (see read_config_register()).
|
|
||||||
self.common
|
|
||||||
.configuration
|
|
||||||
.write_config_register(reg_idx, offset, data);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let reg = (reg_idx * PCI_CONFIG_REGISTER_SIZE) as u64;
|
|
||||||
|
|
||||||
// If the MSI or MSI-X capabilities are accessed, we need to
|
|
||||||
// update our local cache accordingly.
|
|
||||||
// Depending on how the capabilities are modified, this could
|
|
||||||
// trigger a VFIO MSI or MSI-X toggle.
|
|
||||||
if let Some((cap_id, cap_base)) = self.common.interrupt.accessed(reg) {
|
|
||||||
let cap_offset: u64 = reg - cap_base + offset;
|
|
||||||
match cap_id {
|
|
||||||
PciCapabilityId::MessageSignalledInterrupts => {
|
|
||||||
if let Err(e) =
|
|
||||||
self.common
|
|
||||||
.update_msi_capabilities(cap_offset, data, &self.vfio_wrapper)
|
|
||||||
{
|
|
||||||
error!("Could not update MSI capabilities: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PciCapabilityId::MsiX => {
|
|
||||||
if let Err(e) =
|
|
||||||
self.common
|
|
||||||
.update_msix_capabilities(cap_offset, data, &self.vfio_wrapper)
|
|
||||||
{
|
|
||||||
error!("Could not update MSI-X capabilities: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure to write to the device's PCI config space after MSI/MSI-X
|
|
||||||
// interrupts have been enabled/disabled. In case of MSI, when the
|
|
||||||
// interrupts are enabled through VFIO (using VFIO_DEVICE_SET_IRQS),
|
|
||||||
// the MSI Enable bit in the MSI capability structure found in the PCI
|
|
||||||
// config space is disabled by default. That's why when the guest is
|
|
||||||
// enabling this bit, we first need to enable the MSI interrupts with
|
|
||||||
// VFIO through VFIO_DEVICE_SET_IRQS ioctl, and only after we can write
|
|
||||||
// to the device region to update the MSI Enable bit.
|
|
||||||
self.vfio_wrapper.write_config((reg + offset) as u32, data);
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
|
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
|
||||||
// When reading the BARs, we trap it and return what comes
|
self.common
|
||||||
// from our local configuration space. We want the guest to
|
.read_config_register(reg_idx, &self.vfio_wrapper)
|
||||||
// use that and not the VFIO device BARs as it does not map
|
|
||||||
// with the guest address space.
|
|
||||||
if (PCI_CONFIG_BAR0_INDEX..PCI_CONFIG_BAR0_INDEX + BAR_NUMS).contains(®_idx)
|
|
||||||
|| reg_idx == PCI_ROM_EXP_BAR_INDEX
|
|
||||||
{
|
|
||||||
return self.common.configuration.read_reg(reg_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Since we don't support passing multi-functions devices, we should
|
|
||||||
// mask the multi-function bit, bit 7 of the Header Type byte on the
|
|
||||||
// register 3.
|
|
||||||
let mask = if reg_idx == PCI_HEADER_TYPE_REG_INDEX {
|
|
||||||
0xff7f_ffff
|
|
||||||
} else {
|
|
||||||
0xffff_ffff
|
|
||||||
};
|
|
||||||
|
|
||||||
// The config register read comes from the VFIO device itself.
|
|
||||||
self.vfio_wrapper.read_config_dword((reg_idx * 4) as u32) & mask
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_bar_reprogramming(
|
fn detect_bar_reprogramming(
|
||||||
|
Loading…
Reference in New Issue
Block a user