Skip to content

Commit 335a641

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. On the Aarch64, we need to recreate the expected dtb files because default microVMs always create entries for the VMGenID device. Signed-off-by: Babis Chalios <bchalios@amazon.es>
1 parent f6c7100 commit 335a641

File tree

9 files changed

+136
-218
lines changed

9 files changed

+136
-218
lines changed

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

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -275,17 +275,15 @@ fn create_chosen_node(
275275
Ok(())
276276
}
277277

278-
fn create_vmgenid_node(fdt: &mut FdtWriter, vmgenid: &Option<VmGenId>) -> Result<(), FdtError> {
279-
if let Some(vmgenid_info) = vmgenid {
280-
let vmgenid = fdt.begin_node("vmgenid")?;
281-
fdt.property_string("compatible", "microsoft,vmgenid")?;
282-
fdt.property_array_u64("reg", &[vmgenid_info.guest_address.0, VMGENID_MEM_SIZE])?;
283-
fdt.property_array_u32(
284-
"interrupts",
285-
&[GIC_FDT_IRQ_TYPE_SPI, vmgenid_info.gsi, IRQ_TYPE_EDGE_RISING],
286-
)?;
287-
fdt.end_node(vmgenid)?;
288-
}
278+
fn create_vmgenid_node(fdt: &mut FdtWriter, vmgenid: &VmGenId) -> Result<(), FdtError> {
279+
let vmgenid_node = fdt.begin_node("vmgenid")?;
280+
fdt.property_string("compatible", "microsoft,vmgenid")?;
281+
fdt.property_array_u64("reg", &[vmgenid.guest_address.0, VMGENID_MEM_SIZE])?;
282+
fdt.property_array_u32(
283+
"interrupts",
284+
&[GIC_FDT_IRQ_TYPE_SPI, vmgenid.gsi, IRQ_TYPE_EDGE_RISING],
285+
)?;
286+
fdt.end_node(vmgenid_node)?;
289287
Ok(())
290288
}
291289

@@ -586,29 +584,6 @@ mod tests {
586584
.unwrap();
587585
}
588586

589-
#[test]
590-
fn test_create_fdt_with_vmgenid() {
591-
let mem = arch_mem(layout::FDT_MAX_SIZE + 0x1000);
592-
let mut device_manager = default_device_manager();
593-
let kvm = Kvm::new(vec![]).unwrap();
594-
let vm = Vm::new(&kvm).unwrap();
595-
let gic = create_gic(vm.fd(), 1, None).unwrap();
596-
let mut cmdline = kernel_cmdline::Cmdline::new(4096).unwrap();
597-
cmdline.insert("console", "/dev/tty0").unwrap();
598-
599-
device_manager.attach_vmgenid_device(&mem, &vm).unwrap();
600-
601-
create_fdt(
602-
&mem,
603-
vec![0],
604-
CString::new("console=tty0").unwrap(),
605-
&device_manager,
606-
&gic,
607-
&None,
608-
)
609-
.unwrap();
610-
}
611-
612587
#[test]
613588
fn test_create_fdt() {
614589
let mem = arch_mem(layout::FDT_MAX_SIZE + 0x1000);
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

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)