Skip to content

Commit 5cde506

Browse files
Sudan Landgebchalios
authored andcommitted
vmgenid: add support for ARM systems
Expose the VMGenID device via Device Tree bindings. We add a node in the Device Tree that passes to the guest the address of the generation ID and the interrupt we are using to notify it about generation changes, aka snapshot events. Signed-off-by: Sudan Landge <[email protected]> Signed-off-by: Babis Chalios <[email protected]>
1 parent 654f72a commit 5cde506

File tree

11 files changed

+77
-45
lines changed

11 files changed

+77
-45
lines changed

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

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use super::super::{DeviceType, InitrdConfig};
1616
use super::cache_info::{read_cache_config, CacheEntry};
1717
use super::get_fdt_addr;
1818
use super::gic::GICDevice;
19+
use crate::devices::acpi::vmgenid::{VmGenId, VMGENID_MEM_SIZE};
1920
use crate::vstate::memory::{Address, Bytes, GuestAddress, GuestMemory, GuestMemoryMmap};
2021

2122
// This is a value for uniquely identifying the FDT node declaring the interrupt controller.
@@ -25,7 +26,7 @@ const CLOCK_PHANDLE: u32 = 2;
2526
// You may be wondering why this big value?
2627
// This phandle is used to uniquely identify the FDT nodes containing cache information. Each cpu
2728
// can have a variable number of caches, some of these caches may be shared with other cpus.
28-
// So, we start the indexing of the phandles used from a really big number and then substract from
29+
// So, we start the indexing of the phandles used from a really big number and then subtract from
2930
// it as we need more and more phandle for each cache representation.
3031
const LAST_CACHE_PHANDLE: u32 = 4000;
3132
// Read the documentation specified when appending the root node to the FDT.
@@ -70,6 +71,7 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug, S: std::hash::BuildHasher
7071
cmdline: CString,
7172
device_info: &HashMap<(DeviceType, String), T, S>,
7273
gic_device: &GICDevice,
74+
vmgenid: &Option<VmGenId>,
7375
initrd: &Option<InitrdConfig>,
7476
) -> Result<Vec<u8>, FdtError> {
7577
// Allocate stuff necessary for storing the blob.
@@ -97,6 +99,7 @@ pub fn create_fdt<T: DeviceInfoForFDT + Clone + Debug, S: std::hash::BuildHasher
9799
create_clock_node(&mut fdt_writer)?;
98100
create_psci_node(&mut fdt_writer)?;
99101
create_devices_node(&mut fdt_writer, device_info)?;
102+
create_vmgenid_node(&mut fdt_writer, vmgenid)?;
100103

101104
// End Header node.
102105
fdt_writer.end_node(root)?;
@@ -219,12 +222,26 @@ fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> Result<(), FdtEr
219222
}
220223

