xref: /cloud-hypervisor/hypervisor/src/kvm/mod.rs (revision c48d0c1a6794892a28e8a0d3778d179cb719f3dc)
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