devices: Add fw_cfg device

Here we add the fw_cfg device as a legacy device to the device manager.
It is guarded behind a fw_cfg flag in vmm at creation of the
DeviceManager. In this cl we implement the fw_cfg device with one
function (signature).

Signed-off-by: Alex Orozco <alexorozco@google.com>
This commit is contained in:
Alex Orozco
2025-03-24 19:02:50 +00:00
committed by Bo Chen
parent 5226ceb974
commit 777b7ee11e
11 changed files with 455 additions and 0 deletions

View File

@@ -57,6 +57,11 @@ use devices::ioapic;
use devices::legacy::Pl011;
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
use devices::legacy::Serial;
#[cfg(feature = "fw_cfg")]
use devices::legacy::{
fw_cfg::{PORT_FW_CFG_BASE, PORT_FW_CFG_WIDTH},
FwCfg,
};
#[cfg(feature = "pvmemcontrol")]
use devices::pvmemcontrol::{PvmemcontrolBusDevice, PvmemcontrolPciDevice};
use devices::{interrupt_controller, AcpiNotificationFlags};
@@ -644,6 +649,11 @@ pub enum DeviceManagerError {
/// Cannot lock images of all block devices.
#[error("Cannot lock images of all block devices")]
DiskLockError(#[source] virtio_devices::block::Error),
#[cfg(feature = "fw_cfg")]
/// Error adding fw_cfg to bus.
#[error("Error adding fw_cfg to bus")]
ErrorAddingFwCfgToBus(#[source] vm_device::BusError),
}
pub type DeviceManagerResult<T> = result::Result<T, DeviceManagerError>;
@@ -1070,6 +1080,9 @@ pub struct DeviceManager {
rate_limit_groups: HashMap<String, Arc<RateLimiterGroup>>,
mmio_regions: Arc<Mutex<Vec<MmioRegion>>>,
#[cfg(feature = "fw_cfg")]
fw_cfg: Option<Arc<Mutex<FwCfg>>>,
}
fn create_mmio_allocators(
@@ -1334,6 +1347,8 @@ impl DeviceManager {
snapshot,
rate_limit_groups,
mmio_regions: Arc::new(Mutex::new(Vec::new())),
#[cfg(feature = "fw_cfg")]
fw_cfg: None,
};
let device_manager = Arc::new(Mutex::new(device_manager));
@@ -1460,6 +1475,32 @@ impl DeviceManager {
Ok(())
}
#[cfg(feature = "fw_cfg")]
pub fn create_fw_cfg_device(&mut self) -> Result<(), DeviceManagerError> {
let fw_cfg = Arc::new(Mutex::new(devices::legacy::FwCfg::new()));
self.fw_cfg = Some(fw_cfg.clone());
self.bus_devices
.push(Arc::clone(&fw_cfg) as Arc<dyn BusDeviceSync>);
#[cfg(target_arch = "x86_64")]
self.address_manager
.io_bus
.insert(fw_cfg, PORT_FW_CFG_BASE, PORT_FW_CFG_WIDTH)
.map_err(DeviceManagerError::ErrorAddingFwCfgToBus)?;
// default address for fw_cfg on arm via mmio
// https://github.com/torvalds/linux/blob/master/drivers/firmware/qemu_fw_cfg.c#L27
#[cfg(target_arch = "aarch64")]
self.address_manager
.mmio_bus
.insert(fw_cfg.clone(), PORT_FW_CFG_BASE, PORT_FW_CFG_WIDTH)
.map_err(DeviceManagerError::ErrorAddingFwCfgToBus)?;
Ok(())
}
fn state(&self) -> DeviceManagerState {
DeviceManagerState {
device_tree: self.device_tree.lock().unwrap().clone(),
@@ -4181,6 +4222,11 @@ impl DeviceManager {
&self.address_manager.mmio_bus
}
#[cfg(feature = "fw_cfg")]
pub fn fw_cfg(&self) -> Option<&Arc<Mutex<FwCfg>>> {
self.fw_cfg.as_ref()
}
pub fn allocator(&self) -> &Arc<Mutex<SystemAllocator>> {
&self.address_manager.allocator
}

View File

@@ -405,6 +405,8 @@ pub fn feature_list() -> Vec<String> {
"dbus_api".to_string(),
#[cfg(feature = "dhat-heap")]
"dhat-heap".to_string(),
#[cfg(feature = "fw_cfg")]
"fw_cfg".to_string(),
#[cfg(feature = "guest_debug")]
"guest_debug".to_string(),
#[cfg(feature = "igvm")]

View File

@@ -720,6 +720,13 @@ impl Vm {
vm.sev_snp_init().map_err(Error::InitializeSevSnpVm)?;
}
#[cfg(feature = "fw_cfg")]
device_manager
.lock()
.unwrap()
.create_fw_cfg_device()
.map_err(Error::DeviceManager)?;
#[cfg(feature = "tdx")]
let kernel = config
.lock()