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 #![allow(clippy::significant_drop_in_scrutinee)] 22 23 #[macro_use] 24 extern crate anyhow; 25 #[cfg(target_arch = "x86_64")] 26 #[macro_use] 27 extern crate log; 28 29 /// Architecture specific definitions 30 #[macro_use] 31 pub mod arch; 32 33 #[cfg(feature = "kvm")] 34 /// KVM implementation module 35 pub mod kvm; 36 37 /// Microsoft Hypervisor implementation module 38 #[cfg(all(feature = "mshv", target_arch = "x86_64"))] 39 pub mod mshv; 40 41 /// Hypevisor related module 42 mod hypervisor; 43 44 /// Vm related module 45 mod vm; 46 47 /// CPU related module 48 mod cpu; 49 50 /// Device related module 51 mod device; 52 53 pub use cpu::{HypervisorCpuError, Vcpu, VmExit}; 54 pub use device::HypervisorDeviceError; 55 pub use hypervisor::{Hypervisor, HypervisorError}; 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 Kvm, 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