From db93c6fdc7dfc3786128d2aaf2086fe49bc0d858 Mon Sep 17 00:00:00 2001 From: Leander Kohler Date: Tue, 31 Mar 2026 12:03:20 +0200 Subject: [PATCH] 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 Co-authored-by: Julian Schindel On-behalf-of: SAP leander.kohler@sap.com Signed-off-by: Leander Kohler --- pci/src/configuration.rs | 9 ++++++++- pci/src/device.rs | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pci/src/configuration.rs b/pci/src/configuration.rs index 4dbd04f12..f506017b2 100644 --- a/pci/src/configuration.rs +++ b/pci/src/configuration.rs @@ -422,6 +422,9 @@ pub struct PciConfigurationState { rom_bar_used: bool, last_capability: Option<(usize, usize)>, msix_cap_reg_idx: Option, + // Preserve deferred BAR moves across snapshot and restore. + #[serde(default)] + pending_bar_reprogram: Vec, } /// 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(), } } diff --git a/pci/src/device.rs b/pci/src/device.rs index 3c5b3315f..3a23ea777 100644 --- a/pci/src/device.rs +++ b/pci/src/device.rs @@ -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 = std::result::Result; -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct BarReprogrammingParams { pub old_base: u64, pub new_base: u64,