221224
fn create_memory_node(fdt: &mut FdtWriter, guest_mem: &GuestMemoryMmap) -> Result<(), FdtError> {
222-
let mem_size = guest_mem.last_addr().raw_value() - super::layout::DRAM_MEM_START + 1;
223225
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/booting-without-of.txt#L960
224226
// for an explanation of this.
225-
let mem_reg_prop = &[super::layout::DRAM_MEM_START, mem_size];
226227

227-
let mem = fdt.begin_node("memory")?;
228+
// On ARM we reserve some memory so that it can be utilized for devices like VMGenID to send
229+
// data to kernel drivers. The range of this memory is:
230+
//
231+
// [layout::DRAM_MEM_START, layout::DRAM_MEM_START + layout::SYSTEM_MEM_SIZE)
232+
//
233+
// The reason we do this is that Linux does not allow remapping system memory. However, without
234+
// remap, kernel drivers cannot get virtual addresses to read data from device memory. Leaving
235+
// this memory region out allows Linux kernel modules to remap and thus read this region.
236+
let mem_size = guest_mem.last_addr().raw_value()
237+
- super::layout::DRAM_MEM_START
238+
- super::layout::SYSTEM_MEM_SIZE
239+
+ 1;
240+
let mem_reg_prop = &[
241+
super::layout::DRAM_MEM_START + super::layout::SYSTEM_MEM_SIZE,
242+
mem_size,
243+
];
244+
let mem = fdt.begin_node("memory@ram")?;
228245
fdt.property_string("device_type", "memory")?;
229246
fdt.property_array_u64("reg", mem_reg_prop)?;
230247
fdt.end_node(mem)?;
@@ -258,6 +275,20 @@ fn create_chosen_node(
258275
Ok(())
259276
}
260277

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+
}
289+
Ok(())
290+
}
291+
261292
fn create_gic_node(fdt: &mut FdtWriter, gic_device: &GICDevice) -> Result<(), FdtError> {
262293
let interrupt = fdt.begin_node("intc")?;
263294
fdt.property_string("compatible", gic_device.fdt_compatibility())?;
@@ -428,6 +459,7 @@ mod tests {
428459
use super::*;
429460
use crate::arch::aarch64::gic::create_gic;
430461
use crate::arch::aarch64::layout;
462+
use crate::device_manager::resources::ResourceAllocator;
431463
use crate::utilities::test_utils::arch_mem;
432464

433465
const LEN: u64 = 4096;
@@ -492,6 +524,27 @@ mod tests {
492524
&dev_info,
493525
&gic,
494526
&None,
527+
&None,
528+
)
529+
.unwrap();
530+
}
531+
532+
#[test]
533+
fn test_create_fdt_with_vmgenid() {
534+
let mem = arch_mem(layout::FDT_MAX_SIZE + 0x1000);
535+
let mut resource_allocator = ResourceAllocator::new().unwrap();
536+
let vmgenid = VmGenId::new(&mem, &mut resource_allocator).unwrap();
537+
let kvm = Kvm::new().unwrap();
538+
let vm = kvm.create_vm().unwrap();
539+
let gic = create_gic(&vm, 1, None).unwrap();
540+
create_fdt(
541+
&mem,
542+
vec![0],
543+
CString::new("console=tty0").unwrap(),
544+
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
545+
&gic,
546+
&Some(vmgenid),
547+
&None,
495548
)
496549
.unwrap();
497550
}
@@ -516,6 +569,7 @@ mod tests {
516569
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
517570
&gic,
518571
&None,
572+
&None,
519573
)
520574
.unwrap();
521575

@@ -576,6 +630,7 @@ mod tests {
576630
CString::new("console=tty0").unwrap(),
577631
&HashMap::<(DeviceType, std::string::String), MMIODeviceInfo>::new(),
578632
&gic,
633+
&None,
579634
&Some(initrd),
580635
)
581636
.unwrap();

src/vmm/src/arch/aarch64/layout.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ pub const DRAM_MEM_START: u64 = 0x8000_0000; // 2 GB.
5454
/// The maximum RAM size.
5555
pub const DRAM_MEM_MAX_SIZE: usize = 0x00FF_8000_0000; // 1024 - 2 = 1022G.
5656

57+
/// Start of RAM on 64 bit ARM.
58+
pub const SYSTEM_MEM_START: u64 = DRAM_MEM_START;
59+
60+
/// This is used by ACPI device manager for acpi tables or devices like vmgenid
61+
/// In reality, 2MBs is an overkill, but immediately after this we write the kernel
62+
/// image, which needs to be 2MB aligned.
63+
pub const SYSTEM_MEM_SIZE: u64 = 0x20_0000;
64+
5765
/// Kernel command line maximum size.
5866
/// As per `arch/arm64/include/uapi/asm/setup.h`.
5967
pub const CMDLINE_MAX_SIZE: usize = 2048;

src/vmm/src/arch/aarch64/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use std::fmt::Debug;
2020
pub use self::fdt::DeviceInfoForFDT;
2121
use self::gic::GICDevice;
2222
use crate::arch::DeviceType;
23+
use crate::devices::acpi::vmgenid::VmGenId;
2324
use crate::vstate::memory::{Address, GuestAddress, GuestMemory, GuestMemoryMmap};
2425

2526
/// Errors thrown while configuring aarch64 system.
@@ -60,6 +61,7 @@ pub fn configure_system<T: DeviceInfoForFDT + Clone + Debug, S: std::hash::Build
6061
vcpu_mpidr: Vec<u64>,
6162
device_info: &HashMap<(DeviceType, String), T, S>,
6263
gic_device: &GICDevice,
64+
vmgenid: &Option<VmGenId>,
6365
initrd: &Option<super::InitrdConfig>,
6466
) -> Result<(), ConfigurationError> {
6567
fdt::create_fdt(
@@ -68,14 +70,15 @@ pub fn configure_system<T: DeviceInfoForFDT + Clone + Debug, S: std::hash::Build
6870
cmdline_cstring,
6971
device_info,
7072
gic_device,
73+
vmgenid,
7174
initrd,
7275
)?;
7376
Ok(())
7477
}
7578

