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