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