vmm: parse IGVM file early and thread it through VM setup

Move IGVM file parsing from load_igvm() into a dedicated parse_igvm()
helper in igvm/mod.rs, and parse the file upfront in Vm::new() so the
resulting IgvmFile struct is available throughout VM initialization.

This is a prerequisite for extracting VMSA SEV features from the parsed
IGVM before issuing KVM_SEV_INIT2, which needs sev_features.

Signed-off-by: Ruben Hakobyan <hruben@meta.com>
This commit is contained in:
Ruben Hakobyan
2026-04-09 16:58:58 -07:00
committed by Rob Bradford
parent 4f1119a788
commit 425609a8b5
4 changed files with 52 additions and 19 deletions
+37 -9
View File
@@ -47,6 +47,8 @@ use gdbstub_arch::x86::reg::X86_64CoreRegs as CoreRegs;
#[cfg(target_arch = "aarch64")]
use hypervisor::arch::aarch64::regs::AARCH64_PMU_IRQ;
use hypervisor::{HypervisorVmConfig, HypervisorVmError, VmOps};
#[cfg(feature = "igvm")]
use igvm::IgvmFile;
#[cfg(feature = "sev_snp")]
use igvm_defs::SnpPolicy;
use libc::{SIGWINCH, termios};
@@ -333,10 +335,6 @@ pub enum Error {
#[error("Error coredumping VM")]
Coredump(#[source] GuestDebuggableError),
#[cfg(feature = "igvm")]
#[error("Cannot open igvm file")]
IgvmFile(#[source] io::Error),
#[cfg(feature = "igvm")]
#[error("Cannot load the igvm into memory")]
IgvmLoad(#[source] igvm_loader::Error),
@@ -567,6 +565,7 @@ impl Vm {
console_resize_pipe: Option<Arc<File>>,
original_termios: Arc<Mutex<Option<termios>>>,
snapshot: Option<&Snapshot>,
#[cfg(feature = "igvm")] igvm_file: Option<IgvmFile>,
) -> Result<Self> {
trace_scoped!("Vm::new_from_memory_manager");
@@ -649,6 +648,8 @@ impl Vm {
console_resize_pipe.as_ref(),
&original_termios,
snapshot,
#[cfg(feature = "igvm")]
igvm_file,
)?;
// Load kernel and initramfs files
@@ -879,6 +880,7 @@ impl Vm {
console_resize_pipe: Option<&Arc<File>>,
original_termios: &Arc<Mutex<Option<termios>>>,
snapshot: Option<&Snapshot>,
#[cfg(feature = "igvm")] igvm_file: Option<IgvmFile>,
) -> Result<Option<thread::JoinHandle<Result<EntryPoint>>>> {
#[cfg(feature = "mshv")]
let is_mshv = matches!(
@@ -913,6 +915,8 @@ impl Vm {
console_resize_pipe,
original_termios,
snapshot,
#[cfg(feature = "igvm")]
igvm_file,
);
}
@@ -942,6 +946,8 @@ impl Vm {
config,
#[cfg(feature = "igvm")]
cpu_manager,
#[cfg(feature = "igvm")]
igvm_file,
)?
} else {
None
@@ -986,6 +992,7 @@ impl Vm {
console_resize_pipe: Option<&Arc<File>>,
original_termios: &Arc<Mutex<Option<termios>>>,
snapshot: Option<&Snapshot>,
#[cfg(feature = "igvm")] igvm_file: Option<IgvmFile>,
) -> Result<Option<thread::JoinHandle<Result<EntryPoint>>>> {
// Create boot vCPUs before SEV-SNP initialization
cpu_manager
@@ -1005,6 +1012,8 @@ impl Vm {
config,
#[cfg(feature = "igvm")]
cpu_manager,
#[cfg(feature = "igvm")]
igvm_file,
)?
} else {
None
@@ -1306,6 +1315,18 @@ impl Vm {
vm_config.lock().unwrap().is_tdx_enabled()
};
#[cfg(feature = "igvm")]
let igvm_file = {
let config = vm_config.lock().unwrap();
config
.payload
.as_ref()
.and_then(|p| p.igvm.as_ref())
.map(|igvm_path| crate::igvm::parse_igvm(igvm_path))
.transpose()
.map_err(Error::IgvmLoad)?
};
let vm = Self::create_hypervisor_vm(
hypervisor.as_ref(),
vm_config.as_ref().lock().unwrap().deref().into(),
@@ -1366,6 +1387,8 @@ impl Vm {
console_resize_pipe,
original_termios,
snapshot,
#[cfg(feature = "igvm")]
igvm_file,
)
}
@@ -1484,13 +1507,13 @@ impl Vm {
#[cfg(feature = "igvm")]
#[allow(clippy::needless_pass_by_value)]
fn load_igvm(
igvm: File,
igvm_file: IgvmFile,
memory_manager: Arc<Mutex<MemoryManager>>,
cpu_manager: Arc<Mutex<cpu::CpuManager>>,
#[cfg(feature = "sev_snp")] host_data: &Option<String>,
) -> Result<EntryPoint> {
let res = igvm_loader::load_igvm(
&igvm,
igvm_file,
memory_manager,
cpu_manager.clone(),
"",
@@ -1580,14 +1603,16 @@ impl Vm {
payload: &PayloadConfig,
memory_manager: Arc<Mutex<MemoryManager>>,
#[cfg(feature = "igvm")] cpu_manager: Arc<Mutex<cpu::CpuManager>>,
#[cfg(feature = "igvm")] igvm_file: Option<IgvmFile>,
) -> Result<EntryPoint> {
trace_scoped!("load_payload");
#[cfg(feature = "igvm")]
{
if let Some(_igvm_file) = &payload.igvm {
let igvm = File::open(_igvm_file).map_err(Error::IgvmFile)?;
if payload.igvm.is_some() {
let igvm_file =
igvm_file.ok_or(Error::IgvmLoad(igvm_loader::Error::MissingIgvm))?;
return Self::load_igvm(
igvm,
igvm_file,
memory_manager,
cpu_manager,
#[cfg(feature = "sev_snp")]
@@ -1636,6 +1661,7 @@ impl Vm {
memory_manager: &Arc<Mutex<MemoryManager>>,
config: &Arc<Mutex<VmConfig>>,
#[cfg(feature = "igvm")] cpu_manager: &Arc<Mutex<cpu::CpuManager>>,
#[cfg(feature = "igvm")] igvm_file: Option<IgvmFile>,
) -> Result<Option<thread::JoinHandle<Result<EntryPoint>>>> {
// Kernel with TDX is loaded in a different manner
#[cfg(feature = "tdx")]
@@ -1662,6 +1688,8 @@ impl Vm {
memory_manager,
#[cfg(feature = "igvm")]
cpu_manager,
#[cfg(feature = "igvm")]
igvm_file,
)
})
.map_err(Error::KernelLoadThreadSpawn)