mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: refactor VM initialization into modular helper methods
Decompose the monolithic `new_from_memory_manager` function into smaller, focused helper methods to improve code readability, maintainability, and testability. Changes: - Extract `should_force_iommu()` to determine IOMMU requirements for confidential computing (TDX/SEV-SNP) - Extract `should_stop_on_boot()` to check debug pause configuration - Extract `create_cpu_manager()` to encapsulate CPU manager creation and CPUID population - Extract `init_tdx_if_enabled()` for TDX-specific VM initialization - Extract `create_device_manager()` to encapsulate device manager setup - Extract `hypervisor_specific_init()` to orchestrate initialization sequences for different hypervisors (KVM, MSHV, SEV-SNP) - Extract `init_sev_snp()` for SEV-SNP confidential VM setup - Extract `init_mshv()` for MSHV hypervisor initialization - Extract `init_kvm()` for KVM hypervisor initialization - Extract `create_fw_cfg_if_enabled()` for fw_cfg device creation This refactoring replaces complex nested `cfg_if!` blocks with cleaner conditional method calls, providing clear separation between hypervisor- specific initialization paths while preserving existing functionality. No functional changes intended. Issue: https://github.com/cloud-hypervisor/cloud-hypervisor/issues/7598 Signed-off-by: Muminul Islam <muislam@microsoft.com>
This commit is contained in:
committed by
Rob Bradford
parent
03ef7d1991
commit
41b23229a5
@@ -15,7 +15,9 @@ use std::io::{self, IsTerminal, Seek, SeekFrom, stdout};
|
|||||||
use std::num::Wrapping;
|
use std::num::Wrapping;
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::unix::fs::OpenOptionsExt;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||||
use std::path::{Path, PathBuf};
|
#[cfg(not(target_arch = "riscv64"))]
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
#[cfg(not(target_arch = "riscv64"))]
|
#[cfg(not(target_arch = "riscv64"))]
|
||||||
|
|||||||
+438
-244
@@ -11,7 +11,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||||
//
|
//
|
||||||
|
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{self, Seek, SeekFrom, Write};
|
use std::io::{self, Seek, SeekFrom, Write};
|
||||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||||
@@ -560,21 +560,10 @@ impl Vm {
|
|||||||
let numa_nodes =
|
let numa_nodes =
|
||||||
Self::create_numa_nodes(config.lock().unwrap().numa.as_deref(), &memory_manager)?;
|
Self::create_numa_nodes(config.lock().unwrap().numa.as_deref(), &memory_manager)?;
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
// Determine if IOMMU should be forced based on confidential computing features
|
||||||
let tdx_enabled = config.lock().unwrap().is_tdx_enabled();
|
let force_iommu = Self::should_force_iommu(&config);
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
let sev_snp_enabled = config.lock().unwrap().is_sev_snp_enabled();
|
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
let force_iommu = tdx_enabled;
|
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
let force_iommu = sev_snp_enabled;
|
|
||||||
#[cfg(not(any(feature = "tdx", feature = "sev_snp")))]
|
|
||||||
let force_iommu = false;
|
|
||||||
|
|
||||||
#[cfg(feature = "guest_debug")]
|
let stop_on_boot = Self::should_stop_on_boot(&config);
|
||||||
let stop_on_boot = config.lock().unwrap().gdb;
|
|
||||||
#[cfg(not(feature = "guest_debug"))]
|
|
||||||
let stop_on_boot = false;
|
|
||||||
|
|
||||||
let memory = memory_manager.lock().unwrap().guest_memory();
|
let memory = memory_manager.lock().unwrap().guest_memory();
|
||||||
let io_bus = Arc::new(Bus::new());
|
let io_bus = Arc::new(Bus::new());
|
||||||
@@ -587,63 +576,26 @@ impl Vm {
|
|||||||
mmio_bus: mmio_bus.clone(),
|
mmio_bus: mmio_bus.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
let cpus_config = { &config.lock().unwrap().cpus.clone() };
|
// Create CPU manager
|
||||||
let cpu_manager = cpu::CpuManager::new(
|
let cpu_manager = Self::create_cpu_manager(
|
||||||
cpus_config,
|
&config,
|
||||||
vm.clone(),
|
vm.clone(),
|
||||||
exit_evt.try_clone().map_err(Error::EventFdClone)?,
|
exit_evt.try_clone().map_err(Error::EventFdClone)?,
|
||||||
reset_evt.try_clone().map_err(Error::EventFdClone)?,
|
reset_evt.try_clone().map_err(Error::EventFdClone)?,
|
||||||
#[cfg(feature = "guest_debug")]
|
#[cfg(feature = "guest_debug")]
|
||||||
vm_debug_evt,
|
vm_debug_evt,
|
||||||
hypervisor.clone(),
|
&hypervisor,
|
||||||
seccomp_action.clone(),
|
seccomp_action.clone(),
|
||||||
vm_ops,
|
vm_ops,
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
tdx_enabled,
|
|
||||||
&numa_nodes,
|
&numa_nodes,
|
||||||
#[cfg(feature = "sev_snp")]
|
)?;
|
||||||
sev_snp_enabled,
|
|
||||||
)
|
|
||||||
.map_err(Error::CpuManager)?;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
// Perform hypervisor-specific TDX initialization if enabled
|
||||||
cpu_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.populate_cpuid(
|
|
||||||
hypervisor.as_ref(),
|
|
||||||
#[cfg(feature = "tdx")]
|
|
||||||
tdx_enabled,
|
|
||||||
)
|
|
||||||
.map_err(Error::CpuManager)?;
|
|
||||||
|
|
||||||
// The initial TDX configuration must be done before the vCPUs are
|
|
||||||
// created
|
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
if tdx_enabled {
|
Self::init_tdx_if_enabled(&config, &vm, &cpu_manager)?;
|
||||||
let cpuid = cpu_manager.lock().unwrap().common_cpuid();
|
|
||||||
let max_vcpus = cpu_manager.lock().unwrap().max_vcpus();
|
|
||||||
vm.tdx_init(&cpuid, max_vcpus)
|
|
||||||
.map_err(Error::InitializeTdxVm)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "tdx")]
|
// Create device manager
|
||||||
let dynamic = !tdx_enabled;
|
let device_manager = Self::create_device_manager(
|
||||||
#[cfg(not(feature = "tdx"))]
|
|
||||||
let dynamic = true;
|
|
||||||
|
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
let is_kvm = matches!(
|
|
||||||
hypervisor.hypervisor_type(),
|
|
||||||
hypervisor::HypervisorType::Kvm
|
|
||||||
);
|
|
||||||
#[cfg(feature = "mshv")]
|
|
||||||
let is_mshv = matches!(
|
|
||||||
hypervisor.hypervisor_type(),
|
|
||||||
hypervisor::HypervisorType::Mshv
|
|
||||||
);
|
|
||||||
|
|
||||||
let device_manager = DeviceManager::new(
|
|
||||||
io_bus,
|
io_bus,
|
||||||
mmio_bus,
|
mmio_bus,
|
||||||
vm.clone(),
|
vm.clone(),
|
||||||
@@ -659,190 +611,25 @@ impl Vm {
|
|||||||
boot_id_list,
|
boot_id_list,
|
||||||
#[cfg(not(target_arch = "riscv64"))]
|
#[cfg(not(target_arch = "riscv64"))]
|
||||||
timestamp,
|
timestamp,
|
||||||
snapshot_from_id(snapshot, DEVICE_MANAGER_SNAPSHOT_ID),
|
snapshot,
|
||||||
dynamic,
|
&config,
|
||||||
)
|
)?;
|
||||||
.map_err(Error::DeviceManager)?;
|
|
||||||
|
|
||||||
// Initialize the VM now that we have created the device manager.
|
// Perform hypervisor-specific initialization
|
||||||
// For MSHV and non aarch64, we need to initialize the VM before creating vCPUs.
|
let load_payload_handle = Self::hypervisor_specific_init(
|
||||||
// For aarch64, we need to initialize the VM after creating interrupt controller.
|
&vm,
|
||||||
// Push down write after the IC(Interrupt Controller) creation for MSHV aarch64.
|
&memory_manager,
|
||||||
#[cfg(all(feature = "mshv", not(target_arch = "aarch64")))]
|
&cpu_manager,
|
||||||
{
|
&device_manager,
|
||||||
if is_mshv {
|
&config,
|
||||||
vm.init().map_err(Error::InitializeVm)?;
|
&hypervisor,
|
||||||
}
|
console_info.as_ref(),
|
||||||
}
|
console_resize_pipe.as_ref(),
|
||||||
#[cfg(feature = "sev_snp")]
|
&original_termios,
|
||||||
if sev_snp_enabled {
|
snapshot,
|
||||||
cpu_manager
|
)?;
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_boot_vcpus(snapshot_from_id(snapshot, CPU_MANAGER_SNAPSHOT_ID))
|
|
||||||
.map_err(Error::CpuManager)?;
|
|
||||||
|
|
||||||
// This initial SEV-SNP configuration must be done immediately after
|
|
||||||
// vCPUs are created. As part of this initialization we are
|
|
||||||
// transitioning the guest into secure state.
|
|
||||||
vm.sev_snp_init().map_err(Error::InitializeSevSnpVm)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
// Loading the igvm file is pushed down here because
|
|
||||||
// igvm parser needs cpu_manager to retrieve cpuid leaf.
|
|
||||||
// Currently, Microsoft Hypervisor does not provide any
|
|
||||||
// Hypervisor specific common cpuid, we need to call get_cpuid_values
|
|
||||||
// per cpuid through cpu_manager.
|
|
||||||
let _load_payload_handle = if snapshot.is_none() && sev_snp_enabled {
|
|
||||||
Self::load_payload_async(
|
|
||||||
&memory_manager,
|
|
||||||
&config,
|
|
||||||
#[cfg(feature = "igvm")]
|
|
||||||
&cpu_manager,
|
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
sev_snp_enabled,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "mshv")]
|
|
||||||
{
|
|
||||||
if is_mshv {
|
|
||||||
let ic = device_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_interrupt_controller()
|
|
||||||
.map_err(Error::DeviceManager)?;
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
vm.init().map_err(Error::InitializeVm)?;
|
|
||||||
device_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_devices(
|
|
||||||
console_info.clone(),
|
|
||||||
console_resize_pipe.clone(),
|
|
||||||
original_termios.clone(),
|
|
||||||
ic,
|
|
||||||
)
|
|
||||||
.map_err(Error::DeviceManager)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "sev_snp")] {
|
|
||||||
if !sev_snp_enabled {
|
|
||||||
memory_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.allocate_address_space()
|
|
||||||
.map_err(Error::MemoryManager)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
memory_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.allocate_address_space()
|
|
||||||
.map_err(Error::MemoryManager)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
memory_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.add_uefi_flash()
|
|
||||||
.map_err(Error::MemoryManager)?;
|
|
||||||
|
|
||||||
// First case is when sev_snp is enabled(compiled), but run time non-cvn
|
|
||||||
// guest boot. 2nd case is when sev_snp is not compiled in, KVM and MSHV regular guest boot.
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "sev_snp")] {
|
|
||||||
let _load_payload_handle = if snapshot.is_none() && !sev_snp_enabled {
|
|
||||||
Self::load_payload_async(
|
|
||||||
&memory_manager,
|
|
||||||
&config,
|
|
||||||
#[cfg(feature = "igvm")]
|
|
||||||
&cpu_manager,
|
|
||||||
#[cfg(feature = "sev_snp")]
|
|
||||||
sev_snp_enabled,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
let _load_payload_handle = if snapshot.is_none() {
|
|
||||||
Self::load_payload_async(
|
|
||||||
&memory_manager,
|
|
||||||
&config,
|
|
||||||
#[cfg(feature = "igvm")]
|
|
||||||
&cpu_manager,
|
|
||||||
)?
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// First case is when sev_snp is enabled(compiled), but run time non-cvn
|
|
||||||
// guest boot. 2nd case is when sev_snp is not compiled in, KVM and MSHV regular guest boot.
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(feature = "sev_snp")] {
|
|
||||||
if !sev_snp_enabled {
|
|
||||||
cpu_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_boot_vcpus(snapshot_from_id(snapshot, CPU_MANAGER_SNAPSHOT_ID))
|
|
||||||
.map_err(Error::CpuManager)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cpu_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_boot_vcpus(snapshot_from_id(snapshot, CPU_MANAGER_SNAPSHOT_ID))
|
|
||||||
.map_err(Error::CpuManager)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For KVM, we need to create interrupt controller after we create boot vcpus.
|
|
||||||
// Because we restore GIC state from the snapshot as part of boot vcpu creation.
|
|
||||||
// This means that we need to create interrupt controller after we restore in case of KVM guests.
|
|
||||||
#[cfg(feature = "kvm")]
|
|
||||||
{
|
|
||||||
if is_kvm {
|
|
||||||
let ic = device_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_interrupt_controller()
|
|
||||||
.map_err(Error::DeviceManager)?;
|
|
||||||
|
|
||||||
vm.init().map_err(Error::InitializeVm)?;
|
|
||||||
|
|
||||||
device_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_devices(console_info, console_resize_pipe, original_termios, ic)
|
|
||||||
.map_err(Error::DeviceManager)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "fw_cfg")]
|
|
||||||
{
|
|
||||||
let fw_cfg_config = config
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.payload
|
|
||||||
.as_ref()
|
|
||||||
.is_some_and(|p| p.fw_cfg_config.is_some());
|
|
||||||
if fw_cfg_config {
|
|
||||||
device_manager
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.create_fw_cfg_device()
|
|
||||||
.map_err(Error::DeviceManager)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Load kernel and initramfs files
|
||||||
#[cfg(feature = "tdx")]
|
#[cfg(feature = "tdx")]
|
||||||
let kernel = config
|
let kernel = config
|
||||||
.lock()
|
.lock()
|
||||||
@@ -896,10 +683,417 @@ impl Vm {
|
|||||||
#[cfg(not(target_arch = "riscv64"))]
|
#[cfg(not(target_arch = "riscv64"))]
|
||||||
hypervisor,
|
hypervisor,
|
||||||
stop_on_boot,
|
stop_on_boot,
|
||||||
load_payload_handle: _load_payload_handle,
|
load_payload_handle,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determine if IOMMU should be forced based on confidential computing features.
|
||||||
|
fn should_force_iommu(_config: &Arc<Mutex<VmConfig>>) -> bool {
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
if _config.lock().unwrap().is_tdx_enabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
if _config.lock().unwrap().is_sev_snp_enabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determine if VM should stop on boot (for debugging).
|
||||||
|
fn should_stop_on_boot(config: &Arc<Mutex<VmConfig>>) -> bool {
|
||||||
|
#[cfg(feature = "guest_debug")]
|
||||||
|
{
|
||||||
|
config.lock().unwrap().gdb
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "guest_debug"))]
|
||||||
|
{
|
||||||
|
let _ = config;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and configure the CPU manager.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn create_cpu_manager(
|
||||||
|
config: &Arc<Mutex<VmConfig>>,
|
||||||
|
vm: Arc<dyn hypervisor::Vm>,
|
||||||
|
exit_evt: EventFd,
|
||||||
|
reset_evt: EventFd,
|
||||||
|
#[cfg(feature = "guest_debug")] vm_debug_evt: EventFd,
|
||||||
|
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
|
||||||
|
seccomp_action: SeccompAction,
|
||||||
|
vm_ops: Arc<dyn VmOps>,
|
||||||
|
numa_nodes: &NumaNodes,
|
||||||
|
) -> Result<Arc<Mutex<cpu::CpuManager>>> {
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
let tdx_enabled = config.lock().unwrap().is_tdx_enabled();
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
let sev_snp_enabled = config.lock().unwrap().is_sev_snp_enabled();
|
||||||
|
|
||||||
|
let cpus_config = config.lock().unwrap().cpus.clone();
|
||||||
|
let cpu_manager = cpu::CpuManager::new(
|
||||||
|
&cpus_config,
|
||||||
|
vm,
|
||||||
|
exit_evt,
|
||||||
|
reset_evt,
|
||||||
|
#[cfg(feature = "guest_debug")]
|
||||||
|
vm_debug_evt,
|
||||||
|
hypervisor.clone(),
|
||||||
|
seccomp_action,
|
||||||
|
vm_ops,
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
tdx_enabled,
|
||||||
|
numa_nodes,
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
sev_snp_enabled,
|
||||||
|
)
|
||||||
|
.map_err(Error::CpuManager)?;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
cpu_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.populate_cpuid(
|
||||||
|
hypervisor.as_ref(),
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
tdx_enabled,
|
||||||
|
)
|
||||||
|
.map_err(Error::CpuManager)?;
|
||||||
|
|
||||||
|
Ok(cpu_manager)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize TDX if enabled.
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
fn init_tdx_if_enabled(
|
||||||
|
config: &Arc<Mutex<VmConfig>>,
|
||||||
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
cpu_manager: &Arc<Mutex<cpu::CpuManager>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
if config.lock().unwrap().is_tdx_enabled() {
|
||||||
|
let cpuid = cpu_manager.lock().unwrap().common_cpuid();
|
||||||
|
let max_vcpus = cpu_manager.lock().unwrap().max_vcpus();
|
||||||
|
vm.tdx_init(&cpuid, max_vcpus)
|
||||||
|
.map_err(Error::InitializeTdxVm)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create and configure the device manager.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn create_device_manager(
|
||||||
|
io_bus: Arc<Bus>,
|
||||||
|
mmio_bus: Arc<Bus>,
|
||||||
|
vm: Arc<dyn hypervisor::Vm>,
|
||||||
|
config: Arc<Mutex<VmConfig>>,
|
||||||
|
memory_manager: Arc<Mutex<MemoryManager>>,
|
||||||
|
cpu_manager: Arc<Mutex<cpu::CpuManager>>,
|
||||||
|
exit_evt: EventFd,
|
||||||
|
reset_evt: EventFd,
|
||||||
|
seccomp_action: SeccompAction,
|
||||||
|
numa_nodes: NumaNodes,
|
||||||
|
activate_evt: &EventFd,
|
||||||
|
force_iommu: bool,
|
||||||
|
boot_id_list: BTreeSet<String>,
|
||||||
|
#[cfg(not(target_arch = "riscv64"))] timestamp: Instant,
|
||||||
|
snapshot: Option<&Snapshot>,
|
||||||
|
_vm_config: &Arc<Mutex<VmConfig>>,
|
||||||
|
) -> Result<Arc<Mutex<DeviceManager>>> {
|
||||||
|
#[cfg(feature = "tdx")]
|
||||||
|
let dynamic = !_vm_config.lock().unwrap().is_tdx_enabled();
|
||||||
|
#[cfg(not(feature = "tdx"))]
|
||||||
|
let dynamic = true;
|
||||||
|
|
||||||
|
DeviceManager::new(
|
||||||
|
io_bus,
|
||||||
|
mmio_bus,
|
||||||
|
vm,
|
||||||
|
config,
|
||||||
|
memory_manager,
|
||||||
|
cpu_manager,
|
||||||
|
exit_evt,
|
||||||
|
reset_evt,
|
||||||
|
seccomp_action,
|
||||||
|
numa_nodes,
|
||||||
|
activate_evt,
|
||||||
|
force_iommu,
|
||||||
|
boot_id_list,
|
||||||
|
#[cfg(not(target_arch = "riscv64"))]
|
||||||
|
timestamp,
|
||||||
|
snapshot_from_id(snapshot, DEVICE_MANAGER_SNAPSHOT_ID),
|
||||||
|
dynamic,
|
||||||
|
)
|
||||||
|
.map_err(Error::DeviceManager)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Perform hypervisor-specific initialization.
|
||||||
|
///
|
||||||
|
/// This handles the different initialization sequences required by:
|
||||||
|
/// - KVM (x86_64, aarch64, riscv64)
|
||||||
|
/// - MSHV (x86_64, aarch64)
|
||||||
|
/// - SEV-SNP (MSHV with confidential computing)
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn hypervisor_specific_init(
|
||||||
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
memory_manager: &Arc<Mutex<MemoryManager>>,
|
||||||
|
cpu_manager: &Arc<Mutex<cpu::CpuManager>>,
|
||||||
|
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||||
|
config: &Arc<Mutex<VmConfig>>,
|
||||||
|
hypervisor: &Arc<dyn hypervisor::Hypervisor>,
|
||||||
|
console_info: Option<&ConsoleInfo>,
|
||||||
|
console_resize_pipe: Option<&Arc<File>>,
|
||||||
|
original_termios: &Arc<Mutex<Option<termios>>>,
|
||||||
|
snapshot: Option<&Snapshot>,
|
||||||
|
) -> Result<Option<thread::JoinHandle<Result<EntryPoint>>>> {
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
let is_mshv = matches!(
|
||||||
|
hypervisor.hypervisor_type(),
|
||||||
|
hypervisor::HypervisorType::Mshv
|
||||||
|
);
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
|
let is_kvm = matches!(
|
||||||
|
hypervisor.hypervisor_type(),
|
||||||
|
hypervisor::HypervisorType::Kvm
|
||||||
|
);
|
||||||
|
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
let sev_snp_enabled = config.lock().unwrap().is_sev_snp_enabled();
|
||||||
|
|
||||||
|
// MSHV-specific initialization (non-aarch64)
|
||||||
|
#[cfg(all(feature = "mshv", not(target_arch = "aarch64")))]
|
||||||
|
if is_mshv {
|
||||||
|
vm.init().map_err(Error::InitializeVm)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SEV-SNP specific initialization
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
if sev_snp_enabled {
|
||||||
|
return Self::init_sev_snp(
|
||||||
|
vm,
|
||||||
|
memory_manager,
|
||||||
|
cpu_manager,
|
||||||
|
device_manager,
|
||||||
|
config,
|
||||||
|
console_info,
|
||||||
|
console_resize_pipe,
|
||||||
|
original_termios,
|
||||||
|
snapshot,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSHV initialization (create interrupt controller and devices)
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
if is_mshv {
|
||||||
|
Self::init_mshv(
|
||||||
|
vm,
|
||||||
|
device_manager,
|
||||||
|
console_info,
|
||||||
|
console_resize_pipe,
|
||||||
|
original_termios,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate address space for non-SEV-SNP guests
|
||||||
|
memory_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.allocate_address_space()
|
||||||
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
|
// Add UEFI flash for aarch64
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
memory_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.add_uefi_flash()
|
||||||
|
.map_err(Error::MemoryManager)?;
|
||||||
|
|
||||||
|
// Load payload asynchronously
|
||||||
|
let load_payload_handle = if snapshot.is_none() {
|
||||||
|
Self::load_payload_async(
|
||||||
|
memory_manager,
|
||||||
|
config,
|
||||||
|
#[cfg(feature = "igvm")]
|
||||||
|
cpu_manager,
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
false,
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create boot vCPUs
|
||||||
|
cpu_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_boot_vcpus(snapshot_from_id(snapshot, CPU_MANAGER_SNAPSHOT_ID))
|
||||||
|
.map_err(Error::CpuManager)?;
|
||||||
|
|
||||||
|
// KVM-specific initialization
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
|
if is_kvm {
|
||||||
|
Self::init_kvm(
|
||||||
|
vm,
|
||||||
|
device_manager,
|
||||||
|
console_info.cloned(),
|
||||||
|
console_resize_pipe.cloned(),
|
||||||
|
original_termios.clone(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create fw_cfg device if configured
|
||||||
|
#[cfg(feature = "fw_cfg")]
|
||||||
|
Self::create_fw_cfg_if_enabled(config, device_manager)?;
|
||||||
|
|
||||||
|
Ok(load_payload_handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize SEV-SNP specific components.
|
||||||
|
#[cfg(feature = "sev_snp")]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn init_sev_snp(
|
||||||
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
memory_manager: &Arc<Mutex<MemoryManager>>,
|
||||||
|
cpu_manager: &Arc<Mutex<cpu::CpuManager>>,
|
||||||
|
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||||
|
config: &Arc<Mutex<VmConfig>>,
|
||||||
|
console_info: Option<&ConsoleInfo>,
|
||||||
|
console_resize_pipe: Option<&Arc<File>>,
|
||||||
|
original_termios: &Arc<Mutex<Option<termios>>>,
|
||||||
|
snapshot: Option<&Snapshot>,
|
||||||
|
) -> Result<Option<thread::JoinHandle<Result<EntryPoint>>>> {
|
||||||
|
// Create boot vCPUs before SEV-SNP initialization
|
||||||
|
cpu_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_boot_vcpus(snapshot_from_id(snapshot, CPU_MANAGER_SNAPSHOT_ID))
|
||||||
|
.map_err(Error::CpuManager)?;
|
||||||
|
|
||||||
|
// Initialize SEV-SNP - transitions guest into secure state
|
||||||
|
vm.sev_snp_init().map_err(Error::InitializeSevSnpVm)?;
|
||||||
|
|
||||||
|
// Load payload for SEV-SNP (IGVM parser needs cpu_manager for cpuid)
|
||||||
|
let load_payload_handle = if snapshot.is_none() {
|
||||||
|
Self::load_payload_async(
|
||||||
|
memory_manager,
|
||||||
|
config,
|
||||||
|
#[cfg(feature = "igvm")]
|
||||||
|
cpu_manager,
|
||||||
|
true,
|
||||||
|
)?
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create interrupt controller and devices for MSHV
|
||||||
|
let ic = device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_interrupt_controller()
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
vm.init().map_err(Error::InitializeVm)?;
|
||||||
|
|
||||||
|
device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_devices(
|
||||||
|
console_info.cloned(),
|
||||||
|
console_resize_pipe.cloned(),
|
||||||
|
original_termios.clone(),
|
||||||
|
ic,
|
||||||
|
)
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
Ok(load_payload_handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize MSHV-specific components.
|
||||||
|
#[cfg(feature = "mshv")]
|
||||||
|
fn init_mshv(
|
||||||
|
_vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||||
|
console_info: Option<&ConsoleInfo>,
|
||||||
|
console_resize_pipe: Option<&Arc<File>>,
|
||||||
|
original_termios: &Arc<Mutex<Option<termios>>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let ic = device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_interrupt_controller()
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
#[cfg(target_arch = "aarch64")]
|
||||||
|
_vm.init().map_err(Error::InitializeVm)?;
|
||||||
|
|
||||||
|
device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_devices(
|
||||||
|
console_info.cloned(),
|
||||||
|
console_resize_pipe.cloned(),
|
||||||
|
original_termios.clone(),
|
||||||
|
ic,
|
||||||
|
)
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Initialize KVM-specific components.
|
||||||
|
#[cfg(feature = "kvm")]
|
||||||
|
fn init_kvm(
|
||||||
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||||
|
console_info: Option<ConsoleInfo>,
|
||||||
|
console_resize_pipe: Option<Arc<File>>,
|
||||||
|
original_termios: Arc<Mutex<Option<termios>>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
// For KVM, create interrupt controller after boot vcpus
|
||||||
|
// because GIC state is restored from snapshot during vcpu creation
|
||||||
|
let ic = device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_interrupt_controller()
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
vm.init().map_err(Error::InitializeVm)?;
|
||||||
|
|
||||||
|
device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_devices(console_info, console_resize_pipe, original_termios, ic)
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create fw_cfg device if enabled in configuration.
|
||||||
|
#[cfg(feature = "fw_cfg")]
|
||||||
|
fn create_fw_cfg_if_enabled(
|
||||||
|
config: &Arc<Mutex<VmConfig>>,
|
||||||
|
device_manager: &Arc<Mutex<DeviceManager>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let fw_cfg_enabled = config
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.payload
|
||||||
|
.as_ref()
|
||||||
|
.is_some_and(|p| p.fw_cfg_config.is_some());
|
||||||
|
|
||||||
|
if fw_cfg_enabled {
|
||||||
|
device_manager
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.create_fw_cfg_device()
|
||||||
|
.map_err(Error::DeviceManager)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "fw_cfg")]
|
#[cfg(feature = "fw_cfg")]
|
||||||
fn populate_fw_cfg(
|
fn populate_fw_cfg(
|
||||||
fw_cfg_config: &FwCfgConfig,
|
fw_cfg_config: &FwCfgConfig,
|
||||||
|
|||||||
Reference in New Issue
Block a user