kvm_x86_64.rs33.33%
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
use std::arch::x86_64::CpuidResult;16
use std::collections::HashMap;17
18
use snafu::ResultExt;19
20
use crate::arch::cpuid::CpuidIn;21
use crate::hv::{Kvm, Result, error};22
use crate::sys::kvm::{23
KVM_CPUID_FEATURES, KVM_MAX_CPUID_ENTRIES, KvmCap, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2,24
KvmCpuidFeature, KvmX2apicApiFlag, kvm_get_supported_cpuid,25
};26
27
impl From<KvmCpuidEntry2> for (CpuidIn, CpuidResult) {28
fn from(value: KvmCpuidEntry2) -> Self {2x29
let in_ = CpuidIn {2x30
func: value.function,2x31
index: if value.flags.contains(KvmCpuid2Flag::SIGNIFCANT_INDEX) {2x32
Some(value.index)1x33
} else {34
None1x35
},36
};37
let result = CpuidResult {2x38
eax: value.eax,2x39
ebx: value.ebx,2x40
ecx: value.ecx,2x41
edx: value.edx,2x42
};2x43
(in_, result)2x44
}2x45
}46
47
impl 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_cpuid256
.entries57
.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 supported74
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"]83
mod tests;84