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(feature = "mshv")]
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;
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
new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError>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`.
vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T>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;
vec_with_array_field<T: Default, F>(count: usize) -> Vec<T>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(feature = "mshv")]
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(feature = "mshv")]
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 {
reset_flags(&mut self)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 VcpuInit {
201 #[cfg(all(feature = "kvm", target_arch = "aarch64"))]
202 Kvm(kvm_bindings::kvm_vcpu_init),
203 #[cfg(all(feature = "mshv", target_arch = "aarch64"))]
204 Mshv(mshv_bindings::MshvVcpuInit),
205 }
206
207 #[derive(Debug, Clone, PartialEq)]
208 pub enum RegList {
209 #[cfg(all(feature = "kvm", any(target_arch = "aarch64", target_arch = "riscv64")))]
210 Kvm(kvm_bindings::RegList),
211 #[cfg(all(feature = "mshv", target_arch = "aarch64"))]
212 Mshv(mshv_bindings::MshvRegList),
213 }
214
215 pub enum Register {
216 #[cfg(feature = "kvm")]
217 Kvm(kvm_bindings::kvm_one_reg),
218 }
219
220 #[allow(clippy::large_enum_variant)]
221 #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
222 pub enum StandardRegisters {
223 #[cfg(all(feature = "kvm", not(target_arch = "riscv64")))]
224 Kvm(kvm_bindings::kvm_regs),
225 #[cfg(all(feature = "kvm", target_arch = "riscv64"))]
226 Kvm(kvm_bindings::kvm_riscv_core),
227 #[cfg(any(feature = "mshv", feature = "mshv_emulator"))]
228 Mshv(mshv_bindings::StandardRegisters),
229 }
230
231 macro_rules! set_x86_64_reg {
232 ($reg_name:ident) => {
233 concat_idents!(method_name = "set_", $reg_name {
234 #[cfg(target_arch = "x86_64")]
235 impl StandardRegisters {
236 pub fn method_name(&mut self, val: u64) {
237 match self {
238 #[cfg(feature = "kvm")]
239 StandardRegisters::Kvm(s) => s.$reg_name = val,
240 #[cfg(any(feature = "mshv", feature = "mshv_emulator"))]
241 StandardRegisters::Mshv(s) => s.$reg_name = val,
242 }
243 }
244 }
245 });
246 }
247 }
248
249 macro_rules! get_x86_64_reg {
250 ($reg_name:ident) => {
251 concat_idents!(method_name = "get_", $reg_name {
252 #[cfg(target_arch = "x86_64")]
253 impl StandardRegisters {
254 pub fn method_name(&self) -> u64 {
255 match self {
256 #[cfg(feature = "kvm")]
257 StandardRegisters::Kvm(s) => s.$reg_name,
258 #[cfg(any(feature = "mshv", feature = "mshv_emulator"))]
259 StandardRegisters::Mshv(s) => s.$reg_name,
260 }
261 }
262 }
263 });
264 }
265 }
266
267 set_x86_64_reg!(rax);
268 set_x86_64_reg!(rbx);
269 set_x86_64_reg!(rcx);
270 set_x86_64_reg!(rdx);
271 set_x86_64_reg!(rsi);
272 set_x86_64_reg!(rdi);
273 set_x86_64_reg!(rsp);
274 set_x86_64_reg!(rbp);
275 set_x86_64_reg!(r8);
276 set_x86_64_reg!(r9);
277 set_x86_64_reg!(r10);
278 set_x86_64_reg!(r11);
279 set_x86_64_reg!(r12);
280 set_x86_64_reg!(r13);
281 set_x86_64_reg!(r14);
282 set_x86_64_reg!(r15);
283 set_x86_64_reg!(rip);
284 set_x86_64_reg!(rflags);
285
286 get_x86_64_reg!(rax);
287 get_x86_64_reg!(rbx);
288 get_x86_64_reg!(rcx);
289 get_x86_64_reg!(rdx);
290 get_x86_64_reg!(rsi);
291 get_x86_64_reg!(rdi);
292 get_x86_64_reg!(rsp);
293 get_x86_64_reg!(rbp);
294 get_x86_64_reg!(r8);
295 get_x86_64_reg!(r9);
296 get_x86_64_reg!(r10);
297 get_x86_64_reg!(r11);
298 get_x86_64_reg!(r12);
299 get_x86_64_reg!(r13);
300 get_x86_64_reg!(r14);
301 get_x86_64_reg!(r15);
302 get_x86_64_reg!(rip);
303 get_x86_64_reg!(rflags);
304
305 macro_rules! set_aarch64_reg {
306 ($reg_name:ident, $type:ty) => {
307 concat_idents!(method_name = "set_", $reg_name {
308 #[cfg(target_arch = "aarch64")]
309 impl StandardRegisters {
310 pub fn method_name(&mut self, val: $type) {
311 match self {
312 #[cfg(feature = "kvm")]
313 StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
314 #[cfg(feature = "mshv")]
315 StandardRegisters::Mshv(s) => s.$reg_name = val,
316 }
317 }
318 }
319 });
320 }
321 }
322
323 macro_rules! get_aarch64_reg {
324 ($reg_name:ident, $type:ty) => {
325 concat_idents!(method_name = "get_", $reg_name {
326 #[cfg(target_arch = "aarch64")]
327 impl StandardRegisters {
328 pub fn method_name(&self) -> $type {
329 match self {
330 #[cfg(feature = "kvm")]
331 StandardRegisters::Kvm(s) => s.regs.$reg_name,
332 #[cfg(feature = "mshv")]
333 StandardRegisters::Mshv(s) => s.$reg_name,
334 }
335 }
336 }
337 });
338 }
339 }
340
341 set_aarch64_reg!(regs, [u64; 31usize]);
342 set_aarch64_reg!(sp, u64);
343 set_aarch64_reg!(pc, u64);
344 set_aarch64_reg!(pstate, u64);
345
346 get_aarch64_reg!(regs, [u64; 31usize]);
347 get_aarch64_reg!(sp, u64);
348 get_aarch64_reg!(pc, u64);
349 get_aarch64_reg!(pstate, u64);
350
351 macro_rules! set_riscv64_reg {
352 (mode) => {
353 #[cfg(target_arch = "riscv64")]
354 impl StandardRegisters {
355 pub fn set_mode(&mut self, val: u64) {
356 match self {
357 #[cfg(feature = "kvm")]
358 StandardRegisters::Kvm(s) => s.mode = val,
359 }
360 }
361 }
362 };
363 ($reg_name:ident) => {
364 concat_idents!(method_name = "set_", $reg_name {
365 #[cfg(target_arch = "riscv64")]
366 impl StandardRegisters {
367 pub fn method_name(&mut self, val: u64) {
368 match self {
369 #[cfg(feature = "kvm")]
370 StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
371 }
372 }
373 }
374 });
375 }
376 }
377
378 macro_rules! get_riscv64_reg {
379 (mode) => {
380 #[cfg(target_arch = "riscv64")]
381 impl StandardRegisters {
382 pub fn get_mode(&self) -> u64 {
383 match self {
384 #[cfg(feature = "kvm")]
385 StandardRegisters::Kvm(s) => s.mode,
386 }
387 }
388 }
389 };
390 ($reg_name:ident) => {
391 concat_idents!(method_name = "get_", $reg_name {
392 #[cfg(target_arch = "riscv64")]
393 impl StandardRegisters {
394 pub fn method_name(&self) -> u64 {
395 match self {
396 #[cfg(feature = "kvm")]
397 StandardRegisters::Kvm(s) => s.regs.$reg_name,
398 }
399 }
400 }
401 });
402 }
403 }
404
405 set_riscv64_reg!(pc);
406 set_riscv64_reg!(ra);
407 set_riscv64_reg!(sp);
408 set_riscv64_reg!(gp);
409 set_riscv64_reg!(tp);
410 set_riscv64_reg!(t0);
411 set_riscv64_reg!(t1);
412 set_riscv64_reg!(t2);
413 set_riscv64_reg!(s0);
414 set_riscv64_reg!(s1);
415 set_riscv64_reg!(a0);
416 set_riscv64_reg!(a1);
417 set_riscv64_reg!(a2);
418 set_riscv64_reg!(a3);
419 set_riscv64_reg!(a4);
420 set_riscv64_reg!(a5);
421 set_riscv64_reg!(a6);
422 set_riscv64_reg!(a7);
423 set_riscv64_reg!(s2);
424 set_riscv64_reg!(s3);
425 set_riscv64_reg!(s4);
426 set_riscv64_reg!(s5);
427 set_riscv64_reg!(s6);
428 set_riscv64_reg!(s7);
429 set_riscv64_reg!(s8);
430 set_riscv64_reg!(s9);
431 set_riscv64_reg!(s10);
432 set_riscv64_reg!(s11);
433 set_riscv64_reg!(t3);
434 set_riscv64_reg!(t4);
435 set_riscv64_reg!(t5);
436 set_riscv64_reg!(t6);
437 set_riscv64_reg!(mode);
438
439 get_riscv64_reg!(pc);
440 get_riscv64_reg!(ra);
441 get_riscv64_reg!(sp);
442 get_riscv64_reg!(gp);
443 get_riscv64_reg!(tp);
444 get_riscv64_reg!(t0);
445 get_riscv64_reg!(t1);
446 get_riscv64_reg!(t2);
447 get_riscv64_reg!(s0);
448 get_riscv64_reg!(s1);
449 get_riscv64_reg!(a0);
450 get_riscv64_reg!(a1);
451 get_riscv64_reg!(a2);
452 get_riscv64_reg!(a3);
453 get_riscv64_reg!(a4);
454 get_riscv64_reg!(a5);
455 get_riscv64_reg!(a6);
456 get_riscv64_reg!(a7);
457 get_riscv64_reg!(s2);
458 get_riscv64_reg!(s3);
459 get_riscv64_reg!(s4);
460 get_riscv64_reg!(s5);
461 get_riscv64_reg!(s6);
462 get_riscv64_reg!(s7);
463 get_riscv64_reg!(s8);
464 get_riscv64_reg!(s9);
465 get_riscv64_reg!(s10);
466 get_riscv64_reg!(s11);
467 get_riscv64_reg!(t3);
468 get_riscv64_reg!(t4);
469 get_riscv64_reg!(t5);
470 get_riscv64_reg!(t6);
471 get_riscv64_reg!(mode);
472