acpi: x86: add support for ACPI Notify() forwarding

In order to replicate the ACPI notification from the host to the guest
pass-through devices:
1) allocate GPE and eventfd per pci-vfio device
2) generate proper aml code for ACPI GPE handler. The example of generated aml:

    Scope (_GPE)
    {
        Method (_E00, 0, NotSerialized)  // _Exx: Edge-Triggered GPE, xx=0x00-0xFF
        {
            Local0 = \_SB.PC00.PE08.NOTY
            Notify (\_SB.PC00.PE08, Local0)
        }
    }

The eventfd is registered by host kernel via VFIO_DEVICE_SET_IRQS
ioctl. Crosvm upon receiving early provided, per pci-vfio eventfd,
stores the notification value and triggers GPE associated to pci-vfio
device.

Guest kernel upon handling GPE (thanks to generated aml [ad 2)],
triggers Notify on required pass-through device and therefore replicates
the ACPI Notification on the guest side [Accessing \_SB.PC00.PE08.NOTY
pointed by VCFG opregion result with trap to crosvm, which returns
previously stored notify value].

Kernel counterpart: CL:4538472

BUG=b:244205651
TEST=Observe replication of ACPI notification in the guest kernel

Change-Id: Iaf66097acd84f3066f6ff70d382f83ecaeea9a00
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/4538483
Commit-Queue: Grzegorz Jaszczyk <jaszczyk@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Grzegorz Jaszczyk 2023-01-18 16:56:34 +00:00 committed by crosvm LUCI
parent e70a8774a1
commit 298be81446
13 changed files with 303 additions and 32 deletions

View file

@ -547,19 +547,20 @@ impl arch::LinuxArch for AArch64 {
.into_iter()
.map(|(dev, jail_orig)| (dev.into_pci_device().unwrap(), jail_orig))
.collect();
let (pci, pci_irqs, mut pid_debug_label_map, _amls) = arch::generate_pci_root(
pci_devices,
irq_chip.as_irq_chip_mut(),
mmio_bus.clone(),
io_bus.clone(),
system_allocator,
&mut vm,
(devices::AARCH64_GIC_NR_SPIS - AARCH64_IRQ_BASE) as usize,
None,
#[cfg(feature = "swap")]
swap_controller,
)
.map_err(Error::CreatePciRoot)?;
let (pci, pci_irqs, mut pid_debug_label_map, _amls, _gpe_scope_amls) =
arch::generate_pci_root(
pci_devices,
irq_chip.as_irq_chip_mut(),
mmio_bus.clone(),
io_bus.clone(),
system_allocator,
&mut vm,
(devices::AARCH64_GIC_NR_SPIS - AARCH64_IRQ_BASE) as usize,
None,
#[cfg(feature = "swap")]
swap_controller,
)
.map_err(Error::CreatePciRoot)?;
let pci_root = Arc::new(Mutex::new(pci));
let pci_bus = Arc::new(Mutex::new(PciConfigMmio::new(pci_root.clone(), 8)));

View file

@ -39,6 +39,7 @@ use devices::BusDeviceObj;
use devices::BusError;
use devices::BusResumeDevice;
use devices::FwCfgParameters;
use devices::GpeScope;
use devices::HotPlugBus;
use devices::IrqChip;
use devices::IrqEventSource;
@ -957,6 +958,7 @@ pub fn generate_pci_root(
Vec<(PciAddress, u32, PciInterruptPin)>,
BTreeMap<u32, String>,
BTreeMap<PciAddress, Vec<u8>>,
BTreeMap<PciAddress, Vec<u8>>,
),
DeviceRegistrationError,
> {
@ -1081,6 +1083,7 @@ pub fn generate_pci_root(
};
let mut amls = BTreeMap::new();
let mut gpe_scope_amls = BTreeMap::new();
for (dev_idx, dev_value) in devices {
#[cfg(unix)]
let (mut device, jail) = dev_value;
@ -1113,6 +1116,7 @@ pub fn generate_pci_root(
);
}
}
let gpe_nr = device.set_gpe(resources);
#[cfg(unix)]
let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
@ -1148,9 +1152,24 @@ pub fn generate_pci_root(
.insert(arced_dev.clone(), range.addr, range.size)
.map_err(DeviceRegistrationError::MmioInsert)?;
}
if let Some(gpe_nr) = gpe_nr {
if let Some(acpi_path) = root.acpi_path(&address) {
let mut gpe_aml = Vec::new();
GpeScope {}.cast_to_aml_bytes(
&mut gpe_aml,
gpe_nr,
format!("\\{}", acpi_path).as_str(),
);
if !gpe_aml.is_empty() {
gpe_scope_amls.insert(address, gpe_aml);
}
}
}
}
Ok((root, pci_irqs, pid_labels, amls))
Ok((root, pci_irqs, pid_labels, amls, gpe_scope_amls))
}
/// Errors for image loading.

