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