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::{RegList, StandardRegisters, VcpuInit}; 13 #[cfg(target_arch = "x86_64")] 14 use crate::arch::x86::{ 15 CpuIdEntry, FpuState, LapicState, MsrEntry, SpecialRegisters, StandardRegisters, 16 }; 17 #[cfg(feature = "tdx")] 18 use crate::kvm::{TdxExitDetails, TdxExitStatus}; 19 use crate::CpuState; 20 use crate::MpState; 21 use thiserror::Error; 22 use vm_memory::GuestAddress; 23 24 #[cfg(target_arch = "x86_64")] 25 #[derive(Copy, Clone, Default)] 26 pub enum CpuVendor { 27 #[default] 28 Unknown, 29 Intel, 30 AMD, 31 } 32 33 #[derive(Error, Debug)] 34 /// 35 /// Enum for CPU error 36 pub enum HypervisorCpuError { 37 /// 38 /// Setting standard registers error 39 /// 40 #[error("Failed to set standard register: {0}")] 41 SetStandardRegs(#[source] anyhow::Error), 42 /// 43 /// Setting standard registers error 44 /// 45 #[error("Failed to get standard registers: {0}")] 46 GetStandardRegs(#[source] anyhow::Error), 47 /// 48 /// Setting special register error 49 /// 50 #[error("Failed to set special registers: {0}")] 51 SetSpecialRegs(#[source] anyhow::Error), 52 /// 53 /// Getting standard register error 54 /// 55 #[error("Failed to get special registers: {0}")] 56 GetSpecialRegs(#[source] anyhow::Error), 57 /// 58 /// Setting floating point registers error 59 /// 60 #[error("Failed to set floating point registers: {0}")] 61 SetFloatingPointRegs(#[source] anyhow::Error), 62 /// 63 /// Getting floating point register error 64 /// 65 #[error("Failed to get floating points registers: {0}")] 66 GetFloatingPointRegs(#[source] anyhow::Error), 67 /// 68 /// Setting Cpuid error 69 /// 70 #[error("Failed to set Cpuid: {0}")] 71 SetCpuid(#[source] anyhow::Error), 72 /// 73 /// Getting Cpuid error 74 /// 75 #[error("Failed to get Cpuid: {0}")] 76 GetCpuid(#[source] anyhow::Error), 77 /// 78 /// Setting lapic state error 79 /// 80 #[error("Failed to set Lapic state: {0}")] 81 SetLapicState(#[source] anyhow::Error), 82 /// 83 /// Getting Lapic state error 84 /// 85 #[error("Failed to get Lapic state: {0}")] 86 GetlapicState(#[source] anyhow::Error), 87 /// 88 /// Setting MSR entries error 89 /// 90 #[error("Failed to set Msr entries: {0}")] 91 SetMsrEntries(#[source] anyhow::Error), 92 /// 93 /// Getting Msr entries error 94 /// 95 #[error("Failed to get Msr entries: {0}")] 96 GetMsrEntries(#[source] anyhow::Error), 97 /// 98 /// Setting multi-processing state error 99 /// 100 #[error("Failed to set MP state: {0}")] 101 SetMpState(#[source] anyhow::Error), 102 /// 103 /// Getting multi-processing state error 104 /// 105 #[error("Failed to get MP state: {0}")] 106 GetMpState(#[source] anyhow::Error), 107 /// 108 /// Setting Saved Processor Extended States error 109 /// 110 #[error("Failed to set Saved Processor Extended States: {0}")] 111 SetXsaveState(#[source] anyhow::Error), 112 /// 113 /// Getting Saved Processor Extended States error 114 /// 115 #[error("Failed to get Saved Processor Extended States: {0}")] 116 GetXsaveState(#[source] anyhow::Error), 117 /// 118 /// Setting Extended Control Registers error 119 /// 120 #[error("Failed to set Extended Control Registers: {0}")] 121 SetXcsr(#[source] anyhow::Error), 122 /// 123 /// Getting Extended Control Registers error 124 /// 125 #[error("Failed to get Extended Control Registers: {0}")] 126 GetXcsr(#[source] anyhow::Error), 127 /// 128 /// Running Vcpu error 129 /// 130 #[error("Failed to run vcpu: {0}")] 131 RunVcpu(#[source] anyhow::Error), 132 /// 133 /// Getting Vcpu events error 134 /// 135 #[error("Failed to get Vcpu events: {0}")] 136 GetVcpuEvents(#[source] anyhow::Error), 137 /// 138 /// Setting Vcpu events error 139 /// 140 #[error("Failed to set Vcpu events: {0}")] 141 SetVcpuEvents(#[source] anyhow::Error), 142 /// 143 /// Vcpu Init error 144 /// 145 #[error("Failed to init vcpu: {0}")] 146 VcpuInit(#[source] anyhow::Error), 147 /// 148 /// Setting one reg error 149 /// 150 #[error("Failed to init vcpu: {0}")] 151 SetRegister(#[source] anyhow::Error), 152 /// 153 /// Getting one reg error 154 /// 155 #[error("Failed to init vcpu: {0}")] 156 GetRegister(#[source] anyhow::Error), 157 /// 158 /// Getting guest clock paused error 159 /// 160 #[error("Failed to notify guest its clock was paused: {0}")] 161 NotifyGuestClockPaused(#[source] anyhow::Error), 162 /// 163 /// Setting debug register error 164 /// 165 #[error("Failed to set debug registers: {0}")] 166 SetDebugRegs(#[source] anyhow::Error), 167 /// 168 /// Getting debug register error 169 /// 170 #[error("Failed to get debug registers: {0}")] 171 GetDebugRegs(#[source] anyhow::Error), 172 /// 173 /// Setting misc register error 174 /// 175 #[error("Failed to set misc registers: {0}")] 176 SetMiscRegs(#[source] anyhow::Error), 177 /// 178 /// Getting misc register error 179 /// 180 #[error("Failed to get misc registers: {0}")] 181 GetMiscRegs(#[source] anyhow::Error), 182 /// 183 /// Write to Guest Mem 184 /// 185 #[error("Failed to write to Guest Mem at: {0}")] 186 GuestMemWrite(#[source] anyhow::Error), 187 /// Enabling HyperV SynIC error 188 /// 189 #[error("Failed to enable HyperV SynIC")] 190 EnableHyperVSyncIc(#[source] anyhow::Error), 191 /// 192 /// Getting AArch64 core register error 193 /// 194 #[error("Failed to get core register: {0}")] 195 GetCoreRegister(#[source] anyhow::Error), 196 /// 197 /// Setting AArch64 core register error 198 /// 199 #[error("Failed to set core register: {0}")] 200 SetCoreRegister(#[source] anyhow::Error), 201 /// 202 /// Getting AArch64 registers list error 203 /// 204 #[error("Failed to retrieve list of registers: {0}")] 205 GetRegList(#[source] anyhow::Error), 206 /// 207 /// Getting AArch64 system register error 208 /// 209 #[error("Failed to get system register: {0}")] 210 GetSysRegister(#[source] anyhow::Error), 211 /// 212 /// Setting AArch64 system register error 213 /// 214 #[error("Failed to set system register: {0}")] 215 SetSysRegister(#[source] anyhow::Error), 216 /// 217 /// GVA translation error 218 /// 219 #[error("Failed to translate GVA: {0}")] 220 TranslateVirtualAddress(#[source] anyhow::Error), 221 /// 222 /// Set cpu attribute error 223 /// 224 #[error("Failed to set vcpu attribute: {0}")] 225 SetVcpuAttribute(#[source] anyhow::Error), 226 /// 227 /// Check if cpu has a certain attribute error 228 /// 229 #[error("Failed to check if vcpu has attribute: {0}")] 230 HasVcpuAttribute(#[source] anyhow::Error), 231 /// 232 /// Failed to initialize TDX on CPU 233 /// 234 #[cfg(feature = "tdx")] 235 #[error("Failed to initialize TDX: {0}")] 236 InitializeTdx(#[source] std::io::Error), 237 /// 238 /// Unknown TDX VM call 239 /// 240 #[cfg(feature = "tdx")] 241 #[error("Unknown TDX VM call")] 242 UnknownTdxVmCall, 243 #[cfg(target_arch = "aarch64")] 244 /// 245 /// Failed to initialize PMU 246 /// 247 #[error("Failed to initialize PMU")] 248 InitializePmu, 249 #[cfg(target_arch = "x86_64")] 250 /// 251 /// Error getting TSC frequency 252 /// 253 #[error("Failed to get TSC frequency: {0}")] 254 GetTscKhz(#[source] anyhow::Error), 255 /// 256 /// Error setting TSC frequency 257 /// 258 #[error("Failed to set TSC frequency: {0}")] 259 SetTscKhz(#[source] anyhow::Error), 260 /// 261 /// Error reading value at given GPA 262 /// 263 #[error("Failed to read from GPA: {0}")] 264 GpaRead(#[source] anyhow::Error), 265 /// 266 /// Error writing value at given GPA 267 /// 268 #[error("Failed to write to GPA: {0}")] 269 GpaWrite(#[source] anyhow::Error), 270 /// 271 /// Error getting CPUID leaf 272 /// 273 #[error("Failed to get CPUID entries: {0}")] 274 GetCpuidVales(#[source] anyhow::Error), 275 } 276 277 #[derive(Debug)] 278 pub enum VmExit<'a> { 279 #[cfg(target_arch = "x86_64")] 280 IoOut(u16 /* port */, &'a [u8] /* data */), 281 #[cfg(target_arch = "x86_64")] 282 IoIn(u16 /* port */, &'a mut [u8] /* data */), 283 #[cfg(target_arch = "x86_64")] 284 IoapicEoi(u8 /* vector */), 285 MmioRead(u64 /* address */, &'a mut [u8]), 286 MmioWrite(u64 /* address */, &'a [u8]), 287 Ignore, 288 Reset, 289 Shutdown, 290 Hyperv, 291 #[cfg(feature = "tdx")] 292 Tdx, 293 #[cfg(feature = "kvm")] 294 Debug, 295 } 296 297 /// 298 /// Result type for returning from a function 299 /// 300 pub type Result<T> = anyhow::Result<T, HypervisorCpuError>; 301 /// 302 /// Trait to represent a generic Vcpu 303 /// 304 pub trait Vcpu: Send + Sync { 305 /// 306 /// Returns the vCPU general purpose registers. 307 /// 308 fn get_regs(&self) -> Result<StandardRegisters>; 309 /// 310 /// Sets the vCPU general purpose registers. 311 /// 312 fn set_regs(&self, regs: &StandardRegisters) -> Result<()>; 313 #[cfg(target_arch = "x86_64")] 314 /// 315 /// Returns the vCPU special registers. 316 /// 317 fn get_sregs(&self) -> Result<SpecialRegisters>; 318 #[cfg(target_arch = "x86_64")] 319 /// 320 /// Sets the vCPU special registers 321 /// 322 fn set_sregs(&self, sregs: &SpecialRegisters) -> Result<()>; 323 #[cfg(target_arch = "x86_64")] 324 /// 325 /// Returns the floating point state (FPU) from the vCPU. 326 /// 327 fn get_fpu(&self) -> Result<FpuState>; 328 #[cfg(target_arch = "x86_64")] 329 /// 330 /// Set the floating point state (FPU) of a vCPU 331 /// 332 fn set_fpu(&self, fpu: &FpuState) -> Result<()>; 333 #[cfg(target_arch = "x86_64")] 334 /// 335 /// X86 specific call to setup the CPUID registers. 336 /// 337 fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> Result<()>; 338 #[cfg(target_arch = "x86_64")] 339 /// 340 /// X86 specific call to enable HyperV SynIC 341 /// 342 fn enable_hyperv_synic(&self) -> Result<()>; 343 #[cfg(target_arch = "x86_64")] 344 /// 345 /// X86 specific call to retrieve the CPUID registers. 346 /// 347 fn get_cpuid2(&self, num_entries: usize) -> Result<Vec<CpuIdEntry>>; 348 #[cfg(target_arch = "x86_64")] 349 /// 350 /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 351 /// 352 fn get_lapic(&self) -> Result<LapicState>; 353 #[cfg(target_arch = "x86_64")] 354 /// 355 /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 356 /// 357 fn set_lapic(&self, lapic: &LapicState) -> Result<()>; 358 #[cfg(target_arch = "x86_64")] 359 /// 360 /// Returns the model-specific registers (MSR) for this vCPU. 361 /// 362 fn get_msrs(&self, msrs: &mut Vec<MsrEntry>) -> Result<usize>; 363 #[cfg(target_arch = "x86_64")] 364 /// 365 /// Setup the model-specific registers (MSR) for this vCPU. 366 /// 367 fn set_msrs(&self, msrs: &[MsrEntry]) -> Result<usize>; 368 /// 369 /// Returns the vcpu's current "multiprocessing state". 370 /// 371 fn get_mp_state(&self) -> Result<MpState>; 372 /// 373 /// Sets the vcpu's current "multiprocessing state". 374 /// 375 fn set_mp_state(&self, mp_state: MpState) -> Result<()>; 376 #[cfg(target_arch = "x86_64")] 377 /// 378 /// Let the guest know that it has been paused, which prevents from 379 /// potential soft lockups when being resumed. 380 /// 381 fn notify_guest_clock_paused(&self) -> Result<()> { 382 Ok(()) 383 } 384 /// 385 /// Sets debug registers to set hardware breakpoints and/or enable single step. 386 /// 387 fn set_guest_debug(&self, _addrs: &[GuestAddress], _singlestep: bool) -> Result<()> { 388 Err(HypervisorCpuError::SetDebugRegs(anyhow!("unimplemented"))) 389 } 390 /// 391 /// Sets the type of CPU to be exposed to the guest and optional features. 392 /// 393 #[cfg(target_arch = "aarch64")] 394 fn vcpu_init(&self, kvi: &VcpuInit) -> Result<()>; 395 /// 396 /// Gets a list of the guest registers that are supported for the 397 /// KVM_GET_ONE_REG/KVM_SET_ONE_REG calls. 398 /// 399 #[cfg(target_arch = "aarch64")] 400 fn get_reg_list(&self, reg_list: &mut RegList) -> Result<()>; 401 /// 402 /// Gets the value of a system register 403 /// 404 #[cfg(target_arch = "aarch64")] 405 fn get_sys_reg(&self, sys_reg: u32) -> Result<u64>; 406 /// 407 /// Configure core registers for a given CPU. 408 /// 409 #[cfg(target_arch = "aarch64")] 410 fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> Result<()>; 411 /// 412 /// Check if the CPU supports PMU 413 /// 414 #[cfg(target_arch = "aarch64")] 415 fn has_pmu_support(&self) -> bool; 416 /// 417 /// Initialize PMU 418 /// 419 #[cfg(target_arch = "aarch64")] 420 fn init_pmu(&self, irq: u32) -> Result<()>; 421 /// 422 /// Retrieve the vCPU state. 423 /// This function is necessary to snapshot the VM 424 /// 425 fn state(&self) -> Result<CpuState>; 426 /// 427 /// Set the vCPU state. 428 /// This function is required when restoring the VM 429 /// 430 fn set_state(&self, state: &CpuState) -> Result<()>; 431 /// 432 /// Triggers the running of the current virtual CPU returning an exit reason. 433 /// 434 fn run(&self) -> std::result::Result<VmExit, HypervisorCpuError>; 435 #[cfg(target_arch = "x86_64")] 436 /// 437 /// Translate guest virtual address to guest physical address 438 /// 439 fn translate_gva(&self, gva: u64, flags: u64) -> Result<(u64, u32)>; 440 /// 441 /// Initialize TDX support on the vCPU 442 /// 443 #[cfg(feature = "tdx")] 444 fn tdx_init(&self, _hob_address: u64) -> Result<()> { 445 unimplemented!() 446 } 447 /// 448 /// Set the "immediate_exit" state 449 /// 450 fn set_immediate_exit(&self, _exit: bool) {} 451 #[cfg(feature = "tdx")] 452 /// 453 /// Returns the details about TDX exit reason 454 /// 455 fn get_tdx_exit_details(&mut self) -> Result<TdxExitDetails> { 456 unimplemented!() 457 } 458 #[cfg(feature = "tdx")] 459 /// 460 /// Set the status code for TDX exit 461 /// 462 fn set_tdx_status(&mut self, _status: TdxExitStatus) { 463 unimplemented!() 464 } 465 #[cfg(target_arch = "x86_64")] 466 /// 467 /// Return the list of initial MSR entries for a VCPU 468 /// 469 fn boot_msr_entries(&self) -> Vec<MsrEntry>; 470 471 #[cfg(target_arch = "x86_64")] 472 /// 473 /// Get the frequency of the TSC if available 474 /// 475 fn tsc_khz(&self) -> Result<Option<u32>> { 476 Ok(None) 477 } 478 #[cfg(target_arch = "x86_64")] 479 /// 480 /// Set the frequency of the TSC if available 481 /// 482 fn set_tsc_khz(&self, _freq: u32) -> Result<()> { 483 Ok(()) 484 } 485 #[cfg(target_arch = "x86_64")] 486 /// 487 /// X86 specific call to retrieve cpuid leaf 488 /// 489 fn get_cpuid_values( 490 &self, 491 _function: u32, 492 _index: u32, 493 _xfem: u64, 494 _xss: u64, 495 ) -> Result<[u32; 4]> { 496 unimplemented!() 497 } 498 } 499