Skip to content

Commit d0c14df

Browse files
committed
fix(acpi): Instantiate ACPI devices when attached
Since ACPI devices (i.e. VMGenID and VMClock) are always present, we avoided wrapping them with Option [1]. However, the refactoring changed the order of GSI allocation (i.e. ACPI devices come before virtio devices), which caused performance regression for some reasons. Although we need to dive deep into why it affected performance, we should keep the existing order until we find out the root cause. [1]: a52d58d Signed-off-by: Takahiro Itazuri <itazur@amazon.com>
1 parent b2bdff5 commit d0c14df

4 files changed

Lines changed: 69 additions & 32 deletions

File tree

src/vmm/src/arch/aarch64/fdt.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ pub fn create_fdt(
9797
create_clock_node(&mut fdt_writer)?;
9898
create_psci_node(&mut fdt_writer)?;
9999
create_devices_node(&mut fdt_writer, device_manager)?;
100-
create_vmgenid_node(&mut fdt_writer, &device_manager.acpi_devices.vmgenid)?;
101-
create_vmclock_node(&mut fdt_writer, &device_manager.acpi_devices.vmclock)?;
100+
create_vmgenid_node(&mut fdt_writer, device_manager.acpi_devices.vmgenid())?;
101+
create_vmclock_node(&mut fdt_writer, device_manager.acpi_devices.vmclock())?;
102102
create_pci_nodes(&mut fdt_writer, &device_manager.pci_devices)?;
103103

104104
// End Header node.

src/vmm/src/device_manager/acpi.rs

Lines changed: 48 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use vm_memory::GuestMemoryError;
88
use crate::Vm;
99
use crate::devices::acpi::vmclock::VmClock;
1010
use crate::devices::acpi::vmgenid::VmGenId;
11-
use crate::vstate::resources::ResourceAllocator;
11+
use crate::vstate::memory::GuestMemoryMmap;
1212

1313
#[derive(Debug, thiserror::Error, displaydoc::Display)]
1414
pub enum ACPIDeviceError {
@@ -23,40 +23,70 @@ pub enum ACPIDeviceError {
2323
#[derive(Debug)]
2424
pub struct ACPIDeviceManager {
2525
/// VMGenID device
26-
pub vmgenid: VmGenId,
26+
pub vmgenid: Option<VmGenId>,
2727
/// VMclock device
28-
pub vmclock: VmClock,
28+
pub vmclock: Option<VmClock>,
2929
}
3030

3131
impl ACPIDeviceManager {
3232
/// Create a new ACPIDeviceManager object
33-
pub fn new(resource_allocator: &mut ResourceAllocator) -> Self {
33+
pub fn new() -> Self {
34+
// Although both VMGenID and VMClock devices are always present, they should be instantiated
35+
// when they are attached to preserve the existing ordering of GSI allocation.
3436
ACPIDeviceManager {
35-
vmgenid: VmGenId::new(resource_allocator),
36-
vmclock: VmClock::new(resource_allocator),
37+
vmgenid: None,
38+
vmclock: None,
3739
}
3840
}
3941

40-
pub fn attach_vmgenid(&self, vm: &Vm) -> Result<(), ACPIDeviceError> {
41-
vm.register_irq(&self.vmgenid.interrupt_evt, self.vmgenid.gsi)?;
42-
self.vmgenid.activate(vm.guest_memory())?;
42+
pub fn attach_vmgenid(&mut self, vm: &Vm) {
43+
self.vmgenid = Some(VmGenId::new(&mut vm.resource_allocator()));
44+
}
45+
46+
pub fn attach_vmclock(&mut self, vm: &Vm) {
47+
self.vmclock = Some(VmClock::new(&mut vm.resource_allocator()));
48+
}
49+
50+
pub fn vmgenid(&self) -> &VmGenId {
51+
self.vmgenid.as_ref().expect("Missing VMGenID device")
52+
}
53+
54+
pub fn vmclock(&self) -> &VmClock {
55+
self.vmclock.as_ref().expect("Missing VMClock device")
56+
}
57+
58+
pub fn activate_vmgenid(&self, vm: &Vm) -> Result<(), ACPIDeviceError> {
59+
vm.register_irq(&self.vmgenid().interrupt_evt, self.vmgenid().gsi)?;
60+
self.vmgenid().activate(vm.guest_memory())?;
61+
Ok(())
62+
}
63+
64+
pub fn activate_vmclock(&self, vm: &Vm) -> Result<(), ACPIDeviceError> {
65+
vm.register_irq(&self.vmclock().interrupt_evt, self.vmclock().gsi)?;
66+
self.vmclock().activate(vm.guest_memory())?;
4367
Ok(())
4468
}
4569

46-
pub fn attach_vmclock(&self, vm: &Vm) -> Result<(), ACPIDeviceError> {
47-
vm.register_irq(&self.vmclock.interrupt_evt, self.vmclock.gsi)?;
48-
self.vmclock.activate(vm.guest_memory())?;
70+
pub fn do_post_restore_vmgenid(&self) -> Result<(), ACPIDeviceError> {
71+
self.vmgenid().do_post_restore()?;
4972
Ok(())
5073
}
74+
75+
pub fn do_post_restore_vmclock(&mut self, mem: &GuestMemoryMmap) {
76+
self.vmclock
77+
.as_mut()
78+
.expect("Missing VMClock device")
79+
.do_post_restore(mem);
80+
}
5181
}
5282

5383
#[cfg(target_arch = "x86_64")]
5484
impl Aml for ACPIDeviceManager {
5585
fn append_aml_bytes(&self, v: &mut Vec<u8>) -> Result<(), aml::AmlError> {
5686
// AML for [`VmGenId`] device.
57-
self.vmgenid.append_aml_bytes(v)?;
87+
self.vmgenid().append_aml_bytes(v)?;
5888
// AML for [`VmClock`] device.
59-
self.vmclock.append_aml_bytes(v)?;
89+
self.vmclock().append_aml_bytes(v)?;
6090

6191
// Create the AML for the GED interrupt handler
6292
aml::Device::new(
@@ -66,8 +96,8 @@ impl Aml for ACPIDeviceManager {
6696
&aml::Name::new(
6797
"_CRS".try_into()?,
6898
&aml::ResourceTemplate::new(vec![
69-
&aml::Interrupt::new(true, true, false, false, self.vmgenid.gsi),
70-
&aml::Interrupt::new(true, true, false, false, self.vmclock.gsi),
99+
&aml::Interrupt::new(true, true, false, false, self.vmgenid().gsi),
100+
&aml::Interrupt::new(true, true, false, false, self.vmclock().gsi),
71101
]),
72102
)?,
73103
// We know that the maximum IRQ number fits in a u8. We have up to
@@ -81,15 +111,15 @@ impl Aml for ACPIDeviceManager {
81111
vec![
82112
&aml::If::new(
83113
#[allow(clippy::cast_possible_truncation)]
84-
&aml::Equal::new(&aml::Arg(0), &(self.vmgenid.gsi as u8)),
114+
&aml::Equal::new(&aml::Arg(0), &(self.vmgenid().gsi as u8)),
85115
vec![&aml::Notify::new(
86116
&aml::Path::new("\\_SB_.VGEN")?,
87117
&0x80usize,
88118
)],
89119
),
90120
&aml::If::new(
91121
#[allow(clippy::cast_possible_truncation)]
92-
&aml::Equal::new(&aml::Arg(0), &(self.vmclock.gsi as u8)),
122+
&aml::Equal::new(&aml::Arg(0), &(self.vmclock().gsi as u8)),
93123
vec![&aml::Notify::new(
94124
&aml::Path::new("\\_SB_.VCLK")?,
95125
&0x80usize,

src/vmm/src/device_manager/mod.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ impl DeviceManager {
174174
mmio_devices: MMIODeviceManager::new(),
175175
#[cfg(target_arch = "x86_64")]
176176
legacy_devices,
177-
acpi_devices: ACPIDeviceManager::new(&mut vm.resource_allocator()),
177+
acpi_devices: ACPIDeviceManager::new(),
178178
pci_devices: PciDevices::new(),
179179
})
180180
}
@@ -233,12 +233,14 @@ impl DeviceManager {
233233
}
234234

235235
pub(crate) fn attach_vmgenid_device(&mut self, vm: &Vm) -> Result<(), AttachDeviceError> {
236-
self.acpi_devices.attach_vmgenid(vm)?;
236+
self.acpi_devices.attach_vmgenid(vm);
237+
self.acpi_devices.activate_vmgenid(vm)?;
237238
Ok(())
238239
}
239240

240241
pub(crate) fn attach_vmclock_device(&mut self, vm: &Vm) -> Result<(), AttachDeviceError> {
241-
self.acpi_devices.attach_vmclock(vm)?;
242+
self.acpi_devices.attach_vmclock(vm);
243+
self.acpi_devices.activate_vmclock(vm)?;
242244
Ok(())
243245
}
244246

@@ -550,12 +552,17 @@ pub(crate) mod tests {
550552
use super::*;
551553
#[cfg(target_arch = "aarch64")]
552554
use crate::builder::tests::default_vmm;
555+
use crate::devices::acpi::vmclock::VmClock;
556+
use crate::devices::acpi::vmgenid::VmGenId;
553557
use crate::vstate::resources::ResourceAllocator;
554558

555559
pub(crate) fn default_device_manager() -> DeviceManager {
556560
let mut resource_allocator = ResourceAllocator::new();
557561
let mmio_devices = MMIODeviceManager::new();
558-
let acpi_devices = ACPIDeviceManager::new(&mut resource_allocator);
562+
let acpi_devices = ACPIDeviceManager {
563+
vmgenid: Some(VmGenId::new(&mut resource_allocator)),
564+
vmclock: Some(VmClock::new(&mut resource_allocator)),
565+
};
559566
let pci_devices = PciDevices::new();
560567

561568
#[cfg(target_arch = "x86_64")]

src/vmm/src/device_manager/persist.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,24 +177,24 @@ impl<'a> Persist<'a> for ACPIDeviceManager {
177177

178178
fn save(&self) -> Self::State {
179179
ACPIDeviceManagerState {
180-
vmgenid: self.vmgenid.save(),
181-
vmclock: self.vmclock.save(),
180+
vmgenid: self.vmgenid().save(),
181+
vmclock: self.vmclock().save(),
182182
}
183183
}
184184

185185
fn restore(vm: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
186186
let mut acpi_devices = ACPIDeviceManager {
187187
// Safe to unwrap() here, this will never return an error.
188-
vmgenid: VmGenId::restore((), &state.vmgenid).unwrap(),
188+
vmgenid: Some(VmGenId::restore((), &state.vmgenid).unwrap()),
189189
// Safe to unwrap() here, this will never return an error.
190-
vmclock: VmClock::restore((), &state.vmclock).unwrap(),
190+
vmclock: Some(VmClock::restore((), &state.vmclock).unwrap()),
191191
};
192192

193-
acpi_devices.attach_vmgenid(vm)?;
194-
acpi_devices.vmgenid.do_post_restore()?;
193+
acpi_devices.activate_vmgenid(vm)?;
194+
acpi_devices.do_post_restore_vmgenid()?;
195195

196-
acpi_devices.attach_vmclock(vm)?;
197-
acpi_devices.vmclock.do_post_restore(vm.guest_memory());
196+
acpi_devices.activate_vmclock(vm)?;
197+
acpi_devices.do_post_restore_vmclock(vm.guest_memory());
198198

199199
Ok(acpi_devices)
200200
}

0 commit comments

Comments
 (0)