pci: Save deferred BAR reprogramming state

OVMF can reprogram PCI BARs while memory space decoding is disabled.
Cloud Hypervisor defers the corresponding BAR move in
`pending_bar_reprogram` until the PCI command register enables Memory
Space again.

That deferred state was not part of `PciConfigurationState`. A
snapshot taken in that window restored the new BAR values in PCI
config space, but lost the pending BAR relocation needed to update the
VMM-side BAR mapping.

The restore logs show guest MMIO accesses to the reprogrammed BAR
addresses `0xc0000000`, `0x100000000`, and `0x100080000` hitting
unregistered addresses. The firmware serial output shows OVMF
assigning those same BAR addresses during PCI resource allocation,
then reaching BDS, finding the mass-storage device, and failing to
boot from it.

Serialize and restore `pending_bar_reprogram` so deferred BAR moves
survive snapshot and restore.

Co-authored-by: Thomas Prescher <thomas.prescher@cyberus-technology.de>
Co-authored-by: Julian Schindel <julian.schindel@cyberus-technology.de>
On-behalf-of: SAP leander.kohler@sap.com
Signed-off-by: Leander Kohler <leander.kohler@cyberus-technology.de>
This commit is contained in:
Leander Kohler
2026-03-31 12:03:20 +02:00
committed by Rob Bradford
parent 0686045290
commit db93c6fdc7
2 changed files with 10 additions and 2 deletions

View File

@@ -422,6 +422,9 @@ pub struct PciConfigurationState {
rom_bar_used: bool,
last_capability: Option<(usize, usize)>,
msix_cap_reg_idx: Option<usize>,
// Preserve deferred BAR moves across snapshot and restore.
#[serde(default)]
pending_bar_reprogram: Vec<BarReprogrammingParams>,
}
/// Contains the configuration space of a PCI node.
@@ -557,6 +560,7 @@ impl PciConfiguration {
rom_bar_used,
last_capability,
msix_cap_reg_idx,
pending_bar_reprogram,
) = if let Some(state) = state {
(
state.registers.try_into().unwrap(),
@@ -567,6 +571,7 @@ impl PciConfiguration {
state.rom_bar_used,
state.last_capability,
state.msix_cap_reg_idx,
state.pending_bar_reprogram,
)
} else {
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
@@ -606,6 +611,7 @@ impl PciConfiguration {
false,
None,
None,
Vec::new(),
)
};
@@ -619,7 +625,7 @@ impl PciConfiguration {
last_capability,
msix_cap_reg_idx,
msix_config,
pending_bar_reprogram: Vec::new(),
pending_bar_reprogram,
}
}
@@ -633,6 +639,7 @@ impl PciConfiguration {
rom_bar_used: self.rom_bar_used,
last_capability: self.last_capability,
msix_cap_reg_idx: self.msix_cap_reg_idx,
pending_bar_reprogram: self.pending_bar_reprogram.clone(),
}
}

View File

@@ -8,6 +8,7 @@ use std::any::Any;
use std::sync::{Arc, Barrier, Mutex};
use std::{io, result};
use serde::{Deserialize, Serialize};
use thiserror::Error;
use vm_allocator::{AddressAllocator, SystemAllocator};
use vm_device::Resource;
@@ -35,7 +36,7 @@ pub enum Error {
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct BarReprogrammingParams {
pub old_base: u64,
pub new_base: u64,