hypervisor, vmm: Add KVM SEV_{INIT2, SNP_LAUNCH_START} support

Introduce the SevFd abstraction that wraps /dev/sev and implements the
KVM_SEV_INIT2 and KVM_SEV_SNP_LAUNCH_START ioctls for SEV-SNP VM
initialization on KVM.

Key changes:
- Add sev.rs with KvmSevInit and KvmSevSnpLaunchStart ioctl structs
  matching the kernel layout (linux/arch/x86/include/uapi/asm/kvm.h)
- Implement KVM_SEV_INIT2 and KVM_SEV_SNP_LAUNCH_START ioctls
- Set KVM_MEMORY_ATTRIBUTE_PRIVATE on newly created memory regions
  when guest_memfd is supported
- Widen SevSnpPageAccessProxy cfg gates from mshv-only to all
  sev_snp-enabled builds
- Make sev_snp_init a required trait method (remove default impl)
- Include KVM_SEV_SNP_LAUNCH_START in the seccomp allowlist
- Parse VMSA SEV features from IGVM and include them in the
  KVM_SEV_INIT2 ioctl

Co-authored-by: Keith Adler <kadler@cloudflare.com>
Signed-off-by: Keith Adler <kadler@cloudflare.com>
Co-authored-by: Alex Orozco <aorozco@google.com>
Signed-off-by: Alex Orozco <aorozco@google.com>
Co-authored-by: Rob Bradford <rbradford@meta.com>
Signed-off-by: Rob Bradford <rbradford@meta.com>
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
This commit is contained in:
Ruben Hakobyan
2026-04-07 14:23:13 -07:00
committed by Rob Bradford
parent 425609a8b5
commit 2e004521e0
12 changed files with 225 additions and 25 deletions
+4 -4
View File
@@ -957,26 +957,26 @@ pub struct AcpiPlatformAddresses {
pub sleep_status_reg_address: Option<GenericAddress>,
}
#[cfg(all(feature = "mshv", feature = "sev_snp"))]
#[cfg(feature = "sev_snp")]
struct SevSnpPageAccessProxy {
vm: Arc<dyn hypervisor::Vm>,
}
#[cfg(all(feature = "mshv", feature = "sev_snp"))]
#[cfg(feature = "sev_snp")]
impl std::fmt::Debug for SevSnpPageAccessProxy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SNP Page access proxy")
}
}
#[cfg(all(feature = "mshv", feature = "sev_snp"))]
#[cfg(feature = "sev_snp")]
impl SevSnpPageAccessProxy {
fn new(vm: Arc<dyn hypervisor::Vm>) -> SevSnpPageAccessProxy {
SevSnpPageAccessProxy { vm }
}
}
#[cfg(all(feature = "mshv", feature = "sev_snp"))]
#[cfg(feature = "sev_snp")]
impl AccessPlatform for SevSnpPageAccessProxy {
fn translate_gpa(&self, base: u64, _size: u64) -> std::result::Result<u64, std::io::Error> {
Ok(base)
+15
View File
@@ -129,6 +129,21 @@ fn import_parameter(
Ok(())
}
///
/// Extract sev_features from the boot CPU (vp_index 0) VMSA.
///
#[cfg(feature = "sev_snp")]
pub fn extract_sev_features(igvm_file: &IgvmFile) -> u64 {
for header in igvm_file.directives() {
if let IgvmDirectiveHeader::SnpVpContext { vp_index, vmsa, .. } = header
&& *vp_index == 0
{
return vmsa.sev_features.into();
}
}
0
}
///
/// Load the given IGVM file to guest memory.
/// Right now it only supports SNP based isolation.
+2
View File
@@ -234,6 +234,8 @@ impl From<&VmConfig> for hypervisor::HypervisorVmConfig {
sev_snp_enabled: _value.is_sev_snp_enabled(),
#[cfg(feature = "sev_snp")]
mem_size: _value.memory.total_size(),
#[cfg(feature = "sev_snp")]
vmsa_features: 0,
nested: _value.cpus.nested,
smt_enabled: _value
.cpus
+2
View File
@@ -111,6 +111,7 @@ mod kvm {
pub const KVM_NMI: u64 = 0xae9a;
pub const KVM_GET_NESTED_STATE: u64 = 3229658814;
pub const KVM_SET_NESTED_STATE: u64 = 1082175167;
pub const KVM_SEV_SNP_LAUNCH_START: u64 = 0x4018_aeb4;
}
mod iommufd {
@@ -267,6 +268,7 @@ fn create_vmm_ioctl_seccomp_rule_common_kvm() -> Result<Vec<SeccompRule>, Backen
and![Cond::new(1, ArgLen::Dword, Eq, KVM_NMI)?],
and![Cond::new(1, ArgLen::Dword, Eq, KVM_GET_NESTED_STATE)?],
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_NESTED_STATE)?],
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SEV_SNP_LAUNCH_START)?],
])
}
+10 -4
View File
@@ -1327,10 +1327,16 @@ impl Vm {
.map_err(Error::IgvmLoad)?
};
let vm = Self::create_hypervisor_vm(
hypervisor.as_ref(),
vm_config.as_ref().lock().unwrap().deref().into(),
)?;
let vm = {
#[allow(unused_mut)]
let mut hv_config: hypervisor::HypervisorVmConfig =
vm_config.as_ref().lock().unwrap().deref().into();
#[cfg(all(feature = "igvm", feature = "sev_snp"))]
if let Some(ref igvm) = igvm_file {
hv_config.vmsa_features = igvm_loader::extract_sev_features(igvm);
}
Self::create_hypervisor_vm(hypervisor.as_ref(), hv_config)?
};
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
if vm_config.lock().unwrap().max_apic_id() > MAX_SUPPORTED_CPUS_LEGACY {