7679
/// Returns the memory address where the kernel could be loaded.
7780
pub fn get_kernel_start() -> u64 {
78-
layout::DRAM_MEM_START
81+
layout::SYSTEM_MEM_START + layout::SYSTEM_MEM_SIZE
7982
}
8083

8184
/// Returns the memory address where the initrd could be loaded.

src/vmm/src/arch/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ pub mod aarch64;
1212
#[cfg(target_arch = "aarch64")]
1313
pub use aarch64::{
1414
arch_memory_regions, configure_system, get_kernel_start, initrd_load_addr,
15-
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, ConfigurationError, MMIO_MEM_SIZE,
16-
MMIO_MEM_START,
15+
layout::CMDLINE_MAX_SIZE, layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE,
16+
layout::SYSTEM_MEM_START, ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START,
1717
};
1818

1919
/// Module for x86_64 related functionality.

src/vmm/src/builder.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,14 @@ use crate::cpu_config::templates::{
3636
CpuConfiguration, CustomCpuTemplate, GetCpuTemplate, GetCpuTemplateError, GuestConfigError,
3737
KvmCapability,
3838
};
39-
#[cfg(target_arch = "x86_64")]
4039
use crate::device_manager::acpi::ACPIDeviceManager;
4140
#[cfg(target_arch = "x86_64")]
4241
use crate::device_manager::legacy::PortIODeviceManager;
4342
use crate::device_manager::mmio::MMIODeviceManager;
44-
use crate::device_manager::persist::MMIODevManagerConstructorArgs;
45-
#[cfg(target_arch = "x86_64")]
4643
use crate::device_manager::persist::{
47-
ACPIDeviceManagerConstructorArgs, ACPIDeviceManagerRestoreError,
44+
ACPIDeviceManagerConstructorArgs, ACPIDeviceManagerRestoreError, MMIODevManagerConstructorArgs,
4845
};
4946
use crate::device_manager::resources::ResourceAllocator;
50-
#[cfg(target_arch = "x86_64")]
5147
use crate::devices::acpi::vmgenid::{VmGenId, VmGenIdError};
5248
use crate::devices::legacy::serial::SerialOut;
5349
#[cfg(target_arch = "aarch64")]
@@ -79,7 +75,6 @@ pub enum StartMicrovmError {
7975
/// Unable to attach block device to Vmm: {0}
8076
AttachBlockDevice(io::Error),
8177
/// Unable to attach the VMGenID device: {0}
82-
#[cfg(target_arch = "x86_64")]
8378
AttachVmgenidDevice(kvm_ioctls::Error),
8479
/// System configuration error: {0}
8580
ConfigureSystem(crate::arch::ConfigurationError),
@@ -93,7 +88,6 @@ pub enum StartMicrovmError {
9388
#[cfg(target_arch = "x86_64")]
9489
CreateLegacyDevice(device_manager::legacy::LegacyDeviceError),
9590
/// Error creating VMGenID device: {0}
96-
#[cfg(target_arch = "x86_64")]
9791
CreateVMGenID(VmGenIdError),
9892
/// Invalid Memory Configuration: {0}
9993
GuestMemory(crate::vstate::memory::MemoryError),
@@ -175,7 +169,6 @@ fn create_vmm_and_vcpus(
175169
let mmio_device_manager = MMIODeviceManager::new();
176170

177171
// Instantiate ACPI device manager.
178-
#[cfg(target_arch = "x86_64")]
179172
let acpi_device_manager = ACPIDeviceManager::new();
180173

181174
// For x86_64 we need to create the interrupt controller before calling `KVM_CREATE_VCPUS`
@@ -233,7 +226,6 @@ fn create_vmm_and_vcpus(
233226
mmio_device_manager,
234227
#[cfg(target_arch = "x86_64")]
235228
pio_device_manager,
236-
#[cfg(target_arch = "x86_64")]
237229
acpi_device_manager,
238230
};
239231

@@ -347,7 +339,6 @@ pub fn build_microvm_for_boot(
347339
#[cfg(target_arch = "aarch64")]
348340
attach_legacy_devices_aarch64(event_manager, &mut vmm, &mut boot_cmdline).map_err(Internal)?;
349341

350-
#[cfg(target_arch = "x86_64")]
351342
attach_vmgenid_device(&mut vmm)?;
352343

353344
configure_system_for_boot(
@@ -449,7 +440,6 @@ pub enum BuildMicrovmFromSnapshotError {
449440
/// Failed to apply VMM secccomp filter: {0}
450441
SeccompFiltersInternal(#[from] seccompiler::InstallationError),
451442
/// Failed to restore ACPI device manager: {0}
452-
#[cfg(target_arch = "x86_64")]
453443
ACPIDeviManager(#[from] ACPIDeviceManagerRestoreError),
454444
/// VMGenID update failed: {0}
455445
VMGenIDUpdate(std::io::Error),
@@ -532,7 +522,6 @@ pub fn build_microvm_from_snapshot(
532522
.map_err(MicrovmStateError::RestoreDevices)?;
533523
vmm.emulate_serial_init()?;
534524

535-
#[cfg(target_arch = "x86_64")]
536525
{
537526
let acpi_ctor_args = ACPIDeviceManagerConstructorArgs {
538527
mem: &guest_memory,
@@ -859,6 +848,7 @@ pub fn configure_system_for_boot(
859848
vcpu_mpidr,
860849
vmm.mmio_device_manager.get_device_info(),
861850
vmm.vm.get_irqchip(),
851+
&vmm.acpi_device_manager.vmgenid,
862852
initrd,
863853
)
864854
.map_err(ConfigureSystem)?;
@@ -908,7 +898,6 @@ pub(crate) fn attach_boot_timer_device(
908898
Ok(())
909899
}
910900

911-
#[cfg(target_arch = "x86_64")]
912901
fn attach_vmgenid_device(vmm: &mut Vmm) -> Result<(), StartMicrovmError> {
913902
let vmgenid = VmGenId::new(&vmm.guest_memory, &mut vmm.resource_allocator)
914903
.map_err(StartMicrovmError::CreateVMGenID)?;
@@ -1117,7 +1106,6 @@ pub mod tests {
11171106
let mut vm = Vm::new(vec![]).unwrap();
11181107
vm.memory_init(&guest_memory, false).unwrap();
11191108
let mmio_device_manager = MMIODeviceManager::new();
1120-
#[cfg(target_arch = "x86_64")]
11211109
let acpi_device_manager = ACPIDeviceManager::new();
11221110
#[cfg(target_arch = "x86_64")]
11231111
let pio_device_manager = PortIODeviceManager::new(
@@ -1158,7 +1146,6 @@ pub mod tests {
11581146
mmio_device_manager,
11591147
#[cfg(target_arch = "x86_64")]
11601148
pio_device_manager,
1161-
#[cfg(target_arch = "x86_64")]
11621149
acpi_device_manager,
11631150
}
11641151
}

src/vmm/src/device_manager/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
// found in the THIRD-PARTY file.
77

88
/// ACPI device manager.
9-
#[cfg(target_arch = "x86_64")]
109
pub mod acpi;
1110
/// Legacy Device Manager.
1211
pub mod legacy;

src/vmm/src/device_manager/persist.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ use log::{error, warn};
1212
use serde::{Deserialize, Serialize};
1313
use vm_allocator::AllocPolicy;
1414

15-
#[cfg(target_arch = "x86_64")]
1615
use super::acpi::ACPIDeviceManager;
1716
use super::mmio::*;
1817
use super::resources::ResourceAllocator;
1918
#[cfg(target_arch = "aarch64")]
2019
use crate::arch::DeviceType;
21-
#[cfg(target_arch = "x86_64")]
2220
use crate::devices::acpi::vmgenid::{VMGenIDState, VMGenIdConstructorArgs, VmGenId, VmGenIdError};
2321
use crate::devices::virtio::balloon::persist::{BalloonConstructorArgs, BalloonState};
2422
use crate::devices::virtio::balloon::{Balloon, BalloonError};
@@ -230,20 +228,17 @@ impl fmt::Debug for MMIODevManagerConstructorArgs<'_> {
230228
}
231229
}
232230

233-
#[cfg(target_arch = "x86_64")]
234231
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
235232
pub struct ACPIDeviceManagerState {
236233
vmgenid: Option<VMGenIDState>,
237234
}
238235

239-
#[cfg(target_arch = "x86_64")]
240236
pub struct ACPIDeviceManagerConstructorArgs<'a> {
241237
pub mem: &'a GuestMemoryMmap,
242238
pub resource_allocator: &'a mut ResourceAllocator,
243239
pub vm: &'a VmFd,
244240
}
245241

246-
#[cfg(target_arch = "x86_64")]
247242
#[derive(Debug, thiserror::Error, displaydoc::Display)]
248243
pub enum ACPIDeviceManagerRestoreError {
249244
/// Could not register device: {0}
@@ -252,7 +247,6 @@ pub enum ACPIDeviceManagerRestoreError {
252247
VMGenID(#[from] VmGenIdError),
253248
}
254249

255-
#[cfg(target_arch = "x86_64")]
256250
impl<'a> Persist<'a> for ACPIDeviceManager {
257251
type State = ACPIDeviceManagerState;
258252
type ConstructorArgs = ACPIDeviceManagerConstructorArgs<'a>;

src/vmm/src/device_manager/resources.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ pub struct ResourceAllocator {
2020
// Allocator for memory in the MMIO address space
2121
mmio_memory: AddressAllocator,
2222
// Memory allocator for system data
23-
#[cfg(target_arch = "x86_64")]
2423
system_memory: AddressAllocator,
2524
}
2625

@@ -30,7 +29,6 @@ impl ResourceAllocator {
3029
Ok(Self {
3130
gsi_allocator: IdAllocator::new(arch::IRQ_BASE, arch::IRQ_MAX)?,
3231
mmio_memory: AddressAllocator::new(arch::MMIO_MEM_START, arch::MMIO_MEM_SIZE)?,
33-
#[cfg(target_arch = "x86_64")]
3432
system_memory: AddressAllocator::new(arch::SYSTEM_MEM_START, arch::SYSTEM_MEM_SIZE)?,
3533
})
3634
}
@@ -86,7 +84,6 @@ impl ResourceAllocator {
8684
/// * `size` - The size in bytes of the memory to allocate
8785
/// * `alignment` - The alignment of the address of the first byte
8886
/// * `policy` - A [`vm_allocator::AllocPolicy`] variant for determining the allocation policy
89-
#[cfg(target_arch = "x86_64")]
9087
pub fn allocate_system_memory(
9188
&mut self,
9289
size: u64,

src/vmm/src/devices/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
1010
use std::io;
1111

12-
#[cfg(target_arch = "x86_64")]
1312
pub mod acpi;
1413
pub mod bus;
1514
pub mod legacy;

0 commit comments

Comments
 (0)