vmm: Add acpi table for fw_cfg device

This allows the fw_cfg device to be recognized by the guest linux
kernel. This becomes more relavnt in the following cl where I add
the option to load files into the guest via fw_cfg. The Linux kernel
already has a fw_cfg driver that will automatically load these files
under /sys when CONFIG_FW_CFG_SYSFS is enabled in the kernel config

For arm we must add fw_cfg to the devices tree

Signed-off-by: Alex Orozco <alexorozco@google.com>
This commit is contained in:
Alex Orozco
2025-05-19 21:38:21 +00:00
committed by Bo Chen
parent edee53ac1a
commit 971f552e09
6 changed files with 69 additions and 5 deletions
+1
View File
@@ -6,6 +6,7 @@ version = "0.1.0"
[features] [features]
default = [] default = []
fw_cfg = []
kvm = ["hypervisor/kvm"] kvm = ["hypervisor/kvm"]
sev_snp = [] sev_snp = []
tdx = [] tdx = []
+17
View File
@@ -850,6 +850,21 @@ fn create_gpio_node<T: DeviceInfoForFdt + Clone + Debug>(
Ok(()) Ok(())
} }
// https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/fw-cfg.txt
#[cfg(feature = "fw_cfg")]
fn create_fw_cfg_node<T: DeviceInfoForFdt + Clone + Debug>(
fdt: &mut FdtWriter,
dev_info: &T,
) -> FdtWriterResult<()> {
// FwCfg node
let fw_cfg_node = fdt.begin_node(&format!("fw-cfg@{:x}", dev_info.addr()))?;
fdt.property("compatible", b"qemu,fw-cfg-mmio\0")?;
fdt.property_array_u64("reg", &[dev_info.addr(), dev_info.length()])?;
fdt.end_node(fw_cfg_node)?;
Ok(())
}
fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>( fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
fdt: &mut FdtWriter, fdt: &mut FdtWriter,
dev_info: &HashMap<(DeviceType, String), T, S>, dev_info: &HashMap<(DeviceType, String), T, S>,
@@ -865,6 +880,8 @@ fn create_devices_node<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Buil
DeviceType::Virtio(_) => { DeviceType::Virtio(_) => {
ordered_virtio_device.push(info); ordered_virtio_device.push(info);
} }
#[cfg(feature = "fw_cfg")]
DeviceType::FwCfg => create_fw_cfg_node(fdt, info)?,
} }
} }
+3
View File
@@ -155,6 +155,9 @@ pub enum DeviceType {
/// Device Type: GPIO. /// Device Type: GPIO.
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
Gpio, Gpio,
/// Device Type: fw_cfg.
#[cfg(feature = "fw_cfg")]
FwCfg,
} }
/// Default (smallest) memory page size for the supported architectures. /// Default (smallest) memory page size for the supported architectures.
+1 -1
View File
@@ -44,6 +44,6 @@ arch = { path = "../arch" }
[features] [features]
default = [] default = []
fw_cfg = ["bitfield-struct", "linux-loader", "zerocopy"] fw_cfg = ["arch/fw_cfg", "bitfield-struct", "linux-loader", "zerocopy"]
kvm = ["arch/kvm"] kvm = ["arch/kvm"]
pvmemcontrol = [] pvmemcontrol = []
+2
View File
@@ -91,6 +91,8 @@ const FW_CFG_KNOWN_ITEMS: usize = 0x20;
pub const FW_CFG_FILE_FIRST: u16 = 0x20; pub const FW_CFG_FILE_FIRST: u16 = 0x20;
pub const FW_CFG_DMA_SIGNATURE: [u8; 8] = *b"QEMU CFG"; pub const FW_CFG_DMA_SIGNATURE: [u8; 8] = *b"QEMU CFG";
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/qemu_fw_cfg.h
pub const FW_CFG_ACPI_ID: &str = "QEMU0002";
// Reserved (must be enabled) // Reserved (must be enabled)
const FW_CFG_F_RESERVED: u8 = 1 << 0; const FW_CFG_F_RESERVED: u8 = 1 << 0;
// DMA Toggle Bit (enabled by default) // DMA Toggle Bit (enabled by default)
+45 -4
View File
@@ -53,6 +53,8 @@ use devices::gic;
use devices::interrupt_controller::InterruptController; use devices::interrupt_controller::InterruptController;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
use devices::ioapic; use devices::ioapic;
#[cfg(all(feature = "fw_cfg", target_arch = "x86_64"))]
use devices::legacy::fw_cfg::FW_CFG_ACPI_ID;
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
use devices::legacy::Pl011; use devices::legacy::Pl011;
#[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))]
@@ -1495,11 +1497,29 @@ impl DeviceManager {
// default address for fw_cfg on arm via mmio // default address for fw_cfg on arm via mmio
// https://github.com/torvalds/linux/blob/master/drivers/firmware/qemu_fw_cfg.c#L27 // https://github.com/torvalds/linux/blob/master/drivers/firmware/qemu_fw_cfg.c#L27
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
self.address_manager {
.mmio_bus self.address_manager
.insert(fw_cfg.clone(), PORT_FW_CFG_BASE, PORT_FW_CFG_WIDTH) .mmio_bus
.map_err(DeviceManagerError::ErrorAddingFwCfgToBus)?; .insert(fw_cfg.clone(), PORT_FW_CFG_BASE, PORT_FW_CFG_WIDTH)
.map_err(DeviceManagerError::ErrorAddingFwCfgToBus)?;
let fw_cfg_irq = self
.address_manager
.allocator
.lock()
.unwrap()
.allocate_irq()
.unwrap();
self.id_to_dev_info.insert(
(DeviceType::FwCfg, "fw-cfg".to_string()),
MmioDeviceInfo {
addr: PORT_FW_CFG_BASE,
len: PORT_FW_CFG_WIDTH,
irq: fw_cfg_irq,
},
);
}
Ok(()) Ok(())
} }
@@ -5003,6 +5023,27 @@ impl Aml for DeviceManager {
) )
.to_aml_bytes(sink); .to_aml_bytes(sink);
#[cfg(all(feature = "fw_cfg", target_arch = "x86_64"))]
if self.fw_cfg.is_some() {
aml::Device::new(
"_SB_.FWCF".into(),
vec![
&aml::Name::new("_HID".into(), &FW_CFG_ACPI_ID.to_string()),
&aml::Name::new("_STA".into(), &0xB_usize),
&aml::Name::new(
"_CRS".into(),
&aml::ResourceTemplate::new(vec![&aml::IO::new(
PORT_FW_CFG_BASE as u16,
PORT_FW_CFG_BASE as u16,
0x01,
PORT_FW_CFG_WIDTH as u8,
)]),
),
],
)
.to_aml_bytes(sink);
}
// Serial device // Serial device
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
let serial_irq = 4; let serial_irq = 4;