From 6880692a787fd8b69bb60be83bf41e5118e6d42a Mon Sep 17 00:00:00 2001 From: Jianyong Wu Date: Wed, 26 May 2021 13:33:08 +0800 Subject: [PATCH] vmm, acpi: Add DSM method to ACPI _DSM (Device Specific Method) is a control method that enables devices to provide device specific control functions. Linux kernel will evaluate this device then initialize preserve_config in acpi pci initialization. Signed-off-by: Jianyong Wu --- acpi_tables/Cargo.toml | 1 - vmm/Cargo.toml | 1 + vmm/src/device_manager.rs | 71 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/acpi_tables/Cargo.toml b/acpi_tables/Cargo.toml index ae75d27f4..ce46cb201 100644 --- a/acpi_tables/Cargo.toml +++ b/acpi_tables/Cargo.toml @@ -6,4 +6,3 @@ edition = "2018" [dependencies] vm-memory = "0.5.0" - diff --git a/vmm/Cargo.toml b/vmm/Cargo.toml index 5a184d68c..68e77b9fc 100644 --- a/vmm/Cargo.toml +++ b/vmm/Cargo.toml @@ -41,6 +41,7 @@ serde_derive = ">=1.0.27" serde_json = ">=1.0.9" signal-hook = "0.3.9" thiserror = "1.0" +uuid = "0.8" versionize = "0.1.6" versionize_derive = "0.1.4" vfio-ioctls = { git = "https://github.com/rust-vmm/vfio-ioctls", branch = "master" } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 376f1e9ad..07cb8b156 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -77,6 +77,8 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::result; use std::sync::{Arc, Barrier, Mutex}; +#[cfg(feature = "acpi")] +use uuid::Uuid; #[cfg(feature = "kvm")] use vfio_ioctls::{VfioContainer, VfioDevice}; use virtio_devices::transport::VirtioPciDevice; @@ -3593,6 +3595,71 @@ impl Aml for PciDevSlotMethods { } } +#[cfg(feature = "acpi")] +struct PciDsmMethod {} + +#[cfg(feature = "acpi")] +impl Aml for PciDsmMethod { + fn to_aml_bytes(&self) -> Vec { + // Refer to ACPI spec v6.3 Ch 9.1.1 and PCI Firmware spec v3.3 Ch 4.6.1 + // _DSM (Device Specific Method), the following is the implementation in ASL. + /* + Method (_DSM, 4, NotSerialized) // _DSM: Device-Specific Method + { + If ((Arg0 == ToUUID ("e5c937d0-3553-4d7a-9117-ea4d19c3434d") /* Device Labeling Interface */)) + { + If ((Arg2 == Zero)) + { + Return (Buffer (One) { 0x21 }) + } + If ((Arg2 == 0x05)) + { + Return (Zero) + } + } + + Return (Buffer (One) { 0x00 }) + } + */ + /* + * As per ACPI v6.3 Ch 19.6.142, the UUID is required to be in mixed endian: + * Among the fields of a UUID: + * {d1 (8 digits)} - {d2 (4 digits)} - {d3 (4 digits)} - {d4 (16 digits)} + * d1 ~ d3 need to be little endian, d4 be big endian. + * See https://en.wikipedia.org/wiki/Universally_unique_identifier#Encoding . + */ + let uuid = Uuid::parse_str("E5C937D0-3553-4D7A-9117-EA4D19C3434D").unwrap(); + let (uuid_d1, uuid_d2, uuid_d3, uuid_d4) = uuid.as_fields(); + let mut uuid_buf = vec![]; + uuid_buf.extend(&uuid_d1.to_le_bytes()); + uuid_buf.extend(&uuid_d2.to_le_bytes()); + uuid_buf.extend(&uuid_d3.to_le_bytes()); + uuid_buf.extend(uuid_d4); + aml::Method::new( + "_DSM".into(), + 4, + false, + vec![ + &aml::If::new( + &aml::Equal::new(&aml::Arg(0), &aml::Buffer::new(uuid_buf)), + vec![ + &aml::If::new( + &aml::Equal::new(&aml::Arg(2), &aml::ZERO), + vec![&aml::Return::new(&aml::Buffer::new(vec![0x21]))], + ), + &aml::If::new( + &aml::Equal::new(&aml::Arg(2), &0x05u8), + vec![&aml::Return::new(&aml::ZERO)], + ), + ], + ), + &aml::Return::new(&aml::Buffer::new(vec![0])), + ], + ) + .to_aml_bytes() + } +} + #[cfg(feature = "acpi")] impl Aml for DeviceManager { fn to_aml_bytes(&self) -> Vec { @@ -3671,6 +3738,10 @@ impl Aml for DeviceManager { pci_dsdt_inner_data.push(&uid); let supp = aml::Name::new("SUPP".into(), &aml::ZERO); pci_dsdt_inner_data.push(&supp); + + let pci_dsm = PciDsmMethod {}; + pci_dsdt_inner_data.push(&pci_dsm); + let crs = aml::Name::new( "_CRS".into(), &aml::ResourceTemplate::new(vec![