1 // Copyright © 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause 4 // 5 // Copyright © 2020, Microsoft Corporation 6 // 7 // Copyright 2018-2019 CrowdStrike, Inc. 8 // 9 // 10 #[cfg(target_arch = "x86_64")] 11 use crate::arch::x86::CpuIdEntry; 12 #[cfg(target_arch = "x86_64")] 13 use crate::cpu::CpuVendor; 14 #[cfg(feature = "tdx")] 15 use crate::kvm::TdxCapabilities; 16 use crate::vm::Vm; 17 use crate::HypervisorType; 18 #[cfg(target_arch = "x86_64")] 19 use std::arch::x86_64; 20 use std::sync::Arc; 21 use thiserror::Error; 22 23 #[derive(Error, Debug)] 24 pub enum HypervisorError { 25 /// 26 /// Hypervisor availability check error 27 /// 28 #[error("Failed to check availability of the hypervisor: {0}")] 29 HypervisorAvailableCheck(#[source] anyhow::Error), 30 /// 31 /// hypervisor creation error 32 /// 33 #[error("Failed to create the hypervisor: {0}")] 34 HypervisorCreate(#[source] anyhow::Error), 35 /// 36 /// Vm creation failure 37 /// 38 #[error("Failed to create Vm: {0}")] 39 VmCreate(#[source] anyhow::Error), 40 /// 41 /// Vm setup failure 42 /// 43 #[error("Failed to setup Vm: {0}")] 44 VmSetup(#[source] anyhow::Error), 45 /// 46 /// API version error 47 /// 48 #[error("Failed to get API Version: {0}")] 49 GetApiVersion(#[source] anyhow::Error), 50 /// 51 /// CpuId error 52 /// 53 #[error("Failed to get cpuid: {0}")] 54 GetCpuId(#[source] anyhow::Error), 55 /// 56 /// Failed to retrieve list of MSRs. 57 /// 58 #[error("Failed to get the list of supported MSRs: {0}")] 59 GetMsrList(#[source] anyhow::Error), 60 /// 61 /// API version is not compatible 62 /// 63 #[error("Incompatible API version")] 64 IncompatibleApiVersion, 65 /// 66 /// Checking extensions failed 67 /// 68 #[error("Checking extensions:{0}")] 69 CheckExtensions(#[source] anyhow::Error), 70 /// 71 /// Failed to retrieve TDX capabilities 72 /// 73 #[error("Failed to retrieve TDX capabilities:{0}")] 74 TdxCapabilities(#[source] anyhow::Error), 75 /// 76 /// Failed to set partition property 77 /// 78 #[error("Failed to set partition property:{0}")] 79 SetPartitionProperty(#[source] anyhow::Error), 80 /// 81 /// Running on an unsupported CPU 82 /// 83 #[error("Unsupported CPU:{0}")] 84 UnsupportedCpu(#[source] anyhow::Error), 85 /// 86 /// Launching a VM with unsupported VM Type 87 /// 88 #[error("Unsupported VmType")] 89 UnsupportedVmType(), 90 } 91 92 /// 93 /// Result type for returning from a function 94 /// 95 pub type Result<T> = std::result::Result<T, HypervisorError>; 96 97 /// 98 /// Trait to represent a Hypervisor 99 /// 100 /// This crate provides a hypervisor-agnostic interfaces 101 /// 102 pub trait Hypervisor: Send + Sync { 103 /// 104 /// Returns the type of the hypervisor 105 /// 106 fn hypervisor_type(&self) -> HypervisorType; 107 /// 108 /// Create a Vm using the underlying hypervisor 109 /// Return a hypervisor-agnostic Vm trait object 110 /// 111 fn create_vm(&self) -> Result<Arc<dyn Vm>>; 112 /// 113 /// Create a Vm of a specific type using the underlying hypervisor 114 /// Return a hypervisor-agnostic Vm trait object 115 /// 116 fn create_vm_with_type(&self, _vm_type: u64) -> Result<Arc<dyn Vm>> { 117 unreachable!() 118 } 119 #[cfg(target_arch = "x86_64")] 120 /// 121 /// Get the supported CpuID 122 /// 123 fn get_supported_cpuid(&self) -> Result<Vec<CpuIdEntry>>; 124 /// 125 /// Check particular extensions if any 126 /// 127 fn check_required_extensions(&self) -> Result<()> { 128 Ok(()) 129 } 130 #[cfg(target_arch = "aarch64")] 131 /// 132 /// Retrieve AArch64 host maximum IPA size supported by KVM 133 /// 134 fn get_host_ipa_limit(&self) -> i32; 135 /// 136 /// Retrieve TDX capabilities 137 /// 138 #[cfg(feature = "tdx")] 139 fn tdx_capabilities(&self) -> Result<TdxCapabilities> { 140 unimplemented!() 141 } 142 /// 143 /// Get the number of supported hardware breakpoints 144 /// 145 fn get_guest_debug_hw_bps(&self) -> usize { 146 unimplemented!() 147 } 148 149 /// Get maximum number of vCPUs 150 fn get_max_vcpus(&self) -> u32; 151 #[cfg(target_arch = "x86_64")] 152 /// 153 /// Determine CPU vendor 154 /// 155 fn get_cpu_vendor(&self) -> CpuVendor { 156 // SAFETY: call cpuid with valid leaves 157 unsafe { 158 let leaf = x86_64::__cpuid(0x0); 159 160 if leaf.ebx == 0x756e_6547 && leaf.ecx == 0x6c65_746e && leaf.edx == 0x4965_6e69 { 161 // Vendor string GenuineIntel 162 CpuVendor::Intel 163 } else if leaf.ebx == 0x6874_7541 && leaf.ecx == 0x444d_4163 && leaf.edx == 0x6974_6e65 164 { 165 // Vendor string AuthenticAMD 166 CpuVendor::AMD 167 } else { 168 // Not known yet, the corresponding manufacturer manual should contain the 169 // necesssary info. See also https://wiki.osdev.org/CPUID#CPU_Vendor_ID_String 170 CpuVendor::default() 171 } 172 } 173 } 174 } 175