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 use std::sync::Arc; 52 53 use concat_idents::concat_idents; 54 #[cfg(target_arch = "x86_64")] 55 pub use cpu::CpuVendor; 56 pub use cpu::{HypervisorCpuError, Vcpu, VmExit}; 57 pub use device::HypervisorDeviceError; 58 #[cfg(all(feature = "kvm", target_arch = "aarch64"))] 59 pub use kvm::{aarch64, GicState}; 60 pub use vm::{ 61 DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig, 62 Vm, VmOps, 63 }; 64 65 pub use crate::hypervisor::{Hypervisor, HypervisorError}; 66 67 #[derive(Debug, Copy, Clone)] 68 pub enum HypervisorType { 69 #[cfg(feature = "kvm")] 70 Kvm, 71 #[cfg(feature = "mshv")] 72 Mshv, 73 } 74 75 pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> { 76 #[cfg(feature = "kvm")] 77 if kvm::KvmHypervisor::is_available()? { 78 return kvm::KvmHypervisor::new(); 79 } 80 81 #[cfg(feature = "mshv")] 82 if mshv::MshvHypervisor::is_available()? { 83 return mshv::MshvHypervisor::new(); 84 } 85 86 Err(HypervisorError::HypervisorCreate(anyhow!( 87 "no supported hypervisor" 88 ))) 89 } 90 91 // Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`. 92 fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> { 93 let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>(); 94 let mut v = Vec::with_capacity(rounded_size); 95 v.resize_with(rounded_size, T::default); 96 v 97 } 98 99 // The kvm API has many structs that resemble the following `Foo` structure: 100 // 101 // ``` 102 // #[repr(C)] 103 // struct Foo { 104 // some_data: u32 105 // entries: __IncompleteArrayField<__u32>, 106 // } 107 // ``` 108 // 109 // In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not 110 // include any space for `entries`. To make the allocation large enough while still being aligned 111 // for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used 112 // as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous 113 // with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries. 114 use std::mem::size_of; 115 pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> { 116 let element_space = count * size_of::<F>(); 117 let vec_size_bytes = size_of::<T>() + element_space; 118 vec_with_size_in_bytes(vec_size_bytes) 119 } 120 121 /// 122 /// User memory region structure 123 /// 124 #[derive(Debug, Default, Eq, PartialEq)] 125 pub struct UserMemoryRegion { 126 pub slot: u32, 127 pub guest_phys_addr: u64, 128 pub memory_size: u64, 129 pub userspace_addr: u64, 130 pub flags: u32, 131 } 132 133 /// 134 /// Flags for user memory region 135 /// 136 pub const USER_MEMORY_REGION_READ: u32 = 1; 137 pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1; 138 pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2; 139 pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3; 140 pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4; 141 142 #[derive(Debug)] 143 pub enum MpState { 144 #[cfg(feature = "kvm")] 145 Kvm(kvm_bindings::kvm_mp_state), 146 #[cfg(all(feature = "mshv", target_arch = "x86_64"))] 147 Mshv, /* MSHV does not support MpState yet */ 148 } 149 150 #[derive(Debug, Clone, Copy)] 151 pub enum IoEventAddress { 152 Pio(u64), 153 Mmio(u64), 154 } 155 156 #[derive(Clone, serde::Serialize, serde::Deserialize)] 157 #[allow(clippy::large_enum_variant)] 158 pub enum CpuState { 159 #[cfg(feature = "kvm")] 160 Kvm(kvm::VcpuKvmState), 161 #[cfg(all(feature = "mshv", target_arch = "x86_64"))] 162 Mshv(mshv::VcpuMshvState), 163 } 164 165 #[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)] 166 #[cfg(target_arch = "x86_64")] 167 pub enum ClockData { 168 #[cfg(feature = "kvm")] 169 Kvm(kvm_bindings::kvm_clock_data), 170 #[cfg(feature = "mshv")] 171 Mshv(mshv::MshvClockData), 172 } 173 174 #[cfg(target_arch = "x86_64")] 175 impl ClockData { 176 pub fn reset_flags(&mut self) { 177 match self { 178 #[cfg(feature = "kvm")] 179 ClockData::Kvm(s) => s.flags = 0, 180 #[allow(unreachable_patterns)] 181 _ => {} 182 } 183 } 184 } 185 186 #[derive(Copy, Clone)] 187 pub enum IrqRoutingEntry { 188 #[cfg(feature = "kvm")] 189 Kvm(kvm_bindings::kvm_irq_routing_entry), 190 #[cfg(feature = "mshv")] 191 Mshv(mshv_bindings::mshv_user_irq_entry), 192 } 193 194 #[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)] 195 pub enum StandardRegisters { 196 #[cfg(feature = "kvm")] 197 Kvm(kvm_bindings::kvm_regs), 198 #[cfg(all(feature = "mshv", target_arch = "x86_64"))] 199 Mshv(mshv_bindings::StandardRegisters), 200 } 201 202 macro_rules! set_x86_64_reg { 203 ($reg_name:ident) => { 204 concat_idents!(method_name = "set_", $reg_name { 205 #[cfg(target_arch = "x86_64")] 206 impl StandardRegisters { 207 pub fn method_name(&mut self, val: u64) { 208 match self { 209 #[cfg(feature = "kvm")] 210 StandardRegisters::Kvm(s) => s.$reg_name = val, 211 #[cfg(feature = "mshv")] 212 StandardRegisters::Mshv(s) => s.$reg_name = val, 213 } 214 } 215 } 216 }); 217 } 218 } 219 220 macro_rules! get_x86_64_reg { 221 ($reg_name:ident) => { 222 concat_idents!(method_name = "get_", $reg_name { 223 #[cfg(target_arch = "x86_64")] 224 impl StandardRegisters { 225 pub fn method_name(&self) -> u64 { 226 match self { 227 #[cfg(feature = "kvm")] 228 StandardRegisters::Kvm(s) => s.$reg_name, 229 #[cfg(feature = "mshv")] 230 StandardRegisters::Mshv(s) => s.$reg_name, 231 } 232 } 233 } 234 }); 235 } 236 } 237 238 set_x86_64_reg!(rax); 239 set_x86_64_reg!(rbx); 240 set_x86_64_reg!(rcx); 241 set_x86_64_reg!(rdx); 242 set_x86_64_reg!(rsi); 243 set_x86_64_reg!(rdi); 244 set_x86_64_reg!(rsp); 245 set_x86_64_reg!(rbp); 246 set_x86_64_reg!(r8); 247 set_x86_64_reg!(r9); 248 set_x86_64_reg!(r10); 249 set_x86_64_reg!(r11); 250 set_x86_64_reg!(r12); 251 set_x86_64_reg!(r13); 252 set_x86_64_reg!(r14); 253 set_x86_64_reg!(r15); 254 set_x86_64_reg!(rip); 255 set_x86_64_reg!(rflags); 256 257 get_x86_64_reg!(rax); 258 get_x86_64_reg!(rbx); 259 get_x86_64_reg!(rcx); 260 get_x86_64_reg!(rdx); 261 get_x86_64_reg!(rsi); 262 get_x86_64_reg!(rdi); 263 get_x86_64_reg!(rsp); 264 get_x86_64_reg!(rbp); 265 get_x86_64_reg!(r8); 266 get_x86_64_reg!(r9); 267 get_x86_64_reg!(r10); 268 get_x86_64_reg!(r11); 269 get_x86_64_reg!(r12); 270 get_x86_64_reg!(r13); 271 get_x86_64_reg!(r14); 272 get_x86_64_reg!(r15); 273 get_x86_64_reg!(rip); 274 get_x86_64_reg!(rflags); 275 276 macro_rules! set_aarch64_reg { 277 ($reg_name:ident, $type:ty) => { 278 concat_idents!(method_name = "set_", $reg_name { 279 #[cfg(target_arch = "aarch64")] 280 impl StandardRegisters { 281 pub fn method_name(&mut self, val: $type) { 282 match self { 283 #[cfg(feature = "kvm")] 284 StandardRegisters::Kvm(s) => s.regs.$reg_name = val, 285 } 286 } 287 } 288 }); 289 } 290 } 291 292 macro_rules! get_aarch64_reg { 293 ($reg_name:ident, $type:ty) => { 294 concat_idents!(method_name = "get_", $reg_name { 295 #[cfg(target_arch = "aarch64")] 296 impl StandardRegisters { 297 pub fn method_name(&self) -> $type { 298 match self { 299 #[cfg(feature = "kvm")] 300 StandardRegisters::Kvm(s) => s.regs.$reg_name, 301 } 302 } 303 } 304 }); 305 } 306 } 307 308 set_aarch64_reg!(regs, [u64; 31usize]); 309 set_aarch64_reg!(sp, u64); 310 set_aarch64_reg!(pc, u64); 311 set_aarch64_reg!(pstate, u64); 312 313 get_aarch64_reg!(regs, [u64; 31usize]); 314 get_aarch64_reg!(sp, u64); 315 get_aarch64_reg!(pc, u64); 316 get_aarch64_reg!(pstate, u64); 317