kvm_x86_64.rs28.57%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
pub(crate) mod sev;16
pub(crate) mod tdx;17
18
use std::arch::x86_64::CpuidResult;19
use std::collections::HashMap;20
21
use snafu::ResultExt;22
23
use crate::arch::cpuid::CpuidIn;24
#[cfg(target_arch = "x86_64")]25
use crate::hv::Coco;26
use crate::hv::{Kvm, Result, error};27
use crate::sys::kvm::{28
KVM_CPUID_FEATURES, KVM_MAX_CPUID_ENTRIES, KvmCap, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2,29
KvmCpuidFeature, KvmX2apicApiFlag, kvm_get_supported_cpuid,30
};31
32
impl From<KvmCpuidEntry2> for (CpuidIn, CpuidResult) {33
fn from(value: KvmCpuidEntry2) -> Self {2x34
let in_ = CpuidIn {2x35
func: value.function,2x36
index: if value.flags.contains(KvmCpuid2Flag::SIGNIFCANT_INDEX) {2x37
Some(value.index)1x38
} else {39
None1x40
},41
};42
let result = CpuidResult {2x43
eax: value.eax,2x44
ebx: value.ebx,2x45
ecx: value.ecx,2x46
edx: value.edx,2x47
};2x48
(in_, result)2x49
}2x50
}51
52
impl Kvm {53
pub fn get_supported_cpuids(54
&self,55
coco: Option<&Coco>,56
) -> Result<HashMap<CpuidIn, CpuidResult>> {57
let mut kvm_cpuid2 = KvmCpuid2 {58
nent: KVM_MAX_CPUID_ENTRIES as u32,59
padding: 0,60
entries: [KvmCpuidEntry2::default(); KVM_MAX_CPUID_ENTRIES],61
};62
unsafe { kvm_get_supported_cpuid(&self.fd, &mut kvm_cpuid2) }.context(error::GuestCpuid)?;63
let mut cpuids: HashMap<_, _> = kvm_cpuid264
.entries65
.into_iter()66
.filter(|e| e.eax != 0 || e.ebx != 0 || e.ecx != 0 || e.edx != 0)67
.take(kvm_cpuid2.nent as usize)68
.map(From::from)69
.collect();70
71
let leaf_features = CpuidIn {72
func: KVM_CPUID_FEATURES,73
index: None,74
};75
if let Some(entry) = cpuids.get_mut(&leaf_features) {76
if let Ok(ext) = self.check_extension(KvmCap::X2APIC_API)77
&& KvmX2apicApiFlag::from_bits_retain(ext.get() as u64).contains(78
KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK,79
)80
{81
// Enable KVM_FEATURE_MSI_EXT_DEST_ID if KVM_CAP_X2APIC_API is supported82
entry.eax |= KvmCpuidFeature::MSI_EXT_DEST_ID.bits();83
}84
if matches!(coco, Some(Coco::IntelTdx { .. })) {85
entry.eax &= tdx::SUPPORTED_KVM_FEATURES;86
}87
}88
89
Ok(cpuids)90
}91
}92
93
#[cfg(test)]94
#[path = "kvm_x86_64_test.rs"]95
mod tests;96