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 use kvm_ioctls::{NoDatamatch, VcpuFd, VmFd}; 12 use std::result; 13 use std::sync::Arc; 14 #[cfg(target_arch = "x86_64")] 15 use vm_memory::Address; 16 use vmm_sys_util::eventfd::EventFd; 17 18 #[cfg(target_arch = "aarch64")] 19 pub use crate::aarch64::{check_required_kvm_extensions, VcpuInit, VcpuKvmState as CpuState}; 20 use crate::cpu; 21 use crate::hypervisor; 22 use crate::vm; 23 // x86_64 dependencies 24 #[cfg(target_arch = "x86_64")] 25 pub mod x86_64; 26 27 #[cfg(target_arch = "x86_64")] 28 use x86_64::{ 29 boot_msr_entries, check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters, 30 KVM_TSS_ADDRESS, 31 }; 32 33 #[cfg(target_arch = "x86_64")] 34 pub use x86_64::{ 35 CpuId, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState as CpuState, Xsave, 36 }; 37 38 #[cfg(target_arch = "x86_64")] 39 use kvm_bindings::{kvm_enable_cap, KVM_CAP_SPLIT_IRQCHIP}; 40 41 #[cfg(target_arch = "x86_64")] 42 use crate::arch::x86::NUM_IOAPIC_PINS; 43 44 // aarch64 dependencies 45 #[cfg(target_arch = "aarch64")] 46 pub mod aarch64; 47 48 pub use kvm_bindings; 49 pub use kvm_bindings::{ 50 kvm_create_device, kvm_device_type_KVM_DEV_TYPE_VFIO, kvm_irq_routing, kvm_irq_routing_entry, 51 kvm_userspace_memory_region, KVM_IRQ_ROUTING_MSI, KVM_MEM_READONLY, 52 }; 53 pub use kvm_ioctls; 54 pub use kvm_ioctls::{Cap, Kvm}; 55 56 /// 57 /// Export generically-named wrappers of kvm-bindings for Unix-based platforms 58 /// 59 pub use { 60 kvm_bindings::kvm_clock_data as ClockData, kvm_bindings::kvm_create_device as CreateDevice, 61 kvm_bindings::kvm_irq_routing as IrqRouting, kvm_bindings::kvm_mp_state as MpState, 62 kvm_bindings::kvm_userspace_memory_region as MemoryRegion, 63 kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_ioctls::DeviceFd, kvm_ioctls::IoEventAddress, 64 kvm_ioctls::VcpuExit, 65 }; 66 67 /// Wrapper over KVM VM ioctls. 68 pub struct KvmVm { 69 fd: Arc<VmFd>, 70 } 71 /// 72 /// Implementation of Vm trait for KVM 73 /// Example: 74 /// #[cfg(feature = "kvm")] 75 /// extern crate hypervisor 76 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap(); 77 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 78 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 79 /// vm.set/get().unwrap() 80 /// 81 impl vm::Vm for KvmVm { 82 #[cfg(target_arch = "x86_64")] 83 /// 84 /// Sets the address of the three-page region in the VM's address space. 85 /// 86 fn set_tss_address(&self, offset: usize) -> vm::Result<()> { 87 self.fd 88 .set_tss_address(offset) 89 .map_err(|e| vm::HypervisorVmError::SetTssAddress(e.into())) 90 } 91 /// 92 /// Creates an in-kernel interrupt controller. 93 /// 94 fn create_irq_chip(&self) -> vm::Result<()> { 95 self.fd 96 .create_irq_chip() 97 .map_err(|e| vm::HypervisorVmError::CreateIrq(e.into())) 98 } 99 /// 100 /// Registers an event that will, when signaled, trigger the `gsi` IRQ. 101 /// 102 fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> { 103 self.fd 104 .register_irqfd(fd, gsi) 105 .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into())) 106 } 107 /// 108 /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ. 109 /// 110 fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> { 111 self.fd 112 .unregister_irqfd(fd, gsi) 113 .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into())) 114 } 115 /// 116 /// Creates a VcpuFd object from a vcpu RawFd. 117 /// 118 fn create_vcpu(&self, id: u8) -> vm::Result<Arc<dyn cpu::Vcpu>> { 119 let vc = self 120 .fd 121 .create_vcpu(id) 122 .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?; 123 let vcpu = KvmVcpu { fd: vc }; 124 Ok(Arc::new(vcpu)) 125 } 126 /// 127 /// Registers an event to be signaled whenever a certain address is written to. 128 /// 129 fn register_ioevent( 130 &self, 131 fd: &EventFd, 132 addr: &IoEventAddress, 133 datamatch: Option<vm::DataMatch>, 134 ) -> vm::Result<()> { 135 if let Some(dm) = datamatch { 136 match dm { 137 vm::DataMatch::DataMatch32(kvm_dm32) => self 138 .fd 139 .register_ioevent(fd, addr, kvm_dm32) 140 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())), 141 vm::DataMatch::DataMatch64(kvm_dm64) => self 142 .fd 143 .register_ioevent(fd, addr, kvm_dm64) 144 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())), 145 } 146 } else { 147 self.fd 148 .register_ioevent(fd, addr, NoDatamatch) 149 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())) 150 } 151 } 152 /// 153 /// Unregisters an event from a certain address it has been previously registered to. 154 /// 155 fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> { 156 self.fd 157 .unregister_ioevent(fd, addr) 158 .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into())) 159 } 160 /// 161 /// Sets the GSI routing table entries, overwriting any previously set 162 /// entries, as per the `KVM_SET_GSI_ROUTING` ioctl. 163 /// 164 fn set_gsi_routing(&self, irq_routing: &IrqRouting) -> vm::Result<()> { 165 self.fd 166 .set_gsi_routing(irq_routing) 167 .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into())) 168 } 169 /// 170 /// Creates/modifies a guest physical memory slot. 171 /// 172 fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> { 173 // Safe because guest regions are guaranteed not to overlap. 174 unsafe { 175 self.fd 176 .set_user_memory_region(user_memory_region) 177 .map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into())) 178 } 179 } 180 /// 181 /// Creates an emulated device in the kernel. 182 /// 183 /// See the documentation for `KVM_CREATE_DEVICE`. 184 fn create_device(&self, device: &mut CreateDevice) -> vm::Result<DeviceFd> { 185 self.fd 186 .create_device(device) 187 .map_err(|e| vm::HypervisorVmError::CreateDevice(e.into())) 188 } 189 /// 190 /// Returns the preferred CPU target type which can be emulated by KVM on underlying host. 191 /// 192 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 193 fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> { 194 self.fd 195 .get_preferred_target(kvi) 196 .map_err(|e| vm::HypervisorVmError::GetPreferredTarget(e.into())) 197 } 198 #[cfg(target_arch = "x86_64")] 199 fn enable_split_irq(&self) -> vm::Result<()> { 200 // Set TSS 201 self.fd 202 .set_tss_address(KVM_TSS_ADDRESS.raw_value() as usize) 203 .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?; 204 // Create split irqchip 205 // Only the local APIC is emulated in kernel, both PICs and IOAPIC 206 // are not. 207 let mut cap: kvm_enable_cap = Default::default(); 208 cap.cap = KVM_CAP_SPLIT_IRQCHIP; 209 cap.args[0] = NUM_IOAPIC_PINS as u64; 210 self.fd 211 .enable_cap(&cap) 212 .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?; 213 Ok(()) 214 } 215 /// Retrieve guest clock. 216 #[cfg(target_arch = "x86_64")] 217 fn get_clock(&self) -> vm::Result<ClockData> { 218 self.fd 219 .get_clock() 220 .map_err(|e| vm::HypervisorVmError::GetClock(e.into())) 221 } 222 /// Set guest clock. 223 #[cfg(target_arch = "x86_64")] 224 fn set_clock(&self, data: &ClockData) -> vm::Result<()> { 225 self.fd 226 .set_clock(data) 227 .map_err(|e| vm::HypervisorVmError::SetClock(e.into())) 228 } 229 } 230 /// Wrapper over KVM system ioctls. 231 pub struct KvmHypervisor { 232 kvm: Kvm, 233 } 234 /// Enum for KVM related error 235 #[derive(Debug)] 236 pub enum KvmError { 237 CapabilityMissing(Cap), 238 } 239 pub type KvmResult<T> = result::Result<T, KvmError>; 240 impl KvmHypervisor { 241 /// Create a hypervisor based on Kvm 242 pub fn new() -> hypervisor::Result<KvmHypervisor> { 243 let kvm_obj = Kvm::new().map_err(|e| hypervisor::HypervisorError::VmCreate(e.into()))?; 244 Ok(KvmHypervisor { kvm: kvm_obj }) 245 } 246 } 247 /// Implementation of Hypervisor trait for KVM 248 /// Example: 249 /// #[cfg(feature = "kvm")] 250 /// extern crate hypervisor 251 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap(); 252 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 253 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 254 /// 255 impl hypervisor::Hypervisor for KvmHypervisor { 256 /// Create a KVM vm object and return the object as Vm trait object 257 /// Example 258 /// # extern crate hypervisor; 259 /// # use hypervisor::KvmHypervisor; 260 /// use hypervisor::KvmVm; 261 /// let hypervisor = KvmHypervisor::new().unwrap(); 262 /// let vm = hypervisor.create_vm().unwrap() 263 /// 264 fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> { 265 let kvm = Kvm::new().map_err(|e| hypervisor::HypervisorError::VmCreate(e.into()))?; 266 267 let fd: VmFd; 268 loop { 269 match kvm.create_vm() { 270 Ok(res) => fd = res, 271 Err(e) => { 272 if e.errno() == libc::EINTR { 273 // If the error returned is EINTR, which means the 274 // ioctl has been interrupted, we have to retry as 275 // this can't be considered as a regular error. 276 continue; 277 } else { 278 return Err(hypervisor::HypervisorError::VmCreate(e.into())); 279 } 280 } 281 } 282 break; 283 } 284 let vm_fd = Arc::new(fd); 285 let kvm_fd = KvmVm { fd: vm_fd }; 286 Ok(Arc::new(kvm_fd)) 287 } 288 289 fn check_required_extensions(&self) -> hypervisor::Result<()> { 290 check_required_kvm_extensions(&self.kvm).expect("Missing KVM capabilities"); 291 Ok(()) 292 } 293 294 /// 295 /// Returns the KVM API version. 296 /// 297 fn get_api_version(&self) -> i32 { 298 self.kvm.get_api_version() 299 } 300 /// 301 /// Returns the size of the memory mapping required to use the vcpu's `kvm_run` structure. 302 /// 303 fn get_vcpu_mmap_size(&self) -> hypervisor::Result<usize> { 304 self.kvm 305 .get_vcpu_mmap_size() 306 .map_err(|e| hypervisor::HypervisorError::GetVcpuMmap(e.into())) 307 } 308 /// 309 /// Gets the recommended maximum number of VCPUs per VM. 310 /// 311 fn get_max_vcpus(&self) -> hypervisor::Result<usize> { 312 Ok(self.kvm.get_max_vcpus()) 313 } 314 /// 315 /// Gets the recommended number of VCPUs per VM. 316 /// 317 fn get_nr_vcpus(&self) -> hypervisor::Result<usize> { 318 Ok(self.kvm.get_nr_vcpus()) 319 } 320 #[cfg(target_arch = "x86_64")] 321 /// 322 /// Checks if a particular `Cap` is available. 323 /// 324 fn check_capability(&self, c: Cap) -> bool { 325 self.kvm.check_extension(c) 326 } 327 #[cfg(target_arch = "x86_64")] 328 /// 329 /// X86 specific call to get the system supported CPUID values. 330 /// 331 fn get_cpuid(&self) -> hypervisor::Result<CpuId> { 332 self.kvm 333 .get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES) 334 .map_err(|e| hypervisor::HypervisorError::GetCpuId(e.into())) 335 } 336 } 337 /// Vcpu struct for KVM 338 pub struct KvmVcpu { 339 fd: VcpuFd, 340 } 341 /// Implementation of Vcpu trait for KVM 342 /// Example: 343 /// #[cfg(feature = "kvm")] 344 /// extern crate hypervisor 345 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap(); 346 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 347 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 348 /// let vcpu = vm.create_vcpu(0).unwrap(); 349 /// vcpu.get/set().unwrap() 350 /// 351 impl cpu::Vcpu for KvmVcpu { 352 #[cfg(target_arch = "x86_64")] 353 /// 354 /// Returns the vCPU general purpose registers. 355 /// 356 fn get_regs(&self) -> cpu::Result<StandardRegisters> { 357 self.fd 358 .get_regs() 359 .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into())) 360 } 361 #[cfg(target_arch = "x86_64")] 362 /// 363 /// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl. 364 /// 365 fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> { 366 self.fd 367 .set_regs(regs) 368 .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into())) 369 } 370 #[cfg(target_arch = "x86_64")] 371 /// 372 /// Returns the vCPU special registers. 373 /// 374 fn get_sregs(&self) -> cpu::Result<SpecialRegisters> { 375 self.fd 376 .get_sregs() 377 .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into())) 378 } 379 #[cfg(target_arch = "x86_64")] 380 /// 381 /// Sets the vCPU special registers using the `KVM_SET_SREGS` ioctl. 382 /// 383 fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> { 384 self.fd 385 .set_sregs(sregs) 386 .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) 387 } 388 #[cfg(target_arch = "x86_64")] 389 /// 390 /// Returns the floating point state (FPU) from the vCPU. 391 /// 392 fn get_fpu(&self) -> cpu::Result<FpuState> { 393 self.fd 394 .get_fpu() 395 .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into())) 396 } 397 #[cfg(target_arch = "x86_64")] 398 /// 399 /// Set the floating point state (FPU) of a vCPU using the `KVM_SET_FPU` ioct. 400 /// 401 fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> { 402 self.fd 403 .set_fpu(fpu) 404 .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into())) 405 } 406 #[cfg(target_arch = "x86_64")] 407 /// 408 /// X86 specific call to setup the CPUID registers. 409 /// 410 fn set_cpuid2(&self, cpuid: &CpuId) -> cpu::Result<()> { 411 self.fd 412 .set_cpuid2(cpuid) 413 .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into())) 414 } 415 /// 416 /// X86 specific call to retrieve the CPUID registers. 417 /// 418 #[cfg(target_arch = "x86_64")] 419 fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<CpuId> { 420 self.fd 421 .get_cpuid2(num_entries) 422 .map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into())) 423 } 424 #[cfg(target_arch = "x86_64")] 425 /// 426 /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 427 /// 428 fn get_lapic(&self) -> cpu::Result<LapicState> { 429 self.fd 430 .get_lapic() 431 .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into())) 432 } 433 #[cfg(target_arch = "x86_64")] 434 /// 435 /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 436 /// 437 fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> { 438 self.fd 439 .set_lapic(klapic) 440 .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) 441 } 442 #[cfg(target_arch = "x86_64")] 443 /// 444 /// Returns the model-specific registers (MSR) for this vCPU. 445 /// 446 fn get_msrs(&self, msrs: &mut MsrEntries) -> cpu::Result<usize> { 447 self.fd 448 .get_msrs(msrs) 449 .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into())) 450 } 451 #[cfg(target_arch = "x86_64")] 452 /// 453 /// Setup the model-specific registers (MSR) for this vCPU. 454 /// Returns the number of MSR entries actually written. 455 /// 456 fn set_msrs(&self, msrs: &MsrEntries) -> cpu::Result<usize> { 457 self.fd 458 .set_msrs(msrs) 459 .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into())) 460 } 461 /// 462 /// Returns the vcpu's current "multiprocessing state". 463 /// 464 fn get_mp_state(&self) -> cpu::Result<MpState> { 465 self.fd 466 .get_mp_state() 467 .map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into())) 468 } 469 /// 470 /// Sets the vcpu's current "multiprocessing state". 471 /// 472 fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> { 473 self.fd 474 .set_mp_state(mp_state) 475 .map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into())) 476 } 477 #[cfg(target_arch = "x86_64")] 478 /// 479 /// X86 specific call that returns the vcpu's current "xsave struct". 480 /// 481 fn get_xsave(&self) -> cpu::Result<Xsave> { 482 self.fd 483 .get_xsave() 484 .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into())) 485 } 486 #[cfg(target_arch = "x86_64")] 487 /// 488 /// X86 specific call that sets the vcpu's current "xsave struct". 489 /// 490 fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> { 491 self.fd 492 .set_xsave(xsave) 493 .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into())) 494 } 495 #[cfg(target_arch = "x86_64")] 496 /// 497 /// X86 specific call that returns the vcpu's current "xcrs". 498 /// 499 fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> { 500 self.fd 501 .get_xcrs() 502 .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) 503 } 504 #[cfg(target_arch = "x86_64")] 505 /// 506 /// X86 specific call that sets the vcpu's current "xcrs". 507 /// 508 fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> { 509 self.fd 510 .set_xcrs(&xcrs) 511 .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) 512 } 513 /// 514 /// Triggers the running of the current virtual CPU returning an exit reason. 515 /// 516 fn run(&self) -> std::result::Result<VcpuExit, vmm_sys_util::errno::Error> { 517 self.fd.run() 518 } 519 #[cfg(target_arch = "x86_64")] 520 /// 521 /// Returns currently pending exceptions, interrupts, and NMIs as well as related 522 /// states of the vcpu. 523 /// 524 fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> { 525 self.fd 526 .get_vcpu_events() 527 .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) 528 } 529 #[cfg(target_arch = "x86_64")] 530 /// 531 /// Let the guest know that it has been paused, which prevents from 532 /// potential soft lockups when being resumed. 533 /// 534 fn notify_guest_clock_paused(&self) -> cpu::Result<()> { 535 self.fd 536 .kvmclock_ctrl() 537 .map_err(|e| cpu::HypervisorCpuError::NotifyGuestClockPaused(e.into())) 538 } 539 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 540 fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> { 541 self.fd 542 .vcpu_init(kvi) 543 .map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into())) 544 } 545 /// 546 /// Sets the value of one register for this vCPU. 547 /// 548 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 549 fn set_one_reg(&self, reg_id: u64, data: u64) -> cpu::Result<()> { 550 self.fd 551 .set_one_reg(reg_id, data) 552 .map_err(|e| cpu::HypervisorCpuError::SetOneReg(e.into())) 553 } 554 /// 555 /// Gets the value of one register for this vCPU. 556 /// 557 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 558 fn get_one_reg(&self, reg_id: u64) -> cpu::Result<u64> { 559 self.fd 560 .get_one_reg(reg_id) 561 .map_err(|e| cpu::HypervisorCpuError::GetOneReg(e.into())) 562 } 563 #[cfg(target_arch = "x86_64")] 564 /// Get the current CPU state 565 /// 566 /// 567 /// # Example 568 /// 569 /// ```rust 570 /// # extern crate hypervisor; 571 /// # use hypervisor::KvmHypervisor; 572 /// # use std::sync::Arc; 573 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap(); 574 /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 575 /// let vm = hv.create_vm().expect("new VM fd creation failed"); 576 /// vm.enable_split_irq().unwrap(); 577 /// let vcpu = vm.create_vcpu(0).unwrap(); 578 /// let state = vcpu.cpu_state().unwrap(); 579 /// 580 fn cpu_state(&self) -> cpu::Result<CpuState> { 581 let mut msrs = boot_msr_entries(); 582 self.get_msrs(&mut msrs)?; 583 584 let vcpu_events = self.get_vcpu_events()?; 585 let regs = self.get_regs()?; 586 let sregs = self.get_sregs()?; 587 let lapic_state = self.get_lapic()?; 588 let fpu = self.get_fpu()?; 589 let xsave = self.get_xsave()?; 590 let xcrs = self.get_xcrs()?; 591 let mp_state = self.get_mp_state()?; 592 593 Ok(CpuState { 594 msrs, 595 vcpu_events, 596 regs, 597 sregs, 598 fpu, 599 lapic_state, 600 xsave, 601 xcrs, 602 mp_state, 603 }) 604 } 605 #[cfg(target_arch = "aarch64")] 606 fn cpu_state(&self) -> cpu::Result<CpuState> { 607 unimplemented!(); 608 } 609 #[cfg(target_arch = "x86_64")] 610 /// Restore the previously saved CPU state 611 /// 612 /// Arguments: CpuState 613 /// # Example 614 /// 615 /// ```rust 616 /// # extern crate hypervisor; 617 /// # use hypervisor::KvmHypervisor; 618 /// # use std::sync::Arc; 619 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap(); 620 /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 621 /// let vm = hv.create_vm().expect("new VM fd creation failed"); 622 /// vm.enable_split_irq().unwrap(); 623 /// let vcpu = vm.create_vcpu(0).unwrap(); 624 /// let state = vcpu.cpu_state().unwrap(); 625 /// vcpu.set_cpu_state(&state).unwrap(); 626 /// 627 fn set_cpu_state(&self, state: &CpuState) -> cpu::Result<()> { 628 self.set_regs(&state.regs)?; 629 630 self.set_fpu(&state.fpu)?; 631 632 self.set_xsave(&state.xsave)?; 633 634 self.set_sregs(&state.sregs)?; 635 636 self.set_xcrs(&state.xcrs)?; 637 638 self.set_msrs(&state.msrs)?; 639 640 self.set_lapic(&state.lapic_state)?; 641 642 self.set_mp_state(state.mp_state)?; 643 644 Ok(()) 645 } 646 #[allow(unused_variables)] 647 #[cfg(target_arch = "aarch64")] 648 fn set_cpu_state(&self, state: &CpuState) -> cpu::Result<()> { 649 Ok(()) 650 } 651 } 652