pci: Reprogram device BAR when its MSE bit is set

The Memory Space Enable (MSE) bit from the COMMAND register in the
PCI configuration space controls whether a PCI device responds to memory
space accesses, e.g. read and write cycles to the device MMIO regions
defined by its BARs. The MSE bit is used by the device drivers to ensure
the correctness of BAR reprogramming. A common workflow is, the driver
first clears the MSE bit, then writes new values to the BAR registers,
and finally set the MSE bit to finish the BAR reprogramming.

This patch changes how we handle BAR reprogramming for all PCI
devices (e.g. virtio-pci, vfio, vfio-user, etc.), so that we follow the
same convention, e.g. moving PCI BARs when its MSE bit is set.

Note that some device drivers (such as edk2) only clear and set MSE once
while reprogramming multiple BARs of a single device. To support such
behavior, this patch adds support for multiple pending BAR reprogramming.

See: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/7027#issuecomment-2853642959

Signed-off-by: Bo Chen <bchen@crusoe.ai>
This commit is contained in:
Bo Chen
2025-05-12 22:15:56 +00:00
parent 59f98a2edc
commit aaf86ef209
8 changed files with 43 additions and 17 deletions

View File

@@ -698,7 +698,7 @@ impl PciDevice for PvmemcontrolPciDevice {
reg_idx: usize,
offset: u64,
data: &[u8],
) -> (Option<BarReprogrammingParams>, Option<Arc<Barrier>>) {
) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
(
self.configuration
.write_config_register(reg_idx, offset, data),

View File

@@ -90,7 +90,7 @@ impl PvPanicDevice {
let command: [u8; 2] = [0x03, 0x01];
let bar_reprogram = configuration.write_config_register(1, 0, &command);
assert!(
bar_reprogram.is_none(),
bar_reprogram.is_empty(),
"No bar reprogrammig is expected from writing to the COMMAND register"
);
@@ -160,7 +160,7 @@ impl PciDevice for PvPanicDevice {
reg_idx: usize,
offset: u64,
data: &[u8],
) -> (Option<BarReprogrammingParams>, Option<Arc<Barrier>>) {
) -> (Vec<BarReprogrammingParams>, Option<Arc<Barrier>>) {
(
self.configuration
.write_config_register(reg_idx, offset, data),