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