Alioth Code Coverage

kvm_x86_64.rs33.33%

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
15use std::arch::x86_64::CpuidResult;
16use std::collections::HashMap;
17
18use snafu::ResultExt;
19
20use crate::arch::cpuid::CpuidIn;
21use crate::hv::{Kvm, Result, error};
22use crate::sys::kvm::{
23 KVM_CPUID_FEATURES, KVM_MAX_CPUID_ENTRIES, KvmCap, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2,
24 KvmCpuidFeature, KvmX2apicApiFlag, kvm_get_supported_cpuid,
25};
26
27impl From<KvmCpuidEntry2> for (CpuidIn, CpuidResult) {
28 fn from(value: KvmCpuidEntry2) -> Self {2x
29 let in_ = CpuidIn {2x
30 func: value.function,2x
31 index: if value.flags.contains(KvmCpuid2Flag::SIGNIFCANT_INDEX) {2x
32 Some(value.index)1x
33 } else {
34 None1x
35 },
36 };
37 let result = CpuidResult {2x
38 eax: value.eax,2x
39 ebx: value.ebx,2x
40 ecx: value.ecx,2x
41 edx: value.edx,2x
42 };2x
43 (in_, result)2x
44 }2x
45}
46
47impl Kvm {
48 pub fn get_supported_cpuids(&self) -> Result<HashMap<CpuidIn, CpuidResult>> {
49 let mut kvm_cpuid2 = KvmCpuid2 {
50 nent: KVM_MAX_CPUID_ENTRIES as u32,
51 padding: 0,
52 entries: [KvmCpuidEntry2::default(); KVM_MAX_CPUID_ENTRIES],
53 };
54 unsafe { kvm_get_supported_cpuid(&self.fd, &mut kvm_cpuid2) }.context(error::GuestCpuid)?;
55 let mut cpuids: HashMap<_, _> = kvm_cpuid2
56 .entries
57 .into_iter()
58 .filter(|e| e.eax != 0 || e.ebx != 0 || e.ecx != 0 || e.edx != 0)
59 .take(kvm_cpuid2.nent as usize)
60 .map(From::from)
61 .collect();
62
63 let leaf_features = CpuidIn {
64 func: KVM_CPUID_FEATURES,
65 index: None,
66 };
67 if let Some(entry) = cpuids.get_mut(&leaf_features)
68 && let Ok(ext) = self.check_extension(KvmCap::X2APIC_API)
69 && KvmX2apicApiFlag::from_bits_retain(ext.get() as u64).contains(
70 KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK,
71 )
72 {
73 // Enable KVM_FEATURE_MSI_EXT_DEST_ID if KVM_CAP_X2APIC_API is supported
74 entry.eax |= KvmCpuidFeature::MSI_EXT_DEST_ID.bits();
75 }
76
77 Ok(cpuids)
78 }
79}
80
81#[cfg(test)]
82#[path = "kvm_x86_64_test.rs"]
83mod tests;
84