Skip to content

Commit a86844e

Browse files
committed
acpi: simplify the construction of VMGenID device
Decouple creation of VMGenID device with writing the generation ID in guest memory. This way we can avoid keeping an `Option<VmGenId>` inside the ACPI device manager. We can always create it and only write the generation ID in guest memory once we are ready to activate the device (when we have a functioning guest memory object). Also, remove a few of the error types and fail in-place instead of propagating errors all the way up. Signed-off-by: Babis Chalios <bchalios@amazon.es>
1 parent d836109 commit a86844e

File tree

6 files changed

+127
-184
lines changed

6 files changed

+127
-184
lines changed

src/vmm/src/builder.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ use crate::device_manager::{
2929
AttachDeviceError, DeviceManager, DeviceManagerCreateError, DevicePersistError,
3030
DeviceRestoreArgs,
3131
};
32-
use crate::devices::acpi::vmgenid::VmGenIdError;
3332
use crate::devices::virtio::balloon::Balloon;
3433
use crate::devices::virtio::block::device::Block;
3534
use crate::devices::virtio::net::Net;
@@ -76,8 +75,6 @@ pub enum StartMicrovmError {
7675
/// Error creating legacy device: {0}
7776
#[cfg(target_arch = "x86_64")]
7877
CreateLegacyDevice(device_manager::legacy::LegacyDeviceError),
79-
/// Error creating VMGenID device: {0}
80-
CreateVMGenID(VmGenIdError),
8178
/// Error enabling PCIe support: {0}
8279
EnablePciDevices(#[from] PciManagerError),
8380
/// Error enabling pvtime on vcpu: {0}
@@ -258,7 +255,7 @@ pub fn build_microvm_for_boot(
258255
vm_resources.serial_out_path.as_ref(),
259256
)?;
260257

261-
device_manager.attach_vmgenid_device(vm.guest_memory(), &vm)?;
258+
device_manager.attach_vmgenid_device(&vm)?;
262259

263260
#[cfg(target_arch = "aarch64")]
264261
if vcpus[0].kvm_vcpu.supports_pvtime() {
@@ -943,10 +940,7 @@ pub(crate) mod tests {
943940

944941
#[cfg(target_arch = "x86_64")]
945942
pub(crate) fn insert_vmgenid_device(vmm: &mut Vmm) {
946-
vmm.device_manager
947-
.attach_vmgenid_device(vmm.vm.guest_memory(), &vmm.vm)
948-
.unwrap();
949-
assert!(vmm.device_manager.acpi_devices.vmgenid.is_some());
943+
vmm.device_manager.attach_vmgenid_device(&vmm.vm).unwrap();
950944
}
951945

952946
pub(crate) fn insert_balloon_device(

src/vmm/src/device_manager/acpi.rs

Lines changed: 56 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -2,84 +2,79 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use acpi_tables::{Aml, aml};
5+
use vm_memory::GuestMemoryError;
56

67
use crate::Vm;
78
use crate::devices::acpi::vmgenid::VmGenId;
9+
use crate::vstate::resources::ResourceAllocator;
810

9-
#[derive(Debug, Default)]
11+
#[derive(Debug, thiserror::Error, displaydoc::Display)]
12+
pub enum ACPIDeviceError {
13+
/// Could not register GSI with KVM: {0}
14+
RegisterIrq(#[from] kvm_ioctls::Error),
15+
/// Could not write to guest memory: {0}
16+
WriteGuestMemory(#[from] GuestMemoryError),
17+
}
18+
19+
#[derive(Debug)]
1020
pub struct ACPIDeviceManager {
1121
/// VMGenID device
12-
pub vmgenid: Option<VmGenId>,
22+
pub vmgenid: VmGenId,
1323
}
1424

1525
impl ACPIDeviceManager {
1626
/// Create a new ACPIDeviceManager object
17-
pub fn new() -> Self {
18-
Default::default()
19-
}
20-
21-
/// Attach a new VMGenID device to the microVM
22-
///
23-
/// This will register the device's interrupt with KVM
24-
pub fn attach_vmgenid(&mut self, vmgenid: VmGenId, vm: &Vm) -> Result<(), kvm_ioctls::Error> {
25-
vm.register_irq(&vmgenid.interrupt_evt, vmgenid.gsi)?;
26-
self.vmgenid = Some(vmgenid);
27-
Ok(())
27+
pub fn new(resource_allocator: &mut ResourceAllocator) -> Self {
28+
let vmgenid = VmGenId::new(resource_allocator);
29+
ACPIDeviceManager { vmgenid }
2830
}
2931

30-
/// If it exists, notify guest VMGenID device that we have resumed from a snapshot.
31-
pub fn notify_vmgenid(&mut self) -> Result<(), std::io::Error> {
32-
if let Some(vmgenid) = &mut self.vmgenid {
33-
vmgenid.notify_guest()?;
34-
}
32+
pub fn attach_vmgenid(&self, vm: &Vm) -> Result<(), ACPIDeviceError> {
33+
vm.register_irq(&self.vmgenid.interrupt_evt, self.vmgenid.gsi)?;
34+
self.vmgenid.activate(vm.guest_memory())?;
3535
Ok(())
3636
}
3737
}
3838

3939
impl Aml for ACPIDeviceManager {
4040
fn append_aml_bytes(&self, v: &mut Vec<u8>) -> Result<(), aml::AmlError> {
41-
// If we have a VMGenID device, create the AML for the device and GED interrupt handler
42-
match self.vmgenid.as_ref() {
43-
Some(vmgenid) => {
44-
// AML for GED
45-
aml::Device::new(
46-
"_SB_.GED_".try_into()?,
47-
vec![
48-
&aml::Name::new("_HID".try_into()?, &"ACPI0013")?,
49-
&aml::Name::new(
50-
"_CRS".try_into()?,
51-
&aml::ResourceTemplate::new(vec![&aml::Interrupt::new(
52-
true,
53-
true,
54-
false,
55-
false,
56-
vmgenid.gsi,
57-
)]),
58-
)?,
59-
&aml::Method::new(
60-
"_EVT".try_into()?,
61-
1,
62-
true,
63-
vec![&aml::If::new(
64-
// We know that the maximum IRQ number fits in a u8. We have up to
65-
// 32 IRQs in x86 and up to 128 in
66-
// ARM (look into
67-
// `vmm::crate::arch::layout::GSI_LEGACY_END`)
68-
#[allow(clippy::cast_possible_truncation)]
69-
&aml::Equal::new(&aml::Arg(0), &(vmgenid.gsi as u8)),
70-
vec![&aml::Notify::new(
71-
&aml::Path::new("\\_SB_.VGEN")?,
72-
&0x80usize,
73-
)],
74-
)],
75-
),
76-
],
77-
)
78-
.append_aml_bytes(v)?;
79-
// AML for VMGenID itself.
80-
vmgenid.append_aml_bytes(v)
81-
}
82-
None => Ok(()),
83-
}
41+
// AML for [`VmGenId`] device.
42+
self.vmgenid.append_aml_bytes(v)?;
43+
44+
// Create the AML for the GED interrupt handler
45+
aml::Device::new(
46+
"_SB_.GED_".try_into()?,
47+
vec![
48+
&aml::Name::new("_HID".try_into()?, &"ACPI0013")?,
49+
&aml::Name::new(
50+
"_CRS".try_into()?,
51+
&aml::ResourceTemplate::new(vec![&aml::Interrupt::new(
52+
true,
53+
true,
54+
false,
55+
false,
56+
self.vmgenid.gsi,
57+
)]),
58+
)?,
59+
&aml::Method::new(
60+
"_EVT".try_into()?,
61+
1,
62+
true,
63+
vec![&aml::If::new(
64+
// We know that the maximum IRQ number fits in a u8. We have up to
65+
// 32 IRQs in x86 and up to 128 in
66+
// ARM (look into
67+
// `vmm::crate::arch::layout::GSI_LEGACY_END`)
68+
#[allow(clippy::cast_possible_truncation)]
69+
&aml::Equal::new(&aml::Arg(0), &(self.vmgenid.gsi as u8)),
70+
vec![&aml::Notify::new(
71+
&aml::Path::new("\\_SB_.VGEN")?,
72+
&0x80usize,
73+
)],
74+
)],
75+
),
76+
],
77+
)
78+
.append_aml_bytes(v)
8479
}
8580
}

src/vmm/src/device_manager/mod.rs

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ use linux_loader::loader::Cmdline;
1818
use log::{error, info};
1919
use mmio::{MMIODeviceManager, MmioError};
2020
use pci_mngr::{PciDevices, PciDevicesConstructorArgs, PciManagerError};
21-
use persist::{ACPIDeviceManagerConstructorArgs, MMIODevManagerConstructorArgs};
21+
use persist::MMIODevManagerConstructorArgs;
2222
use serde::{Deserialize, Serialize};
2323
use utils::time::TimestampUs;
2424
use vmm_sys_util::eventfd::EventFd;
2525

26-
use crate::devices::acpi::vmgenid::{VmGenId, VmGenIdError};
26+
use crate::device_manager::acpi::ACPIDeviceError;
2727
#[cfg(target_arch = "x86_64")]
2828
use crate::devices::legacy::I8042Device;
2929
#[cfg(target_arch = "aarch64")]
@@ -70,10 +70,8 @@ pub enum AttachDeviceError {
7070
MmioTransport(#[from] MmioError),
7171
/// Error inserting device in bus: {0}
7272
Bus(#[from] BusError),
73-
/// Error creating VMGenID device: {0}
74-
CreateVmGenID(#[from] VmGenIdError),
75-
/// Error while registering VMGenID with KVM: {0}
76-
AttachVmGenID(#[from] kvm_ioctls::Error),
73+
/// Error while registering ACPI with KVM: {0}
74+
AttachAcpiDevice(#[from] ACPIDeviceError),
7775
#[cfg(target_arch = "aarch64")]
7876
/// Cmdline error
7977
Cmdline,
@@ -176,7 +174,7 @@ impl DeviceManager {
176174
mmio_devices: MMIODeviceManager::new(),
177175
#[cfg(target_arch = "x86_64")]
178176
legacy_devices,
179-
acpi_devices: ACPIDeviceManager::new(),
177+
acpi_devices: ACPIDeviceManager::new(&mut vm.resource_allocator()),
180178
pci_devices: PciDevices::new(),
181179
})
182180
}
@@ -234,13 +232,8 @@ impl DeviceManager {
234232
Ok(())
235233
}
236234

237-
pub(crate) fn attach_vmgenid_device(
238-
&mut self,
239-
mem: &GuestMemoryMmap,
240-
vm: &Vm,
241-
) -> Result<(), AttachDeviceError> {
242-
let vmgenid = VmGenId::new(mem, &mut vm.resource_allocator())?;
243-
self.acpi_devices.attach_vmgenid(vmgenid, vm)?;
235+
pub(crate) fn attach_vmgenid_device(&mut self, vm: &Vm) -> Result<(), AttachDeviceError> {
236+
self.acpi_devices.attach_vmgenid(vm)?;
244237
Ok(())
245238
}
246239

@@ -394,7 +387,7 @@ pub enum DevicePersistError {
394387
/// Error restoring MMIO devices: {0}
395388
MmioRestore(#[from] persist::DevicePersistError),
396389
/// Error restoring ACPI devices: {0}
397-
AcpiRestore(#[from] persist::ACPIDeviceManagerRestoreError),
390+
AcpiRestore(#[from] ACPIDeviceError),
398391
/// Error restoring PCI devices: {0}
399392
PciRestore(#[from] PciManagerError),
400393
/// Error notifying VMGenID device: {0}
@@ -464,12 +457,8 @@ impl<'a> Persist<'a> for DeviceManager {
464457
let mmio_devices = MMIODeviceManager::restore(mmio_ctor_args, &state.mmio_state)?;
465458

466459
// Restore ACPI devices
467-
let acpi_ctor_args = ACPIDeviceManagerConstructorArgs {
468-
mem: constructor_args.mem,
469-
vm: constructor_args.vm,
470-
};
471-
let mut acpi_devices = ACPIDeviceManager::restore(acpi_ctor_args, &state.acpi_state)?;
472-
acpi_devices.notify_vmgenid()?;
460+
let mut acpi_devices = ACPIDeviceManager::restore(constructor_args.vm, &state.acpi_state)?;
461+
acpi_devices.vmgenid.notify_guest()?;
473462

474463
// Restore PCI devices
475464
let pci_ctor_args = PciDevicesConstructorArgs {
@@ -542,10 +531,12 @@ pub(crate) mod tests {
542531
use super::*;
543532
#[cfg(target_arch = "aarch64")]
544533
use crate::builder::tests::default_vmm;
534+
use crate::vstate::resources::ResourceAllocator;
545535

546536
pub(crate) fn default_device_manager() -> DeviceManager {
537+
let mut resource_allocator = ResourceAllocator::new();
547538
let mmio_devices = MMIODeviceManager::new();
548-
let acpi_devices = ACPIDeviceManager::new();
539+
let acpi_devices = ACPIDeviceManager::new(&mut resource_allocator);
549540
let pci_devices = PciDevices::new();
550541

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

src/vmm/src/device_manager/persist.rs

Lines changed: 14 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use super::acpi::ACPIDeviceManager;
1414
use super::mmio::*;
1515
#[cfg(target_arch = "aarch64")]
1616
use crate::arch::DeviceType;
17-
use crate::devices::acpi::vmgenid::{VMGenIDState, VMGenIdConstructorArgs, VmGenId, VmGenIdError};
17+
use crate::device_manager::acpi::ACPIDeviceError;
18+
use crate::devices::acpi::vmgenid::{VMGenIDState, VmGenId};
1819
#[cfg(target_arch = "aarch64")]
1920
use crate::devices::legacy::RTCDevice;
2021
use crate::devices::virtio::ActivateError;
@@ -156,50 +157,28 @@ impl fmt::Debug for MMIODevManagerConstructorArgs<'_> {
156157

157158
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
158159
pub struct ACPIDeviceManagerState {
159-
vmgenid: Option<VMGenIDState>,
160-
}
161-
162-
#[derive(Debug)]
163-
pub struct ACPIDeviceManagerConstructorArgs<'a> {
164-
pub mem: &'a GuestMemoryMmap,
165-
pub vm: &'a Vm,
166-
}
167-
168-
#[derive(Debug, thiserror::Error, displaydoc::Display)]
169-
pub enum ACPIDeviceManagerRestoreError {
170-
/// Could not register device: {0}
171-
Interrupt(#[from] kvm_ioctls::Error),
172-
/// Could not create VMGenID device: {0}
173-
VMGenID(#[from] VmGenIdError),
160+
vmgenid: VMGenIDState,
174161
}
175162

176163
impl<'a> Persist<'a> for ACPIDeviceManager {
177164
type State = ACPIDeviceManagerState;
178-
type ConstructorArgs = ACPIDeviceManagerConstructorArgs<'a>;
179-
type Error = ACPIDeviceManagerRestoreError;
165+
type ConstructorArgs = &'a Vm;
166+
type Error = ACPIDeviceError;
180167

181168
fn save(&self) -> Self::State {
182169
ACPIDeviceManagerState {
183-
vmgenid: self.vmgenid.as_ref().map(|dev| dev.save()),
170+
vmgenid: self.vmgenid.save(),
184171
}
185172
}
186173

187-
fn restore(
188-
constructor_args: Self::ConstructorArgs,
189-
state: &Self::State,
190-
) -> Result<Self, Self::Error> {
191-
let mut dev_manager = ACPIDeviceManager::new();
192-
if let Some(vmgenid_args) = &state.vmgenid {
193-
let vmgenid = VmGenId::restore(
194-
VMGenIdConstructorArgs {
195-
mem: constructor_args.mem,
196-
resource_allocator: &mut constructor_args.vm.resource_allocator(),
197-
},
198-
vmgenid_args,
199-
)?;
200-
dev_manager.attach_vmgenid(vmgenid, constructor_args.vm)?;
201-
}
202-
Ok(dev_manager)
174+
fn restore(vm: Self::ConstructorArgs, state: &Self::State) -> Result<Self, Self::Error> {
175+
let acpi_devices = ACPIDeviceManager {
176+
// This can't fail
177+
vmgenid: VmGenId::restore(vm.guest_memory(), &state.vmgenid).unwrap(),
178+
};
179+
180+
acpi_devices.attach_vmgenid(vm)?;
181+
Ok(acpi_devices)
203182
}
204183
}
205184

0 commit comments

Comments
 (0)