1 // Copyright © 2019 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 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 unsafe { 174 self.fd 175 .set_user_memory_region(user_memory_region) 176 .map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into())) 177 } 178 } 179 /// 180 /// Creates an emulated device in the kernel. 181 /// 182 /// See the documentation for `KVM_CREATE_DEVICE`. 183 fn create_device(&self, device: &mut CreateDevice) -> vm::Result<DeviceFd> { 184 self.fd 185 .create_device(device) 186 .map_err(|e| vm::HypervisorVmError::CreateDevice(e.into())) 187 } 188 /// 189 /// Returns the preferred CPU target type which can be emulated by KVM on underlying host. 190 /// 191 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 192 fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> { 193 self.fd 194 .get_preferred_target(kvi) 195 .map_err(|e| vm::HypervisorVmError::GetPreferredTarget(e.into())) 196 } 197 #[cfg(target_arch = "x86_64")] 198 fn enable_split_irq(&self) -> vm::Result<()> { 199 // Set TSS 200 self.fd 201 .set_tss_address(KVM_TSS_ADDRESS.raw_value() as usize) 202 .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?; 203 // Create split irqchip 204 // Only the local APIC is emulated in kernel, both PICs and IOAPIC 205 // are not. 206 let mut cap: kvm_enable_cap = Default::default(); 207 cap.cap = KVM_CAP_SPLIT_IRQCHIP; 208 cap.args[0] = NUM_IOAPIC_PINS as u64; 209 self.fd 210 .enable_cap(&cap) 211 .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?; 212 Ok(()) 213 } 214 /// Retrieve guest clock. 215 #[cfg(target_arch = "x86_64")] 216 fn get_clock(&self) -> vm::Result<ClockData> { 217 self.fd 218 .get_clock() 219 .map_err(|e| vm::HypervisorVmError::GetClock(e.into())) 220 } 221 /// Set guest clock. 222 #[cfg(target_arch = "x86_64")] 223 fn set_clock(&self, data: &ClockData) -> vm::Result<()> { 224 self.fd 225 .set_clock(data) 226 .map_err(|e| vm::HypervisorVmError::SetClock(e.into())) 227 } 228 } 229 /// Wrapper over KVM system ioctls. 230 pub struct KvmHyperVisor { 231 kvm: Kvm, 232 } 233 /// Enum for KVM related error 234 #[derive(Debug)] 235 pub enum KvmError { 236 CapabilityMissing(Cap), 237 } 238 pub type KvmResult<T> = result::Result<T, KvmError>; 239 impl KvmHyperVisor { 240 /// Create a hypervisor based on Kvm 241 pub fn new() -> hypervisor::Result<KvmHyperVisor> { 242 let kvm_obj = Kvm::new().map_err(|e| hypervisor::HypervisorError::VmCreate(e.into()))?; 243 Ok(KvmHyperVisor { kvm: kvm_obj }) 244 } 245 } 246 /// Implementation of Hypervisor trait for KVM 247 /// Example: 248 /// #[cfg(feature = "kvm")] 249 /// extern crate hypervisor 250 /// let kvm = hypervisor::kvm::KvmHyperVisor::new().unwrap(); 251 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 252 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 253 /// 254 impl hypervisor::Hypervisor for KvmHyperVisor { 255 /// Create a KVM vm object and return the object as Vm trait object 256 /// Example 257 /// # extern crate hypervisor; 258 /// # use hypervisor::KvmHyperVisor; 259 /// use hypervisor::KvmVm; 260 /// let hypervisor = KvmHyperVisor::new().unwrap(); 261 /// let vm = hypervisor.create_vm().unwrap() 262 /// 263 fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> { 264 let kvm = Kvm::new().map_err(|e| hypervisor::HypervisorError::VmCreate(e.into()))?; 265 266 let fd: VmFd; 267 loop { 268 match kvm.create_vm() { 269 Ok(res) => fd = res, 270 Err(e) => { 271 if e.errno() == libc::EINTR { 272 // If the error returned is EINTR, which means the 273 // ioctl has been interrupted, we have to retry as 274 // this can't be considered as a regular error. 275 continue; 276 } else { 277 return Err(hypervisor::HypervisorError::VmCreate(e.into())); 278 } 279 } 280 } 281 break; 282 } 283 let vm_fd = Arc::new(fd); 284 let kvm_fd = KvmVm { fd: vm_fd }; 285 Ok(Arc::new(kvm_fd)) 286 } 287 288 fn check_required_extensions(&self) -> hypervisor::Result<()> { 289 check_required_kvm_extensions(&self.kvm).expect("Missing KVM capabilities"); 290 Ok(()) 291 } 292 293 /// 294 /// Returns the KVM API version. 295 /// 296 fn get_api_version(&self) -> i32 { 297 self.kvm.get_api_version() 298 } 299 /// 300 /// Returns the size of the memory mapping required to use the vcpu's `kvm_run` structure. 301 /// 302 fn get_vcpu_mmap_size(&self) -> hypervisor::Result<usize> { 303 self.kvm 304 .get_vcpu_mmap_size() 305 .map_err(|e| hypervisor::HypervisorError::GetVcpuMmap(e.into())) 306 } 307 /// 308 /// Gets the recommended maximum number of VCPUs per VM. 309 /// 310 fn get_max_vcpus(&self) -> hypervisor::Result<usize> { 311 Ok(self.kvm.get_max_vcpus()) 312 } 313 /// 314 /// Gets the recommended number of VCPUs per VM. 315 /// 316 fn get_nr_vcpus(&self) -> hypervisor::Result<usize> { 317 Ok(self.kvm.get_nr_vcpus()) 318 } 319 #[cfg(target_arch = "x86_64")] 320 /// 321 /// Checks if a particular `Cap` is available. 322 /// 323 fn check_capability(&self, c: Cap) -> bool { 324 self.kvm.check_extension(c) 325 } 326 #[cfg(target_arch = "x86_64")] 327 /// 328 /// X86 specific call to get the system supported CPUID values. 329 /// 330 fn get_cpuid(&self) -> hypervisor::Result<CpuId> { 331 self.kvm 332 .get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES) 333 .map_err(|e| hypervisor::HypervisorError::GetCpuId(e.into())) 334 } 335 } 336 /// Vcpu struct for KVM 337 pub struct KvmVcpu { 338 fd: VcpuFd, 339 } 340 /// Implementation of Vcpu trait for KVM 341 /// Example: 342 /// #[cfg(feature = "kvm")] 343 /// extern crate hypervisor 344 /// let kvm = hypervisor::kvm::KvmHyperVisor::new().unwrap(); 345 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 346 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed"); 347 /// let vcpu = vm.create_vcpu(0).unwrap(); 348 /// vcpu.get/set().unwrap() 349 /// 350 impl cpu::Vcpu for KvmVcpu { 351 #[cfg(target_arch = "x86_64")] 352 /// 353 /// Returns the vCPU general purpose registers. 354 /// 355 fn get_regs(&self) -> cpu::Result<StandardRegisters> { 356 self.fd 357 .get_regs() 358 .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into())) 359 } 360 #[cfg(target_arch = "x86_64")] 361 /// 362 /// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl. 363 /// 364 fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> { 365 self.fd 366 .set_regs(regs) 367 .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into())) 368 } 369 #[cfg(target_arch = "x86_64")] 370 /// 371 /// Returns the vCPU special registers. 372 /// 373 fn get_sregs(&self) -> cpu::Result<SpecialRegisters> { 374 self.fd 375 .get_sregs() 376 .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into())) 377 } 378 #[cfg(target_arch = "x86_64")] 379 /// 380 /// Sets the vCPU special registers using the `KVM_SET_SREGS` ioctl. 381 /// 382 fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> { 383 self.fd 384 .set_sregs(sregs) 385 .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into())) 386 } 387 #[cfg(target_arch = "x86_64")] 388 /// 389 /// Returns the floating point state (FPU) from the vCPU. 390 /// 391 fn get_fpu(&self) -> cpu::Result<FpuState> { 392 self.fd 393 .get_fpu() 394 .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into())) 395 } 396 #[cfg(target_arch = "x86_64")] 397 /// 398 /// Set the floating point state (FPU) of a vCPU using the `KVM_SET_FPU` ioct. 399 /// 400 fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> { 401 self.fd 402 .set_fpu(fpu) 403 .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into())) 404 } 405 #[cfg(target_arch = "x86_64")] 406 /// 407 /// X86 specific call to setup the CPUID registers. 408 /// 409 fn set_cpuid2(&self, cpuid: &CpuId) -> cpu::Result<()> { 410 self.fd 411 .set_cpuid2(cpuid) 412 .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into())) 413 } 414 /// 415 /// X86 specific call to retrieve the CPUID registers. 416 /// 417 #[cfg(target_arch = "x86_64")] 418 fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<CpuId> { 419 self.fd 420 .get_cpuid2(num_entries) 421 .map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into())) 422 } 423 #[cfg(target_arch = "x86_64")] 424 /// 425 /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 426 /// 427 fn get_lapic(&self) -> cpu::Result<LapicState> { 428 self.fd 429 .get_lapic() 430 .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into())) 431 } 432 #[cfg(target_arch = "x86_64")] 433 /// 434 /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller). 435 /// 436 fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> { 437 self.fd 438 .set_lapic(klapic) 439 .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into())) 440 } 441 #[cfg(target_arch = "x86_64")] 442 /// 443 /// Returns the model-specific registers (MSR) for this vCPU. 444 /// 445 fn get_msrs(&self, msrs: &mut MsrEntries) -> cpu::Result<usize> { 446 self.fd 447 .get_msrs(msrs) 448 .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into())) 449 } 450 #[cfg(target_arch = "x86_64")] 451 /// 452 /// Setup the model-specific registers (MSR) for this vCPU. 453 /// Returns the number of MSR entries actually written. 454 /// 455 fn set_msrs(&self, msrs: &MsrEntries) -> cpu::Result<usize> { 456 self.fd 457 .set_msrs(msrs) 458 .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into())) 459 } 460 /// 461 /// Returns the vcpu's current "multiprocessing state". 462 /// 463 fn get_mp_state(&self) -> cpu::Result<MpState> { 464 self.fd 465 .get_mp_state() 466 .map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into())) 467 } 468 /// 469 /// Sets the vcpu's current "multiprocessing state". 470 /// 471 fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> { 472 self.fd 473 .set_mp_state(mp_state) 474 .map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into())) 475 } 476 #[cfg(target_arch = "x86_64")] 477 /// 478 /// X86 specific call that returns the vcpu's current "xsave struct". 479 /// 480 fn get_xsave(&self) -> cpu::Result<Xsave> { 481 self.fd 482 .get_xsave() 483 .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into())) 484 } 485 #[cfg(target_arch = "x86_64")] 486 /// 487 /// X86 specific call that sets the vcpu's current "xsave struct". 488 /// 489 fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> { 490 self.fd 491 .set_xsave(xsave) 492 .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into())) 493 } 494 #[cfg(target_arch = "x86_64")] 495 /// 496 /// X86 specific call that returns the vcpu's current "xcrs". 497 /// 498 fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> { 499 self.fd 500 .get_xcrs() 501 .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into())) 502 } 503 #[cfg(target_arch = "x86_64")] 504 /// 505 /// X86 specific call that sets the vcpu's current "xcrs". 506 /// 507 fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> { 508 self.fd 509 .set_xcrs(&xcrs) 510 .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into())) 511 } 512 /// 513 /// Triggers the running of the current virtual CPU returning an exit reason. 514 /// 515 fn run(&self) -> std::result::Result<VcpuExit, vmm_sys_util::errno::Error> { 516 self.fd.run() 517 } 518 #[cfg(target_arch = "x86_64")] 519 /// 520 /// Returns currently pending exceptions, interrupts, and NMIs as well as related 521 /// states of the vcpu. 522 /// 523 fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> { 524 self.fd 525 .get_vcpu_events() 526 .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into())) 527 } 528 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 529 fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> { 530 self.fd 531 .vcpu_init(kvi) 532 .map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into())) 533 } 534 /// 535 /// Sets the value of one register for this vCPU. 536 /// 537 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 538 fn set_one_reg(&self, reg_id: u64, data: u64) -> cpu::Result<()> { 539 self.fd 540 .set_one_reg(reg_id, data) 541 .map_err(|e| cpu::HypervisorCpuError::SetOneReg(e.into())) 542 } 543 /// 544 /// Gets the value of one register for this vCPU. 545 /// 546 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))] 547 fn get_one_reg(&self, reg_id: u64) -> cpu::Result<u64> { 548 self.fd 549 .get_one_reg(reg_id) 550 .map_err(|e| cpu::HypervisorCpuError::GetOneReg(e.into())) 551 } 552 #[cfg(target_arch = "x86_64")] 553 /// Get the current CPU state 554 /// 555 /// 556 /// # Example 557 /// 558 /// ```rust 559 /// # extern crate hypervisor; 560 /// # use hypervisor::KvmHyperVisor; 561 /// # use std::sync::Arc; 562 /// let kvm = hypervisor::kvm::KvmHyperVisor::new().unwrap(); 563 /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 564 /// let vm = hv.create_vm().expect("new VM fd creation failed"); 565 /// vm.enable_split_irq().unwrap(); 566 /// let vcpu = vm.create_vcpu(0).unwrap(); 567 /// let state = vcpu.cpu_state().unwrap(); 568 /// 569 fn cpu_state(&self) -> cpu::Result<CpuState> { 570 let mut msrs = boot_msr_entries(); 571 self.get_msrs(&mut msrs)?; 572 573 let vcpu_events = self.get_vcpu_events()?; 574 let regs = self.get_regs()?; 575 let sregs = self.get_sregs()?; 576 let lapic_state = self.get_lapic()?; 577 let fpu = self.get_fpu()?; 578 let xsave = self.get_xsave()?; 579 let xcrs = self.get_xcrs()?; 580 let mp_state = self.get_mp_state()?; 581 582 Ok(CpuState { 583 msrs, 584 vcpu_events, 585 regs, 586 sregs, 587 fpu, 588 lapic_state, 589 xsave, 590 xcrs, 591 mp_state, 592 }) 593 } 594 #[cfg(target_arch = "aarch64")] 595 fn cpu_state(&self) -> cpu::Result<CpuState> { 596 unimplemented!(); 597 } 598 #[cfg(target_arch = "x86_64")] 599 /// Restore the previously saved CPU state 600 /// 601 /// Arguments: CpuState 602 /// # Example 603 /// 604 /// ```rust 605 /// # extern crate hypervisor; 606 /// # use hypervisor::KvmHyperVisor; 607 /// # use std::sync::Arc; 608 /// let kvm = hypervisor::kvm::KvmHyperVisor::new().unwrap(); 609 /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm); 610 /// let vm = hv.create_vm().expect("new VM fd creation failed"); 611 /// vm.enable_split_irq().unwrap(); 612 /// let vcpu = vm.create_vcpu(0).unwrap(); 613 /// let state = vcpu.cpu_state().unwrap(); 614 /// vcpu.set_cpu_state(&state).unwrap(); 615 /// 616 fn set_cpu_state(&self, state: &CpuState) -> cpu::Result<()> { 617 self.set_regs(&state.regs)?; 618 619 self.set_fpu(&state.fpu)?; 620 621 self.set_xsave(&state.xsave)?; 622 623 self.set_sregs(&state.sregs)?; 624 625 self.set_xcrs(&state.xcrs)?; 626 627 self.set_msrs(&state.msrs)?; 628 629 self.set_lapic(&state.lapic_state)?; 630 631 self.set_mp_state(state.mp_state)?; 632 633 Ok(()) 634 } 635 #[allow(unused_variables)] 636 #[cfg(target_arch = "aarch64")] 637 fn set_cpu_state(&self, state: &CpuState) -> cpu::Result<()> { 638 Ok(()) 639 } 640 } 641