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 #[cfg(target_arch = "aarch64")] 12 use crate::aarch64::VcpuInit; 13 #[cfg(target_arch = "aarch64")] 14 use crate::arch::aarch64::gic::{Vgic, VgicConfig}; 15 #[cfg(feature = "tdx")] 16 use crate::arch::x86::CpuIdEntry; 17 use crate::cpu::Vcpu; 18 #[cfg(target_arch = "x86_64")] 19 use crate::ClockData; 20 use crate::UserMemoryRegion; 21 use crate::{IoEventAddress, IrqRoutingEntry}; 22 use std::any::Any; 23 #[cfg(target_arch = "x86_64")] 24 use std::fs::File; 25 use std::sync::Arc; 26 #[cfg(target_arch = "aarch64")] 27 use std::sync::Mutex; 28 use thiserror::Error; 29 use vmm_sys_util::eventfd::EventFd; 30 31 /// 32 /// I/O events data matches (32 or 64 bits). 33 /// 34 #[derive(Debug)] 35 pub enum DataMatch { 36 DataMatch32(u32), 37 DataMatch64(u64), 38 } 39 40 impl From<DataMatch> for u64 { 41 fn from(dm: DataMatch) -> u64 { 42 match dm { 43 DataMatch::DataMatch32(dm) => dm.into(), 44 DataMatch::DataMatch64(dm) => dm, 45 } 46 } 47 } 48 49 #[derive(Error, Debug)] 50 /// 51 /// Enum for VM error 52 pub enum HypervisorVmError { 53 /// 54 /// Create Vcpu error 55 /// 56 #[error("Failed to create Vcpu: {0}")] 57 CreateVcpu(#[source] anyhow::Error), 58 /// 59 /// Identity map address error 60 /// 61 #[error("Failed to set identity map address: {0}")] 62 SetIdentityMapAddress(#[source] anyhow::Error), 63 /// 64 /// TSS address error 65 /// 66 #[error("Failed to set TSS address: {0}")] 67 SetTssAddress(#[source] anyhow::Error), 68 /// 69 /// Create interrupt controller error 70 /// 71 #[error("Failed to create interrupt controller: {0}")] 72 CreateIrq(#[source] anyhow::Error), 73 /// 74 /// Register interrupt event error 75 /// 76 #[error("Failed to register interrupt event: {0}")] 77 RegisterIrqFd(#[source] anyhow::Error), 78 /// 79 /// Un register interrupt event error 80 /// 81 #[error("Failed to unregister interrupt event: {0}")] 82 UnregisterIrqFd(#[source] anyhow::Error), 83 /// 84 /// Register IO event error 85 /// 86 #[error("Failed to register IO event: {0}")] 87 RegisterIoEvent(#[source] anyhow::Error), 88 /// 89 /// Unregister IO event error 90 /// 91 #[error("Failed to unregister IO event: {0}")] 92 UnregisterIoEvent(#[source] anyhow::Error), 93 /// 94 /// Set GSI routing error 95 /// 96 #[error("Failed to set GSI routing: {0}")] 97 SetGsiRouting(#[source] anyhow::Error), 98 /// 99 /// Create user memory error 100 /// 101 #[error("Failed to create user memory: {0}")] 102 CreateUserMemory(#[source] anyhow::Error), 103 /// 104 /// Remove user memory region error 105 /// 106 #[error("Failed to remove user memory: {0}")] 107 RemoveUserMemory(#[source] anyhow::Error), 108 /// 109 /// Create device error 110 /// 111 #[error("Failed to set GSI routing: {0}")] 112 CreateDevice(#[source] anyhow::Error), 113 /// 114 /// Get preferred target error 115 /// 116 #[error("Failed to get preferred target: {0}")] 117 GetPreferredTarget(#[source] anyhow::Error), 118 /// 119 /// Enable split Irq error 120 /// 121 #[error("Failed to enable split Irq: {0}")] 122 EnableSplitIrq(#[source] anyhow::Error), 123 /// 124 /// Enable SGX attribute error 125 /// 126 #[error("Failed to enable SGX attribute: {0}")] 127 EnableSgxAttribute(#[source] anyhow::Error), 128 /// 129 /// Get clock error 130 /// 131 #[error("Failed to get clock: {0}")] 132 GetClock(#[source] anyhow::Error), 133 /// 134 /// Set clock error 135 /// 136 #[error("Failed to set clock: {0}")] 137 SetClock(#[source] anyhow::Error), 138 /// 139 /// Create passthrough device 140 /// 141 #[error("Failed to create passthrough device: {0}")] 142 CreatePassthroughDevice(#[source] anyhow::Error), 143 /// Write to Guest memory 144 /// 145 #[error("Failed to write to guest memory: {0}")] 146 GuestMemWrite(#[source] anyhow::Error), 147 /// 148 /// Read Guest memory 149 /// 150 #[error("Failed to read guest memory: {0}")] 151 GuestMemRead(#[source] anyhow::Error), 152 /// 153 /// Read from MMIO Bus 154 /// 155 #[error("Failed to read from MMIO Bus: {0}")] 156 MmioBusRead(#[source] anyhow::Error), 157 /// 158 /// Write to MMIO Bus 159 /// 160 #[error("Failed to write to MMIO Bus: {0}")] 161 MmioBusWrite(#[source] anyhow::Error), 162 /// 163 /// Read from IO Bus 164 /// 165 #[error("Failed to read from IO Bus: {0}")] 166 IoBusRead(#[source] anyhow::Error), 167 /// 168 /// Write to IO Bus 169 /// 170 #[error("Failed to write to IO Bus: {0}")] 171 IoBusWrite(#[source] anyhow::Error), 172 /// 173 /// Start dirty log error 174 /// 175 #[error("Failed to get dirty log: {0}")] 176 StartDirtyLog(#[source] anyhow::Error), 177 /// 178 /// Stop dirty log error 179 /// 180 #[error("Failed to get dirty log: {0}")] 181 StopDirtyLog(#[source] anyhow::Error), 182 /// 183 /// Get dirty log error 184 /// 185 #[error("Failed to get dirty log: {0}")] 186 GetDirtyLog(#[source] anyhow::Error), 187 /// 188 /// Assert virtual interrupt error 189 /// 190 #[error("Failed to assert virtual Interrupt: {0}")] 191 AsserttVirtualInterrupt(#[source] anyhow::Error), 192 193 #[cfg(feature = "sev_snp")] 194 /// 195 /// Error initializing SEV-SNP on the VM 196 /// 197 #[error("Failed to initialize SEV-SNP: {0}")] 198 InitializeSevSnp(#[source] std::io::Error), 199 200 #[cfg(feature = "tdx")] 201 /// 202 /// Error initializing TDX on the VM 203 /// 204 #[error("Failed to initialize TDX: {0}")] 205 InitializeTdx(#[source] std::io::Error), 206 #[cfg(feature = "tdx")] 207 /// 208 /// Error finalizing the TDX configuration on the VM 209 /// 210 #[error("Failed to finalize TDX: {0}")] 211 FinalizeTdx(#[source] std::io::Error), 212 #[cfg(feature = "tdx")] 213 /// 214 /// Error initializing the TDX memory region 215 /// 216 #[error("Failed to initialize memory region TDX: {0}")] 217 InitMemRegionTdx(#[source] std::io::Error), 218 /// 219 /// Create Vgic error 220 /// 221 #[error("Failed to create Vgic: {0}")] 222 CreateVgic(#[source] anyhow::Error), 223 } 224 /// 225 /// Result type for returning from a function 226 /// 227 pub type Result<T> = std::result::Result<T, HypervisorVmError>; 228 229 /// Configuration data for legacy interrupts. 230 /// 231 /// On x86 platforms, legacy interrupts means those interrupts routed through PICs or IOAPICs. 232 #[derive(Copy, Clone, Debug)] 233 pub struct LegacyIrqSourceConfig { 234 pub irqchip: u32, 235 pub pin: u32, 236 } 237 238 /// Configuration data for MSI/MSI-X interrupts. 239 /// 240 /// On x86 platforms, these interrupts are vectors delivered directly to the LAPIC. 241 #[derive(Copy, Clone, Debug, Default)] 242 pub struct MsiIrqSourceConfig { 243 /// High address to delivery message signaled interrupt. 244 pub high_addr: u32, 245 /// Low address to delivery message signaled interrupt. 246 pub low_addr: u32, 247 /// Data to write to delivery message signaled interrupt. 248 pub data: u32, 249 /// Unique ID of the device to delivery message signaled interrupt. 250 pub devid: u32, 251 } 252 253 /// Configuration data for an interrupt source. 254 #[derive(Copy, Clone, Debug)] 255 pub enum InterruptSourceConfig { 256 /// Configuration data for Legacy interrupts. 257 LegacyIrq(LegacyIrqSourceConfig), 258 /// Configuration data for PciMsi, PciMsix and generic MSI interrupts. 259 MsiIrq(MsiIrqSourceConfig), 260 } 261 262 /// 263 /// Trait to represent a Vm 264 /// 265 /// This crate provides a hypervisor-agnostic interfaces for Vm 266 /// 267 pub trait Vm: Send + Sync + Any { 268 #[cfg(target_arch = "x86_64")] 269 /// Sets the address of the one-page region in the VM's address space. 270 fn set_identity_map_address(&self, address: u64) -> Result<()>; 271 #[cfg(target_arch = "x86_64")] 272 /// Sets the address of the three-page region in the VM's address space. 273 fn set_tss_address(&self, offset: usize) -> Result<()>; 274 /// Creates an in-kernel interrupt controller. 275 fn create_irq_chip(&self) -> Result<()>; 276 /// Registers an event that will, when signaled, trigger the `gsi` IRQ. 277 fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>; 278 /// Unregister an event that will, when signaled, trigger the `gsi` IRQ. 279 fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> Result<()>; 280 /// Creates a new KVM vCPU file descriptor and maps the memory corresponding 281 fn create_vcpu(&self, id: u8, vm_ops: Option<Arc<dyn VmOps>>) -> Result<Arc<dyn Vcpu>>; 282 #[cfg(target_arch = "aarch64")] 283 fn create_vgic(&self, config: VgicConfig) -> Result<Arc<Mutex<dyn Vgic>>>; 284 285 /// Registers an event to be signaled whenever a certain address is written to. 286 fn register_ioevent( 287 &self, 288 fd: &EventFd, 289 addr: &IoEventAddress, 290 datamatch: Option<DataMatch>, 291 ) -> Result<()>; 292 /// Unregister an event from a certain address it has been previously registered to. 293 fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>; 294 // Construct a routing entry 295 fn make_routing_entry(&self, gsi: u32, config: &InterruptSourceConfig) -> IrqRoutingEntry; 296 /// Sets the GSI routing table entries, overwriting any previously set 297 fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>; 298 /// Creates a memory region structure that can be used with {create/remove}_user_memory_region 299 fn make_user_memory_region( 300 &self, 301 slot: u32, 302 guest_phys_addr: u64, 303 memory_size: u64, 304 userspace_addr: u64, 305 readonly: bool, 306 log_dirty_pages: bool, 307 ) -> UserMemoryRegion; 308 /// Creates a guest physical memory slot. 309 fn create_user_memory_region(&self, user_memory_region: UserMemoryRegion) -> Result<()>; 310 /// Removes a guest physical memory slot. 311 fn remove_user_memory_region(&self, user_memory_region: UserMemoryRegion) -> Result<()>; 312 /// Returns the preferred CPU target type which can be emulated by KVM on underlying host. 313 #[cfg(target_arch = "aarch64")] 314 fn get_preferred_target(&self, kvi: &mut VcpuInit) -> Result<()>; 315 /// Enable split Irq capability 316 #[cfg(target_arch = "x86_64")] 317 fn enable_split_irq(&self) -> Result<()>; 318 #[cfg(target_arch = "x86_64")] 319 fn enable_sgx_attribute(&self, file: File) -> Result<()>; 320 /// Retrieve guest clock. 321 #[cfg(target_arch = "x86_64")] 322 fn get_clock(&self) -> Result<ClockData>; 323 /// Set guest clock. 324 #[cfg(target_arch = "x86_64")] 325 fn set_clock(&self, data: &ClockData) -> Result<()>; 326 /// Create a device that is used for passthrough 327 fn create_passthrough_device(&self) -> Result<vfio_ioctls::VfioDeviceFd>; 328 /// Start logging dirty pages 329 fn start_dirty_log(&self) -> Result<()>; 330 /// Stop logging dirty pages 331 fn stop_dirty_log(&self) -> Result<()>; 332 /// Get dirty pages bitmap 333 fn get_dirty_log(&self, slot: u32, base_gpa: u64, memory_size: u64) -> Result<Vec<u64>>; 334 #[cfg(feature = "sev_snp")] 335 /// Initialize SEV-SNP on this VM 336 fn sev_snp_init(&self) -> Result<()> { 337 unimplemented!() 338 } 339 #[cfg(feature = "tdx")] 340 /// Initialize TDX on this VM 341 fn tdx_init(&self, _cpuid: &[CpuIdEntry], _max_vcpus: u32) -> Result<()> { 342 unimplemented!() 343 } 344 #[cfg(feature = "tdx")] 345 /// Finalize the configuration of TDX on this VM 346 fn tdx_finalize(&self) -> Result<()> { 347 unimplemented!() 348 } 349 #[cfg(feature = "tdx")] 350 /// Initialize a TDX memory region for this VM 351 fn tdx_init_memory_region( 352 &self, 353 _host_address: u64, 354 _guest_address: u64, 355 _size: u64, 356 _measure: bool, 357 ) -> Result<()> { 358 unimplemented!() 359 } 360 /// Downcast to the underlying hypervisor VM type 361 fn as_any(&self) -> &dyn Any; 362 } 363 364 pub trait VmOps: Send + Sync { 365 fn guest_mem_write(&self, gpa: u64, buf: &[u8]) -> Result<usize>; 366 fn guest_mem_read(&self, gpa: u64, buf: &mut [u8]) -> Result<usize>; 367 fn mmio_read(&self, gpa: u64, data: &mut [u8]) -> Result<()>; 368 fn mmio_write(&self, gpa: u64, data: &[u8]) -> Result<()>; 369 #[cfg(target_arch = "x86_64")] 370 fn pio_read(&self, port: u64, data: &mut [u8]) -> Result<()>; 371 #[cfg(target_arch = "x86_64")] 372 fn pio_write(&self, port: u64, data: &[u8]) -> Result<()>; 373 } 374