xref: /cloud-hypervisor/hypervisor/src/lib.rs (revision 3f8cd52ffd74627242cb7e8ea1c2bdedadf6741a)
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 #[cfg(target_arch = "x86_64")]
53 pub use cpu::CpuVendor;
54 pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
55 pub use device::HypervisorDeviceError;
56 #[cfg(all(feature = "kvm", target_arch = "aarch64"))]
57 pub use kvm::{aarch64, GicState};
58 use std::sync::Arc;
59 pub use vm::{
60     DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
61     Vm, VmOps,
62 };
63 
64 #[derive(Debug, Copy, Clone)]
65 pub enum HypervisorType {
66     #[cfg(feature = "kvm")]
67     Kvm,
68     #[cfg(feature = "mshv")]
69     Mshv,
70 }
71 
72 pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
73     #[cfg(feature = "kvm")]
74     if kvm::KvmHypervisor::is_available()? {
75         return kvm::KvmHypervisor::new();
76     }
77 
78     #[cfg(feature = "mshv")]
79     if mshv::MshvHypervisor::is_available()? {
80         return mshv::MshvHypervisor::new();
81     }
82 
83     Err(HypervisorError::HypervisorCreate(anyhow!(
84         "no supported hypervisor"
85     )))
86 }
87 
88 // Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
89 fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
90     let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
91     let mut v = Vec::with_capacity(rounded_size);
92     v.resize_with(rounded_size, T::default);
93     v
94 }
95 
96 // The kvm API has many structs that resemble the following `Foo` structure:
97 //
98 // ```
99 // #[repr(C)]
100 // struct Foo {
101 //    some_data: u32
102 //    entries: __IncompleteArrayField<__u32>,
103 // }
104 // ```
105 //
106 // In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not
107 // include any space for `entries`. To make the allocation large enough while still being aligned
108 // for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used
109 // as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous
110 // with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries.
111 use std::mem::size_of;
112 pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
113     let element_space = count * size_of::<F>();
114     let vec_size_bytes = size_of::<T>() + element_space;
115     vec_with_size_in_bytes(vec_size_bytes)
116 }
117 
118 ///
119 /// User memory region structure
120 ///
121 #[derive(Debug, Default, Eq, PartialEq)]
122 pub struct UserMemoryRegion {
123     pub slot: u32,
124     pub guest_phys_addr: u64,
125     pub memory_size: u64,
126     pub userspace_addr: u64,
127     pub flags: u32,
128 }
129 
130 ///
131 /// Flags for user memory region
132 ///
133 pub const USER_MEMORY_REGION_READ: u32 = 1;
134 pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
135 pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
136 pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
137 pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
138 
139 #[derive(Debug)]
140 pub enum MpState {
141     #[cfg(feature = "kvm")]
142     Kvm(kvm_bindings::kvm_mp_state),
143     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
144     Mshv, /* MSHV does not support MpState yet */
145 }
146 
147 #[derive(Debug, Clone, Copy)]
148 pub enum IoEventAddress {
149     Pio(u64),
150     Mmio(u64),
151 }
152 
153 #[derive(Clone, serde::Serialize, serde::Deserialize)]
154 #[allow(clippy::large_enum_variant)]
155 pub enum CpuState {
156     #[cfg(feature = "kvm")]
157     Kvm(kvm::VcpuKvmState),
158     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
159     Mshv(mshv::VcpuMshvState),
160 }
161 
162 #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
163 #[cfg(target_arch = "x86_64")]
164 pub enum ClockData {
165     #[cfg(feature = "kvm")]
166     Kvm(kvm_bindings::kvm_clock_data),
167     #[cfg(feature = "mshv")]
168     Mshv(mshv::MshvClockData),
169 }
170 
171 #[cfg(target_arch = "x86_64")]
172 impl ClockData {
173     pub fn reset_flags(&mut self) {
174         match self {
175             #[cfg(feature = "kvm")]
176             ClockData::Kvm(s) => s.flags = 0,
177             #[allow(unreachable_patterns)]
178             _ => {}
179         }
180     }
181 }
182 
183 #[derive(Copy, Clone)]
184 pub enum IrqRoutingEntry {
185     #[cfg(feature = "kvm")]
186     Kvm(kvm_bindings::kvm_irq_routing_entry),
187     #[cfg(feature = "mshv")]
188     Mshv(mshv_bindings::mshv_msi_routing_entry),
189 }
190