mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
CPU profiles will describe a list of MSRs they require when applying the profile we want to check that the host has all the required MSRs otherwise we have an incompatibility issue. In order to check which MSRs the host supports we start by exposing the hypervisor's get_msr_index_list method. The MSRs required by a chosen CPU profile will be checked against the output of the get_msr_index_list and get_feature_msrs on the hypervisor in a follow up commit. The get_msr_index_list method does not have an obvious implementation for MSHV, because in that case one needs to obtain MSR indices from the VM fd, after the VM has been initialized. Since CPU profiles are only intended for the KVM hypervisor to begin with, we leave the MSHV implementation as unimplemented for now. A proper solution for MSHV should rather be found if/when CPU profiles are also desired in that context. Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de> On-behalf-of: SAP oliver.anderson@sap.com
219 lines
6.5 KiB
Rust
219 lines
6.5 KiB
Rust
// Copyright © 2019 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
|
//
|
|
// Copyright © 2020, Microsoft Corporation
|
|
//
|
|
// Copyright 2018-2019 CrowdStrike, Inc.
|
|
//
|
|
//
|
|
#[cfg(target_arch = "x86_64")]
|
|
use std::arch::x86_64;
|
|
use std::result;
|
|
use std::sync::Arc;
|
|
|
|
use thiserror::Error;
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
use crate::arch::x86::{
|
|
AmxGuestSupportError, CpuIdEntry, MsrEntry, amx_supported, request_guest_amx_support,
|
|
};
|
|
#[cfg(target_arch = "x86_64")]
|
|
use crate::cpu::CpuVendor;
|
|
#[cfg(feature = "tdx")]
|
|
use crate::kvm::TdxCapabilities;
|
|
use crate::vm::Vm;
|
|
use crate::{HypervisorType, HypervisorVmConfig};
|
|
|
|
#[derive(Error, Debug)]
|
|
pub enum HypervisorError {
|
|
///
|
|
/// Hypervisor availability check error
|
|
///
|
|
#[error("Failed to check availability of the hypervisor")]
|
|
HypervisorAvailableCheck(#[source] anyhow::Error),
|
|
///
|
|
/// hypervisor creation error
|
|
///
|
|
#[error("Failed to create the hypervisor")]
|
|
HypervisorCreate(#[source] anyhow::Error),
|
|
///
|
|
/// Vm creation failure
|
|
///
|
|
#[error("Failed to create Vm")]
|
|
VmCreate(#[source] anyhow::Error),
|
|
///
|
|
/// Vm setup failure
|
|
///
|
|
#[error("Failed to setup Vm")]
|
|
VmSetup(#[source] anyhow::Error),
|
|
///
|
|
/// API version error
|
|
///
|
|
#[error("Failed to get API Version")]
|
|
GetApiVersion(#[source] anyhow::Error),
|
|
///
|
|
/// CpuId error
|
|
///
|
|
#[error("Failed to get cpuid")]
|
|
GetCpuId(#[source] anyhow::Error),
|
|
///
|
|
/// Failed to retrieve list of MSRs.
|
|
///
|
|
#[error("Failed to get the list of supported MSRs")]
|
|
GetMsrList(#[source] anyhow::Error),
|
|
///
|
|
/// API version is not compatible
|
|
///
|
|
#[error("Incompatible API version")]
|
|
IncompatibleApiVersion,
|
|
///
|
|
/// Checking extensions failed
|
|
///
|
|
#[error("Checking extensions")]
|
|
CheckExtensions(#[source] anyhow::Error),
|
|
///
|
|
/// Failed to retrieve TDX capabilities
|
|
///
|
|
#[error("Failed to retrieve TDX capabilities")]
|
|
TdxCapabilities(#[source] anyhow::Error),
|
|
///
|
|
/// Failed to set partition property
|
|
///
|
|
#[error("Failed to set partition property")]
|
|
SetPartitionProperty(#[source] anyhow::Error),
|
|
///
|
|
/// Running on an unsupported CPU
|
|
///
|
|
#[error("Unsupported CPU")]
|
|
UnsupportedCpu(#[source] anyhow::Error),
|
|
///
|
|
/// Launching a VM with unsupported VM Type
|
|
///
|
|
#[error("Unsupported VmType")]
|
|
UnsupportedVmType(),
|
|
|
|
///
|
|
/// The attempt to enable AMX tile state components failed
|
|
///
|
|
#[cfg(target_arch = "x86_64")]
|
|
#[error("Failed to enable AMX tile state components")]
|
|
CouldNotEnableAmxStateComponents(#[source] AmxGuestSupportError),
|
|
///
|
|
/// Failed to retrieve SEV-SNP capabilities
|
|
///
|
|
#[error("Failed to retrieve SEV-SNP capabilities:{0}")]
|
|
SevSnpCapabilities(#[source] anyhow::Error),
|
|
///
|
|
/// Unable to read the requested feature MSRs
|
|
///
|
|
#[error("Failed to get feature MSRs")]
|
|
GetFeatureMsrs(#[source] anyhow::Error),
|
|
///
|
|
/// Unable to read all feature MSRs advertised by the Hypervisor
|
|
///
|
|
#[error("Unable to read all feature MSRs")]
|
|
GetFeatureMsrsPartial,
|
|
}
|
|
|
|
///
|
|
/// Result type for returning from a function
|
|
///
|
|
pub type Result<T> = result::Result<T, HypervisorError>;
|
|
|
|
///
|
|
/// Trait to represent a Hypervisor
|
|
///
|
|
/// This crate provides a hypervisor-agnostic interfaces
|
|
///
|
|
pub trait Hypervisor: Send + Sync {
|
|
///
|
|
/// Returns the type of the hypervisor
|
|
///
|
|
fn hypervisor_type(&self) -> HypervisorType;
|
|
///
|
|
/// Create a Vm using the underlying hypervisor
|
|
/// Return a hypervisor-agnostic Vm trait object
|
|
///
|
|
fn create_vm(&self, config: HypervisorVmConfig) -> Result<Arc<dyn Vm>>;
|
|
#[cfg(target_arch = "x86_64")]
|
|
///
|
|
/// Get the supported CpuID
|
|
///
|
|
fn get_supported_cpuid(&self) -> Result<Vec<CpuIdEntry>>;
|
|
#[cfg(target_arch = "x86_64")]
|
|
///
|
|
/// Get feature MSRs supported by the hardware and hypervisor
|
|
///
|
|
fn get_feature_msrs(&self) -> Result<Vec<MsrEntry>>;
|
|
#[cfg(target_arch = "x86_64")]
|
|
///
|
|
/// Get the MSR indices supported by the hardware and hypervisor
|
|
///
|
|
fn get_msr_index_list(&self) -> Result<Vec<u32>>;
|
|
///
|
|
/// Check particular extensions if any
|
|
///
|
|
fn check_required_extensions(&self) -> Result<()> {
|
|
Ok(())
|
|
}
|
|
#[cfg(target_arch = "aarch64")]
|
|
///
|
|
/// Retrieve AArch64 host maximum IPA size supported by KVM
|
|
///
|
|
fn get_host_ipa_limit(&self) -> i32;
|
|
///
|
|
/// Retrieve TDX capabilities
|
|
///
|
|
#[cfg(feature = "tdx")]
|
|
fn tdx_capabilities(&self) -> Result<TdxCapabilities> {
|
|
unimplemented!()
|
|
}
|
|
///
|
|
/// Get the number of supported hardware breakpoints
|
|
///
|
|
fn get_guest_debug_hw_bps(&self) -> usize {
|
|
unimplemented!()
|
|
}
|
|
|
|
/// Get maximum number of vCPUs
|
|
fn get_max_vcpus(&self) -> u32;
|
|
#[cfg(target_arch = "x86_64")]
|
|
///
|
|
/// Determine CPU vendor
|
|
///
|
|
fn get_cpu_vendor(&self) -> CpuVendor {
|
|
#[allow(unused_unsafe)]
|
|
// SAFETY: not actually unsafe, but considered unsafe by current stable
|
|
unsafe {
|
|
let leaf = x86_64::__cpuid(0x0);
|
|
|
|
if leaf.ebx == 0x756e_6547 && leaf.ecx == 0x6c65_746e && leaf.edx == 0x4965_6e69 {
|
|
// Vendor string GenuineIntel
|
|
CpuVendor::Intel
|
|
} else if leaf.ebx == 0x6874_7541 && leaf.ecx == 0x444d_4163 && leaf.edx == 0x6974_6e65
|
|
{
|
|
// Vendor string AuthenticAMD
|
|
CpuVendor::AMD
|
|
} else {
|
|
// Not known yet, the corresponding manufacturer manual should contain the
|
|
// necessary info. See also https://wiki.osdev.org/CPUID#CPU_Vendor_ID_String
|
|
CpuVendor::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// This function enables the AMX related TILECFG and TILEDATA state components for guests.
|
|
///
|
|
/// # Background
|
|
/// AMX uses a concept of tiles which are small 2D blocks of data stored in registers on the CPU,
|
|
/// where the TILECFG state component defines the shape and size of each tile (rows and columns),
|
|
/// and the TILEDATA state component holds the actual elements of these tiles used by matrix operations.
|
|
#[cfg(target_arch = "x86_64")]
|
|
fn enable_amx_state_components(&self) -> Result<()> {
|
|
let cpu_vendor = self.get_cpu_vendor();
|
|
amx_supported(cpu_vendor).map_err(HypervisorError::CouldNotEnableAmxStateComponents)?;
|
|
request_guest_amx_support().map_err(HypervisorError::CouldNotEnableAmxStateComponents)
|
|
}
|
|
}
|