xref: /cloud-hypervisor/hypervisor/src/lib.rs (revision d90fa96bb70492dfa8cf7419120dab5051e768ed)
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 
11 //! A generic abstraction around hypervisor functionality
12 //!
13 //! This crate offers a trait abstraction for underlying hypervisors
14 //!
15 //! # Platform support
16 //!
17 //! - x86_64
18 //! - arm64
19 //!
20 
21 #[macro_use]
22 extern crate anyhow;
23 #[allow(unused_imports)]
24 #[macro_use]
25 extern crate log;
26 
27 /// Architecture specific definitions
28 #[macro_use]
29 pub mod arch;
30 
31 #[cfg(feature = "kvm")]
32 /// KVM implementation module
33 pub mod kvm;
34 
35 /// Microsoft Hypervisor implementation module
36 #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
37 pub mod mshv;
38 
39 /// Hypervisor related module
40 mod hypervisor;
41 
42 /// Vm related module
43 mod vm;
44 
45 /// CPU related module
46 mod cpu;
47 
48 /// Device related module
49 mod device;
50 
51 pub use crate::hypervisor::{Hypervisor, HypervisorError};
52 use concat_idents::concat_idents;
53 #[cfg(target_arch = "x86_64")]
54 pub use cpu::CpuVendor;
55 pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
56 pub use device::HypervisorDeviceError;
57 #[cfg(all(feature = "kvm", target_arch = "aarch64"))]
58 pub use kvm::{aarch64, GicState};
59 use std::sync::Arc;
60 pub use vm::{
61     DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
62     Vm, VmOps,
63 };
64 
65 #[derive(Debug, Copy, Clone)]
66 pub enum HypervisorType {
67     #[cfg(feature = "kvm")]
68     Kvm,
69     #[cfg(feature = "mshv")]
70     Mshv,
71 }
72 
73 pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
74     #[cfg(feature = "kvm")]
75     if kvm::KvmHypervisor::is_available()? {
76         return kvm::KvmHypervisor::new();
77     }
78 
79     #[cfg(feature = "mshv")]
80     if mshv::MshvHypervisor::is_available()? {
81         return mshv::MshvHypervisor::new();
82     }
83 
84     Err(HypervisorError::HypervisorCreate(anyhow!(
85         "no supported hypervisor"
86     )))
87 }
88 
89 // Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
90 fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
91     let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
92     let mut v = Vec::with_capacity(rounded_size);
93     v.resize_with(rounded_size, T::default);
94     v
95 }
96 
97 // The kvm API has many structs that resemble the following `Foo` structure:
98 //
99 // ```
100 // #[repr(C)]
101 // struct Foo {
102 //    some_data: u32
103 //    entries: __IncompleteArrayField<__u32>,
104 // }
105 // ```
106 //
107 // In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not
108 // include any space for `entries`. To make the allocation large enough while still being aligned
109 // for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used
110 // as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous
111 // with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries.
112 use std::mem::size_of;
113 pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
114     let element_space = count * size_of::<F>();
115     let vec_size_bytes = size_of::<T>() + element_space;
116     vec_with_size_in_bytes(vec_size_bytes)
117 }
118 
119 ///
120 /// User memory region structure
121 ///
122 #[derive(Debug, Default, Eq, PartialEq)]
123 pub struct UserMemoryRegion {
124     pub slot: u32,
125     pub guest_phys_addr: u64,
126     pub memory_size: u64,
127     pub userspace_addr: u64,
128     pub flags: u32,
129 }
130 
131 ///
132 /// Flags for user memory region
133 ///
134 pub const USER_MEMORY_REGION_READ: u32 = 1;
135 pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
136 pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
137 pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
138 pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
139 
140 #[derive(Debug)]
141 pub enum MpState {
142     #[cfg(feature = "kvm")]
143     Kvm(kvm_bindings::kvm_mp_state),
144     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
145     Mshv, /* MSHV does not support MpState yet */
146 }
147 
148 #[derive(Debug, Clone, Copy)]
149 pub enum IoEventAddress {
150     Pio(u64),
151     Mmio(u64),
152 }
153 
154 #[derive(Clone, serde::Serialize, serde::Deserialize)]
155 #[allow(clippy::large_enum_variant)]
156 pub enum CpuState {
157     #[cfg(feature = "kvm")]
158     Kvm(kvm::VcpuKvmState),
159     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
160     Mshv(mshv::VcpuMshvState),
161 }
162 
163 #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
164 #[cfg(target_arch = "x86_64")]
165 pub enum ClockData {
166     #[cfg(feature = "kvm")]
167     Kvm(kvm_bindings::kvm_clock_data),
168     #[cfg(feature = "mshv")]
169     Mshv(mshv::MshvClockData),
170 }
171 
172 #[cfg(target_arch = "x86_64")]
173 impl ClockData {
174     pub fn reset_flags(&mut self) {
175         match self {
176             #[cfg(feature = "kvm")]
177             ClockData::Kvm(s) => s.flags = 0,
178             #[allow(unreachable_patterns)]
179             _ => {}
180         }
181     }
182 }
183 
184 #[derive(Copy, Clone)]
185 pub enum IrqRoutingEntry {
186     #[cfg(feature = "kvm")]
187     Kvm(kvm_bindings::kvm_irq_routing_entry),
188     #[cfg(feature = "mshv")]
189     Mshv(mshv_bindings::mshv_user_irq_entry),
190 }
191 
192 #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
193 pub enum StandardRegisters {
194     #[cfg(feature = "kvm")]
195     Kvm(kvm_bindings::kvm_regs),
196     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
197     Mshv(mshv_bindings::StandardRegisters),
198 }
199 
200 macro_rules! set_x86_64_reg {
201     ($reg_name:ident) => {
202         concat_idents!(method_name = "set_", $reg_name {
203             #[cfg(target_arch = "x86_64")]
204             impl StandardRegisters {
205                 pub fn method_name(&mut self, val: u64) {
206                     match self {
207                         #[cfg(feature = "kvm")]
208                         StandardRegisters::Kvm(s) => s.$reg_name = val,
209                         #[cfg(feature = "mshv")]
210                         StandardRegisters::Mshv(s) => s.$reg_name = val,
211                     }
212                 }
213             }
214         });
215     }
216 }
217 
218 macro_rules! get_x86_64_reg {
219     ($reg_name:ident) => {
220         concat_idents!(method_name = "get_", $reg_name {
221             #[cfg(target_arch = "x86_64")]
222             impl StandardRegisters {
223                 pub fn method_name(&self) -> u64 {
224                     match self {
225                         #[cfg(feature = "kvm")]
226                         StandardRegisters::Kvm(s) => s.$reg_name,
227                         #[cfg(feature = "mshv")]
228                         StandardRegisters::Mshv(s) => s.$reg_name,
229                     }
230                 }
231             }
232         });
233     }
234 }
235 
236 set_x86_64_reg!(rax);
237 set_x86_64_reg!(rbx);
238 set_x86_64_reg!(rcx);
239 set_x86_64_reg!(rdx);
240 set_x86_64_reg!(rsi);
241 set_x86_64_reg!(rdi);
242 set_x86_64_reg!(rsp);
243 set_x86_64_reg!(rbp);
244 set_x86_64_reg!(r8);
245 set_x86_64_reg!(r9);
246 set_x86_64_reg!(r10);
247 set_x86_64_reg!(r11);
248 set_x86_64_reg!(r12);
249 set_x86_64_reg!(r13);
250 set_x86_64_reg!(r14);
251 set_x86_64_reg!(r15);
252 set_x86_64_reg!(rip);
253 set_x86_64_reg!(rflags);
254 
255 get_x86_64_reg!(rax);
256 get_x86_64_reg!(rbx);
257 get_x86_64_reg!(rcx);
258 get_x86_64_reg!(rdx);
259 get_x86_64_reg!(rsi);
260 get_x86_64_reg!(rdi);
261 get_x86_64_reg!(rsp);
262 get_x86_64_reg!(rbp);
263 get_x86_64_reg!(r8);
264 get_x86_64_reg!(r9);
265 get_x86_64_reg!(r10);
266 get_x86_64_reg!(r11);
267 get_x86_64_reg!(r12);
268 get_x86_64_reg!(r13);
269 get_x86_64_reg!(r14);
270 get_x86_64_reg!(r15);
271 get_x86_64_reg!(rip);
272 get_x86_64_reg!(rflags);
273 
274 macro_rules! set_aarch64_reg {
275     ($reg_name:ident, $type:ty) => {
276         concat_idents!(method_name = "set_", $reg_name {
277             #[cfg(target_arch = "aarch64")]
278             impl StandardRegisters {
279                 pub fn method_name(&mut self, val: $type) {
280                     match self {
281                         #[cfg(feature = "kvm")]
282                         StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
283                     }
284                 }
285             }
286         });
287     }
288 }
289 
290 macro_rules! get_aarch64_reg {
291     ($reg_name:ident, $type:ty) => {
292         concat_idents!(method_name = "get_", $reg_name {
293             #[cfg(target_arch = "aarch64")]
294             impl StandardRegisters {
295                 pub fn method_name(&self) -> $type {
296                     match self {
297                         #[cfg(feature = "kvm")]
298                         StandardRegisters::Kvm(s) => s.regs.$reg_name,
299                     }
300                 }
301             }
302         });
303     }
304 }
305 
306 set_aarch64_reg!(regs, [u64; 31usize]);
307 set_aarch64_reg!(sp, u64);
308 set_aarch64_reg!(pc, u64);
309 set_aarch64_reg!(pstate, u64);
310 
311 get_aarch64_reg!(regs, [u64; 31usize]);
312 get_aarch64_reg!(sp, u64);
313 get_aarch64_reg!(pc, u64);
314 get_aarch64_reg!(pstate, u64);
315