xref: /cloud-hypervisor/hypervisor/src/lib.rs (revision eeae63b4595fbf0cc69f62b6e9d9a79c543c4ac7)
1 // Copyright © 2024 Institute of Software, CAS. All rights reserved.
2 //
3 // Copyright © 2019 Intel Corporation
4 //
5 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
6 //
7 // Copyright © 2020, Microsoft Corporation
8 //
9 // Copyright 2018-2019 CrowdStrike, Inc.
10 //
11 //
12 
13 //! A generic abstraction around hypervisor functionality
14 //!
15 //! This crate offers a trait abstraction for underlying hypervisors
16 //!
17 //! # Platform support
18 //!
19 //! - x86_64
20 //! - arm64
21 //! - riscv64 (experimental)
22 //!
23 
24 #[macro_use]
25 extern crate anyhow;
26 #[allow(unused_imports)]
27 #[macro_use]
28 extern crate log;
29 
30 /// Architecture specific definitions
31 #[macro_use]
32 pub mod arch;
33 
34 #[cfg(feature = "kvm")]
35 /// KVM implementation module
36 pub mod kvm;
37 
38 /// Microsoft Hypervisor implementation module
39 #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
40 pub mod mshv;
41 
42 /// Hypervisor related module
43 mod hypervisor;
44 
45 /// Vm related module
46 mod vm;
47 
48 /// CPU related module
49 mod cpu;
50 
51 /// Device related module
52 mod device;
53 
54 use std::sync::Arc;
55 
56 use concat_idents::concat_idents;
57 #[cfg(target_arch = "x86_64")]
58 pub use cpu::CpuVendor;
59 pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
60 pub use device::HypervisorDeviceError;
61 #[cfg(all(feature = "kvm", target_arch = "aarch64"))]
62 pub use kvm::{aarch64, GicState};
63 #[cfg(all(feature = "kvm", target_arch = "riscv64"))]
64 pub use kvm::{riscv64, AiaState};
65 pub use vm::{
66     DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
67     Vm, VmOps,
68 };
69 
70 pub use crate::hypervisor::{Hypervisor, HypervisorError};
71 
72 #[derive(Debug, Copy, Clone)]
73 pub enum HypervisorType {
74     #[cfg(feature = "kvm")]
75     Kvm,
76     #[cfg(feature = "mshv")]
77     Mshv,
78 }
79 
80 pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
81     #[cfg(feature = "kvm")]
82     if kvm::KvmHypervisor::is_available()? {
83         return kvm::KvmHypervisor::new();
84     }
85 
86     #[cfg(feature = "mshv")]
87     if mshv::MshvHypervisor::is_available()? {
88         return mshv::MshvHypervisor::new();
89     }
90 
91     Err(HypervisorError::HypervisorCreate(anyhow!(
92         "no supported hypervisor"
93     )))
94 }
95 
96 // Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
97 fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
98     let rounded_size = size_in_bytes.div_ceil(size_of::<T>());
99     let mut v = Vec::with_capacity(rounded_size);
100     v.resize_with(rounded_size, T::default);
101     v
102 }
103 
104 // The kvm API has many structs that resemble the following `Foo` structure:
105 //
106 // ```
107 // #[repr(C)]
108 // struct Foo {
109 //    some_data: u32
110 //    entries: __IncompleteArrayField<__u32>,
111 // }
112 // ```
113 //
114 // In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not
115 // include any space for `entries`. To make the allocation large enough while still being aligned
116 // for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used
117 // as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous
118 // with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries.
119 use std::mem::size_of;
120 pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
121     let element_space = count * size_of::<F>();
122     let vec_size_bytes = size_of::<T>() + element_space;
123     vec_with_size_in_bytes(vec_size_bytes)
124 }
125 
126 ///
127 /// User memory region structure
128 ///
129 #[derive(Debug, Default, Eq, PartialEq)]
130 pub struct UserMemoryRegion {
131     pub slot: u32,
132     pub guest_phys_addr: u64,
133     pub memory_size: u64,
134     pub userspace_addr: u64,
135     pub flags: u32,
136 }
137 
138 ///
139 /// Flags for user memory region
140 ///
141 pub const USER_MEMORY_REGION_READ: u32 = 1;
142 pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
143 pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
144 pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
145 pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
146 
147 #[derive(Debug)]
148 pub enum MpState {
149     #[cfg(feature = "kvm")]
150     Kvm(kvm_bindings::kvm_mp_state),
151     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
152     Mshv, /* MSHV does not support MpState yet */
153 }
154 
155 #[derive(Debug, Clone, Copy)]
156 pub enum IoEventAddress {
157     Pio(u64),
158     Mmio(u64),
159 }
160 
161 #[derive(Clone, serde::Serialize, serde::Deserialize)]
162 #[allow(clippy::large_enum_variant)]
163 pub enum CpuState {
164     #[cfg(feature = "kvm")]
165     Kvm(kvm::VcpuKvmState),
166     #[cfg(all(feature = "mshv", target_arch = "x86_64"))]
167     Mshv(mshv::VcpuMshvState),
168 }
169 
170 #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
171 #[cfg(target_arch = "x86_64")]
172 pub enum ClockData {
173     #[cfg(feature = "kvm")]
174     Kvm(kvm_bindings::kvm_clock_data),
175     #[cfg(feature = "mshv")]
176     Mshv(mshv::MshvClockData),
177 }
178 
179 #[cfg(target_arch = "x86_64")]
180 impl ClockData {
181     pub fn reset_flags(&mut self) {
182         match self {
183             #[cfg(feature = "kvm")]
184             ClockData::Kvm(s) => s.flags = 0,
185             #[allow(unreachable_patterns)]
186             _ => {}
187         }
188     }
189 }
190 
191 #[derive(Copy, Clone)]
192 pub enum IrqRoutingEntry {
193     #[cfg(feature = "kvm")]
194     Kvm(kvm_bindings::kvm_irq_routing_entry),
195     #[cfg(feature = "mshv")]
196     Mshv(mshv_bindings::mshv_user_irq_entry),
197 }
198 
199 #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
200 pub enum StandardRegisters {
201     #[cfg(all(feature = "kvm", not(target_arch = "riscv64")))]
202     Kvm(kvm_bindings::kvm_regs),
203     #[cfg(all(feature = "kvm", target_arch = "riscv64"))]
204     Kvm(kvm_bindings::kvm_riscv_core),
205     #[cfg(all(
206         any(feature = "mshv", feature = "mshv_emulator"),
207         target_arch = "x86_64"
208     ))]
209     Mshv(mshv_bindings::StandardRegisters),
210 }
211 
212 macro_rules! set_x86_64_reg {
213     ($reg_name:ident) => {
214         concat_idents!(method_name = "set_", $reg_name {
215             #[cfg(target_arch = "x86_64")]
216             impl StandardRegisters {
217                 pub fn method_name(&mut self, val: u64) {
218                     match self {
219                         #[cfg(feature = "kvm")]
220                         StandardRegisters::Kvm(s) => s.$reg_name = val,
221                         #[cfg(any(feature = "mshv", feature = "mshv_emulator"))]
222                         StandardRegisters::Mshv(s) => s.$reg_name = val,
223                     }
224                 }
225             }
226         });
227     }
228 }
229 
230 macro_rules! get_x86_64_reg {
231     ($reg_name:ident) => {
232         concat_idents!(method_name = "get_", $reg_name {
233             #[cfg(target_arch = "x86_64")]
234             impl StandardRegisters {
235                 pub fn method_name(&self) -> u64 {
236                     match self {
237                         #[cfg(feature = "kvm")]
238                         StandardRegisters::Kvm(s) => s.$reg_name,
239                         #[cfg(any(feature = "mshv", feature = "mshv_emulator"))]
240                         StandardRegisters::Mshv(s) => s.$reg_name,
241                     }
242                 }
243             }
244         });
245     }
246 }
247 
248 set_x86_64_reg!(rax);
249 set_x86_64_reg!(rbx);
250 set_x86_64_reg!(rcx);
251 set_x86_64_reg!(rdx);
252 set_x86_64_reg!(rsi);
253 set_x86_64_reg!(rdi);
254 set_x86_64_reg!(rsp);
255 set_x86_64_reg!(rbp);
256 set_x86_64_reg!(r8);
257 set_x86_64_reg!(r9);
258 set_x86_64_reg!(r10);
259 set_x86_64_reg!(r11);
260 set_x86_64_reg!(r12);
261 set_x86_64_reg!(r13);
262 set_x86_64_reg!(r14);
263 set_x86_64_reg!(r15);
264 set_x86_64_reg!(rip);
265 set_x86_64_reg!(rflags);
266 
267 get_x86_64_reg!(rax);
268 get_x86_64_reg!(rbx);
269 get_x86_64_reg!(rcx);
270 get_x86_64_reg!(rdx);
271 get_x86_64_reg!(rsi);
272 get_x86_64_reg!(rdi);
273 get_x86_64_reg!(rsp);
274 get_x86_64_reg!(rbp);
275 get_x86_64_reg!(r8);
276 get_x86_64_reg!(r9);
277 get_x86_64_reg!(r10);
278 get_x86_64_reg!(r11);
279 get_x86_64_reg!(r12);
280 get_x86_64_reg!(r13);
281 get_x86_64_reg!(r14);
282 get_x86_64_reg!(r15);
283 get_x86_64_reg!(rip);
284 get_x86_64_reg!(rflags);
285 
286 macro_rules! set_aarch64_reg {
287     ($reg_name:ident, $type:ty) => {
288         concat_idents!(method_name = "set_", $reg_name {
289             #[cfg(target_arch = "aarch64")]
290             impl StandardRegisters {
291                 pub fn method_name(&mut self, val: $type) {
292                     match self {
293                         #[cfg(feature = "kvm")]
294                         StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
295                     }
296                 }
297             }
298         });
299     }
300 }
301 
302 macro_rules! get_aarch64_reg {
303     ($reg_name:ident, $type:ty) => {
304         concat_idents!(method_name = "get_", $reg_name {
305             #[cfg(target_arch = "aarch64")]
306             impl StandardRegisters {
307                 pub fn method_name(&self) -> $type {
308                     match self {
309                         #[cfg(feature = "kvm")]
310                         StandardRegisters::Kvm(s) => s.regs.$reg_name,
311                     }
312                 }
313             }
314         });
315     }
316 }
317 
318 set_aarch64_reg!(regs, [u64; 31usize]);
319 set_aarch64_reg!(sp, u64);
320 set_aarch64_reg!(pc, u64);
321 set_aarch64_reg!(pstate, u64);
322 
323 get_aarch64_reg!(regs, [u64; 31usize]);
324 get_aarch64_reg!(sp, u64);
325 get_aarch64_reg!(pc, u64);
326 get_aarch64_reg!(pstate, u64);
327 
328 macro_rules! set_riscv64_reg {
329     (mode) => {
330         #[cfg(target_arch = "riscv64")]
331         impl StandardRegisters {
332             pub fn set_mode(&mut self, val: u64) {
333                 match self {
334                     #[cfg(feature = "kvm")]
335                     StandardRegisters::Kvm(s) => s.mode = val,
336                 }
337             }
338         }
339     };
340     ($reg_name:ident) => {
341         concat_idents!(method_name = "set_", $reg_name {
342             #[cfg(target_arch = "riscv64")]
343             impl StandardRegisters {
344                 pub fn method_name(&mut self, val: u64) {
345                     match self {
346                         #[cfg(feature = "kvm")]
347                         StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
348                     }
349                 }
350             }
351         });
352     }
353 }
354 
355 macro_rules! get_riscv64_reg {
356     (mode) => {
357         #[cfg(target_arch = "riscv64")]
358         impl StandardRegisters {
359             pub fn get_mode(&self) -> u64 {
360                 match self {
361                     #[cfg(feature = "kvm")]
362                     StandardRegisters::Kvm(s) => s.mode,
363                 }
364             }
365         }
366     };
367     ($reg_name:ident) => {
368         concat_idents!(method_name = "get_", $reg_name {
369             #[cfg(target_arch = "riscv64")]
370             impl StandardRegisters {
371                 pub fn method_name(&self) -> u64 {
372                     match self {
373                         #[cfg(feature = "kvm")]
374                         StandardRegisters::Kvm(s) => s.regs.$reg_name,
375                     }
376                 }
377             }
378         });
379     }
380 }
381 
382 set_riscv64_reg!(pc);
383 set_riscv64_reg!(ra);
384 set_riscv64_reg!(sp);
385 set_riscv64_reg!(gp);
386 set_riscv64_reg!(tp);
387 set_riscv64_reg!(t0);
388 set_riscv64_reg!(t1);
389 set_riscv64_reg!(t2);
390 set_riscv64_reg!(s0);
391 set_riscv64_reg!(s1);
392 set_riscv64_reg!(a0);
393 set_riscv64_reg!(a1);
394 set_riscv64_reg!(a2);
395 set_riscv64_reg!(a3);
396 set_riscv64_reg!(a4);
397 set_riscv64_reg!(a5);
398 set_riscv64_reg!(a6);
399 set_riscv64_reg!(a7);
400 set_riscv64_reg!(s2);
401 set_riscv64_reg!(s3);
402 set_riscv64_reg!(s4);
403 set_riscv64_reg!(s5);
404 set_riscv64_reg!(s6);
405 set_riscv64_reg!(s7);
406 set_riscv64_reg!(s8);
407 set_riscv64_reg!(s9);
408 set_riscv64_reg!(s10);
409 set_riscv64_reg!(s11);
410 set_riscv64_reg!(t3);
411 set_riscv64_reg!(t4);
412 set_riscv64_reg!(t5);
413 set_riscv64_reg!(t6);
414 set_riscv64_reg!(mode);
415 
416 get_riscv64_reg!(pc);
417 get_riscv64_reg!(ra);
418 get_riscv64_reg!(sp);
419 get_riscv64_reg!(gp);
420 get_riscv64_reg!(tp);
421 get_riscv64_reg!(t0);
422 get_riscv64_reg!(t1);
423 get_riscv64_reg!(t2);
424 get_riscv64_reg!(s0);
425 get_riscv64_reg!(s1);
426 get_riscv64_reg!(a0);
427 get_riscv64_reg!(a1);
428 get_riscv64_reg!(a2);
429 get_riscv64_reg!(a3);
430 get_riscv64_reg!(a4);
431 get_riscv64_reg!(a5);
432 get_riscv64_reg!(a6);
433 get_riscv64_reg!(a7);
434 get_riscv64_reg!(s2);
435 get_riscv64_reg!(s3);
436 get_riscv64_reg!(s4);
437 get_riscv64_reg!(s5);
438 get_riscv64_reg!(s6);
439 get_riscv64_reg!(s7);
440 get_riscv64_reg!(s8);
441 get_riscv64_reg!(s9);
442 get_riscv64_reg!(s10);
443 get_riscv64_reg!(s11);
444 get_riscv64_reg!(t3);
445 get_riscv64_reg!(t4);
446 get_riscv64_reg!(t5);
447 get_riscv64_reg!(t6);
448 get_riscv64_reg!(mode);
449