Skip to content

Commit f8e983a

Browse files
committed
pci: virtio: refactor: separate BARs logic from PciConfiguration
Currently logic for handling BARs is integrated into the PciConfiguration type. This makes it impossible to reuse for future VFIO work. In order to fix this, create a separate type just for handling of BARs region and make VirtioPciDevice type (the only user of PciConfiguration) to use that instead of PciConfiguration. This makes the original PciConfiguration not aware of any BARs which is fine. Future commits will remove BAR handling from PciConfiguration type, so the duplication is temporary. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 3d848e9 commit f8e983a

File tree

3 files changed

+267
-80
lines changed

3 files changed

+267
-80
lines changed

src/vmm/src/device_manager/pci_mngr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,11 @@ impl PciDevices {
9393

9494
debug!(
9595
"Inserting MMIO BAR region: {:#x}:{:#x}",
96-
virtio_device_locked.bar_address, CAPABILITY_BAR_SIZE
96+
virtio_device_locked.config_bar_addr(), CAPABILITY_BAR_SIZE
9797
);
9898
vm.common.mmio_bus.insert(
9999
virtio_device.clone(),
100-
virtio_device_locked.bar_address,
100+
virtio_device_locked.config_bar_addr(),
101101
CAPABILITY_BAR_SIZE,
102102
)?;
103103

src/vmm/src/devices/virtio/transport/pci/device.rs

Lines changed: 66 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use vm_allocator::{AddressAllocator, AllocPolicy, RangeInclusive};
2626
use vm_memory::{Address, ByteValued, GuestAddress, Le32};
2727
use vmm_sys_util::errno;
2828
use vmm_sys_util::eventfd::EventFd;
29+
use zerocopy::IntoBytes;
2930

3031
use crate::Vm;
3132
use crate::devices::virtio::device::{VirtioDevice, VirtioDeviceType};
@@ -36,7 +37,9 @@ use crate::devices::virtio::transport::pci::common_config::{
3637
};
3738
use crate::devices::virtio::transport::{VirtioInterrupt, VirtioInterruptType};
3839
use crate::logger::{debug, error};
39-
use crate::pci::configuration::{PciCapability, PciConfiguration, PciConfigurationState};
40+
use crate::pci::configuration::{
41+
BAR0_REG, Bars, NUM_BAR_REGS, PciCapability, PciConfiguration, PciConfigurationState,
42+
};
4043
use crate::pci::msix::{MsixCap, MsixConfig, MsixConfigState};
4144
use crate::pci::{BarReprogrammingParams, DeviceRelocationError, PciDevice};
4245
use crate::snapshot::Persist;
@@ -242,7 +245,7 @@ pub struct VirtioPciDeviceState {
242245
pub pci_configuration_state: PciConfigurationState,
243246
pub pci_dev_state: VirtioPciCommonConfigState,
244247
pub msix_state: MsixConfigState,
245-
pub bar_address: u64,
248+
pub bars: Bars,
246249
}
247250

248251
#[derive(Debug, thiserror::Error, displaydoc::Display)]
@@ -286,8 +289,8 @@ pub struct VirtioPciDevice {
286289
// a device.
287290
cap_pci_cfg_info: VirtioPciCfgCapInfo,
288291

289-
// Allocated address for the BAR
290-
pub bar_address: u64,
292+
// BARs region for the device
293+
pub bars: Bars,
291294
}
292295

293296
impl Debug for VirtioPciDevice {
@@ -350,16 +353,14 @@ impl VirtioPciDevice {
350353
)
351354
.unwrap()
352355
.start();
353-
354-
self.configuration.add_pci_bar(
355-
VIRTIO_BAR_INDEX as usize,
356+
// Virtio BAR is 64bit BAR without prefetchable bit since it is an MMIO region.
357+
self.bars.set_bar_64(
358+
VIRTIO_BAR_INDEX,
356359
virtio_pci_bar_addr,
357360
CAPABILITY_BAR_SIZE,
361+
false,
358362
);
359-
360-
// Once the BARs are allocated, the capabilities can be added to the PCI configuration.
361363
self.add_pci_capabilities();
362-
self.bar_address = virtio_pci_bar_addr;
363364
}
364365

365366
/// Constructs a new PCI transport for the given virtio device.
@@ -408,7 +409,7 @@ impl VirtioPciDevice {
408409
virtio_interrupt: Some(interrupt),
409410
memory,
410411
cap_pci_cfg_info: VirtioPciCfgCapInfo::default(),
411-
bar_address: 0,
412+
bars: Bars::default(),
412413
};
413414

414415
Ok(virtio_pci_device)
@@ -453,7 +454,7 @@ impl VirtioPciDevice {
453454
virtio_interrupt: Some(interrupt),
454455
memory: vm.guest_memory().clone(),
455456
cap_pci_cfg_info,
456-
bar_address: state.bar_address,
457+
bars: state.bars,
457458
};
458459

459460
if state.device_activated {
@@ -483,7 +484,7 @@ impl VirtioPciDevice {
483484
}
484485

485486
pub fn config_bar_addr(&self) -> u64 {
486-
self.configuration.get_bar_addr(VIRTIO_BAR_INDEX as usize)
487+
self.bars.get_bar_addr_64(VIRTIO_BAR_INDEX)
487488
}
488489

489490
fn add_pci_capabilities(&mut self) {
@@ -638,7 +639,7 @@ impl VirtioPciDevice {
638639
.lock()
639640
.expect("Poisoned lock")
640641
.state(),
641-
bar_address: self.bar_address,
642+
bars: self.bars,
642643
}
643644
}
644645
}
@@ -742,42 +743,63 @@ impl PciDevice for VirtioPciDevice {
742743
offset: u64,
743744
data: &[u8],
744745
) -> Option<Arc<Barrier>> {
745-
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
746-
// is accessed. This capability has a special meaning as it allows the
747-
// guest to access other capabilities without mapping the PCI BAR.
748-
let base = reg_idx * 4;
749-
if base + u64_to_usize(offset) >= self.cap_pci_cfg_info.offset
750-
&& base + u64_to_usize(offset) + data.len()
751-
<= self.cap_pci_cfg_info.offset + self.cap_pci_cfg_info.cap.bytes().len()
752-
{
753-
let offset = base + u64_to_usize(offset) - self.cap_pci_cfg_info.offset;
754-
self.write_cap_pci_cfg(offset, data)
755-
} else {
756-
self.configuration
757-
.write_config_register(reg_idx, offset, data);
746+
if BAR0_REG as usize <= reg_idx && reg_idx < (BAR0_REG + NUM_BAR_REGS) as usize {
747+
// reg_idx is in [BAR0_REG, BAR0_REG+NUM_BAR_REGS), so the difference is 0..5.
748+
#[allow(clippy::cast_possible_truncation)]
749+
let bar_idx = (reg_idx - BAR0_REG as usize) as u8;
750+
// offset is within a 4-byte PCI config register (0..3).
751+
#[allow(clippy::cast_possible_truncation)]
752+
let offset = offset as u8;
753+
self.bars.write(bar_idx, offset, data);
758754
None
755+
} else {
756+
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
757+
// is accessed. This capability has a special meaning as it allows the
758+
// guest to access other capabilities without mapping the PCI BAR.
759+
let base = reg_idx * 4;
760+
if base + u64_to_usize(offset) >= self.cap_pci_cfg_info.offset
761+
&& base + u64_to_usize(offset) + data.len()
762+
<= self.cap_pci_cfg_info.offset + self.cap_pci_cfg_info.cap.bytes().len()
763+
{
764+
let offset = base + u64_to_usize(offset) - self.cap_pci_cfg_info.offset;
765+
self.write_cap_pci_cfg(offset, data)
766+
} else {
767+
self.configuration
768+
.write_config_register(reg_idx, offset, data);
769+
None
770+
}
759771
}
760772
}
761773

762774
fn read_config_register(&mut self, reg_idx: usize) -> u32 {
763-
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
764-
// is accessed. This capability has a special meaning as it allows the
765-
// guest to access other capabilities without mapping the PCI BAR.
766-
let base = reg_idx * 4;
767-
if base >= self.cap_pci_cfg_info.offset
768-
&& base + 4 <= self.cap_pci_cfg_info.offset + self.cap_pci_cfg_info.cap.bytes().len()
769-
{
770-
let offset = base - self.cap_pci_cfg_info.offset;
771-
let mut data = [0u8; 4];
772-
let len = u32::from(self.cap_pci_cfg_info.cap.cap.length) as usize;
773-
if len <= 4 {
774-
self.read_cap_pci_cfg(offset, &mut data[..len]);
775-
u32::from_le_bytes(data)
775+
if BAR0_REG as usize <= reg_idx && reg_idx < (BAR0_REG + NUM_BAR_REGS) as usize {
776+
// reg_idx is in [BAR0_REG, BAR0_REG+NUM_BAR_REGS), so the difference is 0..5.
777+
#[allow(clippy::cast_possible_truncation)]
778+
let bar_idx = (reg_idx - BAR0_REG as usize) as u8;
779+
let mut value: u32 = 0;
780+
self.bars.read(bar_idx, 0, value.as_mut_bytes());
781+
value
782+
} else {
783+
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
784+
// is accessed. This capability has a special meaning as it allows the
785+
// guest to access other capabilities without mapping the PCI BAR.
786+
let base = reg_idx * 4;
787+
if base >= self.cap_pci_cfg_info.offset
788+
&& base + 4
789+
<= self.cap_pci_cfg_info.offset + self.cap_pci_cfg_info.cap.bytes().len()
790+
{
791+
let offset = base - self.cap_pci_cfg_info.offset;
792+
let mut data = [0u8; 4];
793+
let len = u32::from(self.cap_pci_cfg_info.cap.cap.length) as usize;
794+
if len <= 4 {
795+
self.read_cap_pci_cfg(offset, &mut data[..len]);
796+
u32::from_le_bytes(data)
797+
} else {
798+
0
799+
}
776800
} else {
777-
0
801+
self.configuration.read_reg(reg_idx)
778802
}
779-
} else {
780-
self.configuration.read_reg(reg_idx)
781803
}
782804
}
783805

@@ -786,7 +808,7 @@ impl PciDevice for VirtioPciDevice {
786808
reg_idx: usize,
787809
data: &[u8],
788810
) -> Option<BarReprogrammingParams> {
789-
self.configuration.detect_bar_reprogramming(reg_idx, data)
811+
None
790812
}
791813

792814
fn read_bar(&mut self, _base: u64, offset: u64, data: &mut [u8]) {

0 commit comments

Comments
 (0)