View file

@ -97,6 +97,7 @@ pub use self::pci::Ac97Dev;
pub use self::pci::Ac97Parameters;
pub use self::pci::BarRange;
pub use self::pci::CrosvmDeviceId;
pub use self::pci::GpeScope;
#[cfg(feature = "pci-hotplug")]
pub use self::pci::HotPluggable;
#[cfg(feature = "pci-hotplug")]

View file

@ -53,6 +53,7 @@ impl Aml for DeviceVcfgRegister {
vec![
aml::FieldEntry::Named(*b"PFPM", 32),
aml::FieldEntry::Named(*b"PDSM", 32),
aml::FieldEntry::Named(*b"NOTY", 32),
],
)
.to_aml_bytes(bytes);
@ -531,3 +532,26 @@ impl Aml for PowerResourceMethod {
.to_aml_bytes(aml);
}
}
pub struct GpeScope {}
impl GpeScope {
pub fn cast_to_aml_bytes(&self, aml: &mut Vec<u8>, gpe_nr: u32, notification_path: &str) {
aml::Scope::new(
"_GPE".into(),
vec![&aml::Method::new(
format!("_E{:02X}", gpe_nr).as_str().into(),
0,
false,
vec![
&aml::Store::new(
&aml::Local(0),
&aml::Path::new(format!("{}.NOTY", notification_path).as_str()),
),
&aml::Notify::new(&aml::Path::new(notification_path), &aml::Local(0)),
],
)],
)
.to_aml_bytes(aml);
}
}

View file

