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