pub(crate) mod sev;
pub(crate) mod tdx;
use std::arch::x86_64::CpuidResult;
use std::collections::HashMap;
use snafu::ResultExt;
use crate::arch::cpuid::CpuidIn;
#[cfg(target_arch = "x86_64")]
use crate::hv::Coco;
use crate::hv::{Kvm, Result, error};
use crate::sys::kvm::{
KVM_CPUID_FEATURES, KVM_MAX_CPUID_ENTRIES, KvmCap, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2,
KvmCpuidFeature, KvmX2apicApiFlag, kvm_get_supported_cpuid,
};
impl From<KvmCpuidEntry2> for (CpuidIn, CpuidResult) {
fn from(value: KvmCpuidEntry2) -> Self {
let in_ = CpuidIn {
func: value.function,
index: if value.flags.contains(KvmCpuid2Flag::SIGNIFCANT_INDEX) {
Some(value.index)
} else {
None
},
};
let result = CpuidResult {
eax: value.eax,
ebx: value.ebx,
ecx: value.ecx,
edx: value.edx,
};
(in_, result)
}
}
impl Kvm {
pub fn get_supported_cpuids(
&self,
coco: Option<&Coco>,
) -> Result<HashMap<CpuidIn, CpuidResult>> {
let mut kvm_cpuid2 = KvmCpuid2 {
nent: KVM_MAX_CPUID_ENTRIES as u32,
padding: 0,
entries: [KvmCpuidEntry2::default(); KVM_MAX_CPUID_ENTRIES],
};
unsafe { kvm_get_supported_cpuid(&self.fd, &mut kvm_cpuid2) }.context(error::GuestCpuid)?;
let mut cpuids: HashMap<_, _> = kvm_cpuid2
.entries
.into_iter()
.filter(|e| e.eax != 0 || e.ebx != 0 || e.ecx != 0 || e.edx != 0)
.take(kvm_cpuid2.nent as usize)
.map(From::from)
.collect();
let leaf_features = CpuidIn {
func: KVM_CPUID_FEATURES,
index: None,
};
if let Some(entry) = cpuids.get_mut(&leaf_features) {
if let Ok(ext) = self.check_extension(KvmCap::X2APIC_API)
&& KvmX2apicApiFlag::from_bits_retain(ext.get() as u64).contains(
KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK,
)
{
entry.eax |= KvmCpuidFeature::MSI_EXT_DEST_ID.bits();
}
if matches!(coco, Some(Coco::IntelTdx { .. })) {
entry.eax &= tdx::SUPPORTED_KVM_FEATURES;
}
}
Ok(cpuids)
}
}
#[cfg(test)]
#[path = "kvm_x86_64_test.rs"]
mod tests;