diff --git a/arch/Cargo.toml b/arch/Cargo.toml index 3e2202f02..4739c14f3 100644 --- a/arch/Cargo.toml +++ b/arch/Cargo.toml @@ -6,6 +6,7 @@ version = "0.1.0" [features] default = [] +fw_cfg = [] kvm = ["hypervisor/kvm"] sev_snp = [] tdx = [] diff --git a/arch/src/aarch64/fdt.rs b/arch/src/aarch64/fdt.rs index 23df4d805..3b8cfbcc4 100644 --- a/arch/src/aarch64/fdt.rs +++ b/arch/src/aarch64/fdt.rs @@ -850,6 +850,21 @@ fn create_gpio_node( Ok(()) } +// https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/fw-cfg.txt +#[cfg(feature = "fw_cfg")] +fn create_fw_cfg_node( + 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( fdt: &mut FdtWriter, dev_info: &HashMap<(DeviceType, String), T, S>, @@ -865,6 +880,8 @@ fn create_devices_node { ordered_virtio_device.push(info); } + #[cfg(feature = "fw_cfg")] + DeviceType::FwCfg => create_fw_cfg_node(fdt, info)?, } } diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 333a65d9c..bbca3e4ea 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -155,6 +155,9 @@ pub enum DeviceType { /// Device Type: GPIO. #[cfg(target_arch = "aarch64")] Gpio, + /// Device Type: fw_cfg. + #[cfg(feature = "fw_cfg")] + FwCfg, } /// Default (smallest) memory page size for the supported architectures. diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 81776dbc3..d2fcc4a94 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -44,6 +44,6 @@ arch = { path = "../arch" } [features] default = [] -fw_cfg = ["bitfield-struct", "linux-loader", "zerocopy"] +fw_cfg = ["arch/fw_cfg", "bitfield-struct", "linux-loader", "zerocopy"] kvm = ["arch/kvm"] pvmemcontrol = [] diff --git a/devices/src/legacy/fw_cfg.rs b/devices/src/legacy/fw_cfg.rs index 78bf87574..4e96d4535 100644 --- a/devices/src/legacy/fw_cfg.rs +++ b/devices/src/legacy/fw_cfg.rs @@ -91,6 +91,8 @@ const FW_CFG_KNOWN_ITEMS: usize = 0x20; pub const FW_CFG_FILE_FIRST: u16 = 0x20; 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) const FW_CFG_F_RESERVED: u8 = 1 << 0; // DMA Toggle Bit (enabled by default) diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index db9c0792b..53e2d1a4a 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -53,6 +53,8 @@ use devices::gic; use devices::interrupt_controller::InterruptController; #[cfg(target_arch = "x86_64")] 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")] use devices::legacy::Pl011; #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] @@ -1495,11 +1497,29 @@ impl DeviceManager { // 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)?; + { + self.address_manager + .mmio_bus + .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(()) } @@ -5003,6 +5023,27 @@ impl Aml for DeviceManager { ) .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 #[cfg(target_arch = "x86_64")] let serial_irq = 4;