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