Alioth Code Coverage

kvm_x86_64.rs28.57%

1// Copyright 2024 Google LLC
2//
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 at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// 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 and
13// limitations under the License.
14
15pub(crate) mod sev;
16pub(crate) mod tdx;
17
18use std::arch::x86_64::CpuidResult;
19use std::collections::HashMap;
20
21use snafu::ResultExt;
22
23use crate::arch::cpuid::CpuidIn;
24#[cfg(target_arch = "x86_64")]
25use crate::hv::Coco;
26use crate::hv::{Kvm, Result, error};
27use crate::sys::kvm::{
28 KVM_CPUID_FEATURES, KVM_MAX_CPUID_ENTRIES, KvmCap, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2,
29 KvmCpuidFeature, KvmX2apicApiFlag, kvm_get_supported_cpuid,
30};
31
32impl From<KvmCpuidEntry2> for (CpuidIn, CpuidResult) {
33 fn from(value: KvmCpuidEntry2) -> Self {2x
34 let in_ = CpuidIn {2x
35 func: value.function,2x
36 index: if value.flags.contains(KvmCpuid2Flag::SIGNIFCANT_INDEX) {2x
37 Some(value.index)1x
38 } else {
39 None1x
40 },
41 };
42 let result = CpuidResult {2x
43 eax: value.eax,2x
44 ebx: value.ebx,2x
45 ecx: value.ecx,2x
46 edx: value.edx,2x
47 };2x
48 (in_, result)2x
49 }2x
50}
51
52impl 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_cpuid2
64 .entries
65 .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 supported
82 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"]
95mod tests;
96