@ -43,6 +43,7 @@ pub use self::ac97::Ac97Dev;
pub use self::ac97::Ac97Parameters;
pub use self::acpi::DeviceVcfgRegister;
pub use self::acpi::DsmMethod;
pub use self::acpi::GpeScope;
pub use self::acpi::PowerResourceMethod;
#[cfg(unix)]
pub use self::coiommu::CoIommuDev;
@ -124,6 +125,7 @@ impl PciInterruptPin {
// VCFG
pub const PCI_VCFG_PM: usize = 0x0;
pub const PCI_VCFG_DSM: usize = 0x1;
pub const PCI_VCFG_NOTY: usize = 0x2;
pub const PCI_VENDOR_ID_INTEL: u16 = 0x8086;
pub const PCI_VENDOR_ID_REDHAT: u16 = 0x1b36;

View file

@ -48,6 +48,15 @@ use crate::Suspendable;
#[sorted]
#[derive(Error, Debug)]
pub enum Error {
/// Deactivation of ACPI notifications failed
#[error("failed to disable ACPI notifications")]
AcpiNotifyDeactivationFailed,
/// Setup of ACPI notifications failed
#[error("failed to enable ACPI notifications")]
AcpiNotifySetupFailed,
/// Simulating ACPI notifications hardware triggering failed
#[error("failed to test ACPI notifications")]
AcpiNotifyTestFailed,
/// Added pci device's parent bus does not belong to this bus
#[error("pci device {0}'s parent bus does not belong to bus {1}")]
AddedDeviceBusNotExist(PciAddress, u8),
@ -433,6 +442,10 @@ pub trait PciDevice: Send + Suspendable {
(Vec::new(), None)
}
fn set_gpe(&mut self, _resources: &mut SystemAllocator) -> Option<u32> {
None
}
/// Invoked when the device is destroyed
fn destroy_device(&mut self) {}
@ -766,6 +779,10 @@ impl<T: PciDevice + ?Sized> PciDevice for Box<T> {
(**self).generate_acpi_methods()
}
fn set_gpe(&mut self, resources: &mut SystemAllocator) -> Option<u32> {
(**self).set_gpe(resources)
}
fn destroy_device(&mut self) {
(**self).destroy_device();
}

View file

@ -34,6 +34,7 @@ use resources::AllocOptions;
use resources::MmioType;
use resources::SystemAllocator;
use sync::Mutex;
use vfio_sys::vfio::VFIO_PCI_ACPI_NTFY_IRQ_INDEX;
use vfio_sys::*;
use vm_control::api::VmMemoryClient;
use vm_control::HotPlugDeviceInfo;
@ -76,6 +77,7 @@ use crate::pci::PciClassCode;
use crate::pci::PciId;
use crate::pci::PciInterruptPin;
use crate::pci::PCI_VCFG_DSM;
use crate::pci::PCI_VCFG_NOTY;
use crate::pci::PCI_VCFG_PM;
use crate::pci::PCI_VENDOR_ID_INTEL;
use crate::vfio::VfioDevice;
@ -509,14 +511,18 @@ impl VfioPciWorker {
&mut self,
req_irq_evt: Event,
wakeup_evt: Event,
acpi_notify_evt: Event,
kill_evt: Event,
msix_evt: Vec<Event>,
is_in_low_power: Arc<Mutex<bool>>,
gpe: Option<u32>,
notification_val: Arc<Mutex<Vec<u32>>>,
) {
#[derive(EventToken)]
#[derive(EventToken, Debug)]
enum Token {
ReqIrq,
WakeUp,
AcpiNotifyEvent,
Kill,
MsixIrqi { index: usize },
}
@ -524,6 +530,7 @@ impl VfioPciWorker {
let wait_ctx: WaitContext<Token> = match WaitContext::build_with(&[
(&req_irq_evt, Token::ReqIrq),
(&wakeup_evt, Token::WakeUp),
(&acpi_notify_evt, Token::AcpiNotifyEvent),
(&kill_evt, Token::Kill),
]) {
Ok(pc) => pc,
@ -596,6 +603,21 @@ impl VfioPciWorker {
}
}
}
Token::AcpiNotifyEvent => {
if let Some(gpe) = gpe {
if let Ok(val) = base::EventExt::read_count(&acpi_notify_evt) {
notification_val.lock().push(val as u32);
let request = VmRequest::Gpe(gpe);
if self.vm_socket.send(&request).is_ok() {
if let Err(e) = self.vm_socket.recv::<VmResponse>() {
error!("{} failed to send GPE: {}", self.name.clone(), e);
}
}
} else {
error!("{} failed to read acpi_notify_evt", self.name.clone());
}
}
}
Token::Kill => break 'wait,
}
}
@ -641,6 +663,7 @@ pub struct VfioPciDevice {
preferred_address: PciAddress,
pci_address: Option<PciAddress>,
interrupt_evt: Option<IrqLevelEvent>,
acpi_notification_evt: Option<Event>,
mmio_regions: Vec<PciBarConfiguration>,
io_regions: Vec<PciBarConfiguration>,
pm_cap: Option<Arc<Mutex<VfioPmCap>>>,
@ -659,6 +682,8 @@ pub struct VfioPciDevice {
vcfg_shm_mmap: Option<MemoryMapping>,
mapped_mmio_bars: BTreeMap<PciBarIndex, (u64, Vec<VmMemoryRegionId>)>,
activated: bool,
acpi_notifier_val: Arc<Mutex<Vec<u32>>>,
gpe: Option<u32>,
}
impl VfioPciDevice {
@ -806,6 +831,7 @@ impl VfioPciDevice {
preferred_address,
pci_address: None,
interrupt_evt: None,
acpi_notification_evt: None,
mmio_regions: Vec::new(),
io_regions: Vec::new(),
pm_cap,
@ -823,6 +849,8 @@ impl VfioPciDevice {
vcfg_shm_mmap: None,
mapped_mmio_bars: BTreeMap::new(),
activated: false,
acpi_notifier_val: Arc::new(Mutex::new(Vec::new())),
gpe: None,
})
}
@ -843,6 +871,38 @@ impl VfioPciDevice {
ret
}
fn enable_acpi_notification(&mut self) -> Result<(), PciDeviceError> {
if let Some(ref acpi_notification_evt) = self.acpi_notification_evt {
return self
.device
.acpi_notification_evt_enable(acpi_notification_evt, VFIO_PCI_ACPI_NTFY_IRQ_INDEX)
.map_err(|_| PciDeviceError::AcpiNotifySetupFailed);
}
Err(PciDeviceError::AcpiNotifySetupFailed)
}
#[allow(dead_code)]
fn disable_acpi_notification(&mut self) -> Result<(), PciDeviceError> {
if let Some(ref _acpi_notification_evt) = self.acpi_notification_evt {
return self
.device
.acpi_notification_disable(VFIO_PCI_ACPI_NTFY_IRQ_INDEX)
.map_err(|_| PciDeviceError::AcpiNotifyDeactivationFailed);
}
Err(PciDeviceError::AcpiNotifyDeactivationFailed)
}
#[allow(dead_code)]
fn test_acpi_notification(&mut self, val: u32) -> Result<(), PciDeviceError> {
if let Some(ref _acpi_notification_evt) = self.acpi_notification_evt {
return self
.device
.acpi_notification_test(VFIO_PCI_ACPI_NTFY_IRQ_INDEX, val)
.map_err(|_| PciDeviceError::AcpiNotifyTestFailed);
}
Err(PciDeviceError::AcpiNotifyTestFailed)
}
fn enable_intx(&mut self) {
if let Some(ref interrupt_evt) = self.interrupt_evt {
if let Err(e) = self.device.irq_enable(
@ -1223,6 +1283,24 @@ impl VfioPciDevice {
};
self.pm_evt = Some(self_pm_evt);
let (self_acpi_notify_evt, acpi_notify_evt) =
match Event::new().and_then(|e| Ok((e.try_clone()?, e))) {
Ok(v) => v,
Err(e) => {
error!(
"{} failed creating ACPI Event pair: {}",
self.debug_label(),
e
);
return;
}
};
self.acpi_notification_evt = Some(self_acpi_notify_evt);
if let Err(e) = self.enable_acpi_notification() {
error!("{}: {}", self.debug_label(), e);
}
let mut msix_evt = Vec::new();
if let Some(msix_cap) = &self.msix_cap {
msix_evt = msix_cap.lock().clone_msix_evt();
@ -1234,6 +1312,8 @@ impl VfioPciDevice {
let pm_cap = self.pm_cap.clone();
let msix_cap = self.msix_cap.clone();
let is_in_low_power = self.is_in_low_power.clone();
let gpe_nr = self.gpe;
let notification_val = self.acpi_notifier_val.clone();
self.worker_thread = Some(WorkerThread::start("vfio_pci", move |kill_evt| {
let mut worker = VfioPciWorker {
address,
@ -1243,7 +1323,16 @@ impl VfioPciDevice {
pm_cap,
msix_cap,
};
worker.run(req_evt, pm_evt, kill_evt, msix_evt, is_in_low_power);
worker.run(
req_evt,
pm_evt,
acpi_notify_evt,
kill_evt,
msix_evt,
is_in_low_power,
gpe_nr,
notification_val,
);
worker
}));
self.activated = true;
@ -1865,6 +1954,16 @@ impl PciDevice for VfioPciDevice {
}
fn read_virtual_config_register(&self, reg_idx: usize) -> u32 {
if reg_idx == PCI_VCFG_NOTY {
let mut q = self.acpi_notifier_val.lock();
let mut val = 0;
if !q.is_empty() {
val = q.remove(0);
}
drop(q);
return val;
}
warn!(
"{} read unsupported vcfg register {}",
self.debug_label(),
@ -2002,6 +2101,14 @@ impl PciDevice for VfioPciDevice {
(amls, shm)
}
fn set_gpe(&mut self, resources: &mut SystemAllocator) -> Option<u32> {
if let Some(gpe_nr) = resources.allocate_gpe() {
base::debug!("set_gpe: gpe-nr {} addr {:?}", gpe_nr, self.pci_address);
self.gpe = Some(gpe_nr);
}
self.gpe
}
}
impl Suspendable for VfioPciDevice {

View file

@ -44,6 +44,7 @@ use resources::Error as ResourcesError;
use sync::Mutex;
use thiserror::Error;
use vfio_sys::vfio::vfio_acpi_dsm;
use vfio_sys::vfio::VFIO_IRQ_SET_DATA_BOOL;
use vfio_sys::*;
use vm_memory::MemoryRegionInformation;
use zerocopy::AsBytes;
@ -96,6 +97,12 @@ pub enum VfioError {
UnknownDeviceType(u32),
#[error("failed to call vfio device's ACPI _DSM: {0}")]
VfioAcpiDsm(Error),
#[error("failed to disable vfio deviece's acpi notification: {0}")]
VfioAcpiNotificationDisable(Error),
#[error("failed to enable vfio deviece's acpi notification: {0}")]
VfioAcpiNotificationEnable(Error),
#[error("failed to test vfio deviece's acpi notification: {0}")]
VfioAcpiNotificationTest(Error),
#[error(
"vfio API version doesn't match with VFIO_API_VERSION defined in vfio_sys/src/vfio.rs"
)]
@ -971,6 +978,78 @@ impl VfioDevice {
}
}
/// Enable vfio device's ACPI notifications and associate EventFD with device.
pub fn acpi_notification_evt_enable(
&self,
acpi_notification_eventfd: &Event,
index: u32,
) -> Result<()> {
let u32_size = mem::size_of::<u32>();
let count = 1;
let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(count);
irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + count * u32_size) as u32;
irq_set[0].flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
irq_set[0].index = index;
irq_set[0].start = 0;
irq_set[0].count = count as u32;
// It is safe as enough space is reserved through vec_with_array_field(u32)<count>.
let data = unsafe { irq_set[0].data.as_mut_slice(count * u32_size) };
data.copy_from_slice(&acpi_notification_eventfd.as_raw_descriptor().to_ne_bytes()[..]);
// Safe as we are the owner of self and irq_set which are valid value
let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS(), &irq_set[0]) };
if ret < 0 {
Err(VfioError::VfioAcpiNotificationEnable(get_error()))
} else {
Ok(())
}
}
/// Disable vfio device's ACPI notification and disconnect EventFd with device.
pub fn acpi_notification_disable(&self, index: u32) -> Result<()> {
let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(0);
irq_set[0].argsz = mem::size_of::<vfio_irq_set>() as u32;
irq_set[0].flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
irq_set[0].index = index;
irq_set[0].start = 0;
irq_set[0].count = 0;
// Safe as we are the owner of self and irq_set which are valid value
let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS(), &irq_set[0]) };
if ret < 0 {
Err(VfioError::VfioAcpiNotificationDisable(get_error()))
} else {
Ok(())
}
}
/// Test vfio device's ACPI notification by simulating hardware triggering.
/// When the signaling mechanism is set, the VFIO_IRQ_SET_DATA_BOOL can be used with
/// VFIO_IRQ_SET_ACTION_TRIGGER to perform kernel level interrupt loopback testing.
pub fn acpi_notification_test(&self, index: u32, val: u32) -> Result<()> {
let u32_size = mem::size_of::<u32>();
let mut irq_set = vec_with_array_field::<vfio_irq_set, u32>(1);
irq_set[0].argsz = (mem::size_of::<vfio_irq_set>() + u32_size) as u32;
irq_set[0].flags = VFIO_IRQ_SET_DATA_BOOL | VFIO_IRQ_SET_ACTION_TRIGGER;
irq_set[0].index = index;
irq_set[0].start = 0;
irq_set[0].count = 1;
// It is safe as enough space is reserved through vec_with_array_field(u32)<count>.
let data = unsafe { irq_set[0].data.as_mut_slice(u32_size) };
data.copy_from_slice(&val.to_ne_bytes()[..]);
// Safe as we are the owner of self and irq_set which are valid value
let ret = unsafe { ioctl_with_ref(&self.dev, VFIO_DEVICE_SET_IRQS(), &irq_set[0]) };
if ret < 0 {
Err(VfioError::VfioAcpiNotificationTest(get_error()))
} else {
Ok(())
}
}
/// Enable vfio device's irq and associate Irqfd Event with device.
/// When MSIx is enabled, multi vectors will be supported, and vectors starting from subindex to subindex +
/// descriptors length will be assigned with irqfd in the descriptors array.

View file

@ -28,6 +28,13 @@ pub struct vfio_acpi_dsm {
pub args: __IncompleteArrayField<u8>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_acpi_notify_eventfd {
pub notify_eventfd: i32,
pub reserved: u32,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct vfio_region_info_with_cap {

View file

@ -19,6 +19,13 @@ pub struct vfio_acpi_dsm {
pub args: __IncompleteArrayField<u8>,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct vfio_acpi_notify_eventfd {
pub notify_eventfd: i32,
pub reserved: u32,
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct vfio_region_info_with_cap {
@ -308,7 +315,8 @@ pub const VFIO_PCI_MSI_IRQ_INDEX: _bindgen_ty_2 = 1;
pub const VFIO_PCI_MSIX_IRQ_INDEX: _bindgen_ty_2 = 2;
pub const VFIO_PCI_ERR_IRQ_INDEX: _bindgen_ty_2 = 3;
pub const VFIO_PCI_REQ_IRQ_INDEX: _bindgen_ty_2 = 4;
pub const VFIO_PCI_NUM_IRQS: _bindgen_ty_2 = 5;
pub const VFIO_PCI_ACPI_NTFY_IRQ_INDEX: _bindgen_ty_2 = 5;
pub const VFIO_PCI_NUM_IRQS: _bindgen_ty_2 = 6;
pub type _bindgen_ty_2 = ::std::os::raw::c_uint;
pub const VFIO_CCW_CONFIG_REGION_INDEX: _bindgen_ty_3 = 0;
pub const VFIO_CCW_NUM_REGIONS: _bindgen_ty_3 = 1;

View file

@ -178,6 +178,7 @@ const SSDT_REVISION: u8 = 2;
pub fn create_customize_ssdt(
pci_root: Arc<Mutex<PciRoot>>,
amls: BTreeMap<PciAddress, Vec<u8>>,
gpe_scope_amls: BTreeMap<PciAddress, Vec<u8>>,
) -> Option<SDT> {
if amls.is_empty() {
return None;
@ -198,6 +199,10 @@ pub fn create_customize_ssdt(
}
}
for children in gpe_scope_amls.values() {
ssdt.append_slice(children);
}
Some(ssdt)
}

View file

@ -746,19 +746,20 @@ impl arch::LinuxArch for X8664arch {
.map(|(dev, jail_orig)| (dev.into_pci_device().unwrap(), jail_orig))
.collect();
let (pci, pci_irqs, mut pid_debug_label_map, amls) = arch::generate_pci_root(
pci_devices,
irq_chip.as_irq_chip_mut(),
mmio_bus.clone(),
io_bus.clone(),
system_allocator,
&mut vm,
4, // Share the four pin interrupts (INTx#)
Some(pcie_vcfg_range.start),
#[cfg(feature = "swap")]
swap_controller,
)
.map_err(Error::CreatePciRoot)?;
let (pci, pci_irqs, mut pid_debug_label_map, amls, gpe_scope_amls) =
arch::generate_pci_root(
pci_devices,
irq_chip.as_irq_chip_mut(),
mmio_bus.clone(),
io_bus.clone(),
system_allocator,
&mut vm,
4, // Share the four pin interrupts (INTx#)
Some(pcie_vcfg_range.start),
#[cfg(feature = "swap")]
swap_controller,
)
.map_err(Error::CreatePciRoot)?;
let pci = Arc::new(Mutex::new(pci));
pci.lock().enable_pcie_cfg_mmio(pcie_cfg_mmio_range.start);
@ -896,7 +897,7 @@ impl arch::LinuxArch for X8664arch {
)?;
// Create customized SSDT table
let sdt = acpi::create_customize_ssdt(pci.clone(), amls);
let sdt = acpi::create_customize_ssdt(pci.clone(), amls, gpe_scope_amls);
if let Some(sdt) = sdt {
acpi_dev_resource.sdts.push(sdt);
}

View file

@ -129,7 +129,7 @@ where
let devices = vec![];
let (pci, pci_irqs, _pid_debug_label_map, _amls) = arch::generate_pci_root(
let (pci, pci_irqs, _pid_debug_label_map, _amls, _gpe_scope_amls) = arch::generate_pci_root(
devices,
&mut irq_chip,
mmio_bus.clone(),