xref: /cloud-hypervisor/hypervisor/src/hypervisor.rs (revision 50bac1694f5bb305f00f02dc257896536eac5e0f)
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 std::arch::x86_64;
12 use std::sync::Arc;
13 
14 use thiserror::Error;
15 
16 #[cfg(target_arch = "x86_64")]
17 use crate::arch::x86::CpuIdEntry;
18 #[cfg(target_arch = "x86_64")]
19 use crate::cpu::CpuVendor;
20 #[cfg(feature = "tdx")]
21 use crate::kvm::TdxCapabilities;
22 use crate::vm::Vm;
23 use crate::HypervisorType;
24 
25 #[derive(Error, Debug)]
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     ///
122     /// Create a Vm of a specific type using the underlying hypervisor, passing memory size
123     /// Return a hypervisor-agnostic Vm trait object
124     ///
125     fn create_vm_with_type_and_memory(
126         &self,
127         _vm_type: u64,
128         #[cfg(feature = "sev_snp")] _mem_size: u64,
129     ) -> Result<Arc<dyn Vm>> {
130         unreachable!()
131     }
132     #[cfg(target_arch = "x86_64")]
133     ///
134     /// Get the supported CpuID
135     ///
136     fn get_supported_cpuid(&self) -> Result<Vec<CpuIdEntry>>;
137     ///
138     /// Check particular extensions if any
139     ///
140     fn check_required_extensions(&self) -> Result<()> {
141         Ok(())
142     }
143     #[cfg(target_arch = "aarch64")]
144     ///
145     /// Retrieve AArch64 host maximum IPA size supported by KVM
146     ///
147     fn get_host_ipa_limit(&self) -> i32;
148     ///
149     /// Retrieve TDX capabilities
150     ///
151     #[cfg(feature = "tdx")]
152     fn tdx_capabilities(&self) -> Result<TdxCapabilities> {
153         unimplemented!()
154     }
155     ///
156     /// Get the number of supported hardware breakpoints
157     ///
158     fn get_guest_debug_hw_bps(&self) -> usize {
159         unimplemented!()
160     }
161 
162     /// Get maximum number of vCPUs
163     fn get_max_vcpus(&self) -> u32;
164     #[cfg(target_arch = "x86_64")]
165     ///
166     /// Determine CPU vendor
167     ///
168     fn get_cpu_vendor(&self) -> CpuVendor {
169         // SAFETY: call cpuid with valid leaves
170         unsafe {
171             let leaf = x86_64::__cpuid(0x0);
172 
173             if leaf.ebx == 0x756e_6547 && leaf.ecx == 0x6c65_746e && leaf.edx == 0x4965_6e69 {
174                 // Vendor string GenuineIntel
175                 CpuVendor::Intel
176             } else if leaf.ebx == 0x6874_7541 && leaf.ecx == 0x444d_4163 && leaf.edx == 0x6974_6e65
177             {
178                 // Vendor string AuthenticAMD
179                 CpuVendor::AMD
180             } else {
181                 // Not known yet, the corresponding manufacturer manual should contain the
182                 // necessary info. See also https://wiki.osdev.org/CPUID#CPU_Vendor_ID_String
183                 CpuVendor::default()
184             }
185         }
186     }
187 }
188