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