xref: /cloud-hypervisor/hypervisor/src/kvm/mod.rs (revision cc57467d10a6ed036be81c38b6b0b8a0ddfa26ed)
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     check_required_kvm_extensions, FpuState, SpecialRegisters, StandardRegisters, KVM_TSS_ADDRESS,
30 };
31 
32 #[cfg(target_arch = "x86_64")]
33 pub use x86_64::{
34     CpuId, CpuIdEntry, ExtendedControlRegisters, LapicState, MsrEntries, VcpuKvmState as CpuState,
35     Xsave, CPUID_FLAG_VALID_INDEX,
36 };
37 
38 #[cfg(target_arch = "x86_64")]
39 use kvm_bindings::{kvm_enable_cap, MsrList, 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, KVM_MSI_VALID_DEVID,
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     #[cfg(target_arch = "x86_64")]
71     msrs: MsrEntries,
72 }
73 ///
74 /// Implementation of Vm trait for KVM
75 /// Example:
76 /// #[cfg(feature = "kvm")]
77 /// extern crate hypervisor
78 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
79 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
80 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
81 /// vm.set/get().unwrap()
82 ///
83 impl vm::Vm for KvmVm {
84     #[cfg(target_arch = "x86_64")]
85     ///
86     /// Sets the address of the three-page region in the VM's address space.
87     ///
88     fn set_tss_address(&self, offset: usize) -> vm::Result<()> {
89         self.fd
90             .set_tss_address(offset)
91             .map_err(|e| vm::HypervisorVmError::SetTssAddress(e.into()))
92     }
93     ///
94     /// Creates an in-kernel interrupt controller.
95     ///
96     fn create_irq_chip(&self) -> vm::Result<()> {
97         self.fd
98             .create_irq_chip()
99             .map_err(|e| vm::HypervisorVmError::CreateIrq(e.into()))
100     }
101     ///
102     /// Registers an event that will, when signaled, trigger the `gsi` IRQ.
103     ///
104     fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
105         self.fd
106             .register_irqfd(fd, gsi)
107             .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))
108     }
109     ///
110     /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
111     ///
112     fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
113         self.fd
114             .unregister_irqfd(fd, gsi)
115             .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))
116     }
117     ///
118     /// Creates a VcpuFd object from a vcpu RawFd.
119     ///
120     fn create_vcpu(&self, id: u8) -> vm::Result<Arc<dyn cpu::Vcpu>> {
121         let vc = self
122             .fd
123             .create_vcpu(id)
124             .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
125         let vcpu = KvmVcpu {
126             fd: vc,
127             #[cfg(target_arch = "x86_64")]
128             msrs: self.msrs.clone(),
129         };
130         Ok(Arc::new(vcpu))
131     }
132     ///
133     /// Registers an event to be signaled whenever a certain address is written to.
134     ///
135     fn register_ioevent(
136         &self,
137         fd: &EventFd,
138         addr: &IoEventAddress,
139         datamatch: Option<vm::DataMatch>,
140     ) -> vm::Result<()> {
141         if let Some(dm) = datamatch {
142             match dm {
143                 vm::DataMatch::DataMatch32(kvm_dm32) => self
144                     .fd
145                     .register_ioevent(fd, addr, kvm_dm32)
146                     .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())),
147                 vm::DataMatch::DataMatch64(kvm_dm64) => self
148                     .fd
149                     .register_ioevent(fd, addr, kvm_dm64)
150                     .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())),
151             }
152         } else {
153             self.fd
154                 .register_ioevent(fd, addr, NoDatamatch)
155                 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
156         }
157     }
158     ///
159     /// Unregisters an event from a certain address it has been previously registered to.
160     ///
161     fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
162         self.fd
163             .unregister_ioevent(fd, addr, NoDatamatch)
164             .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
165     }
166     ///
167     /// Sets the GSI routing table entries, overwriting any previously set
168     /// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
169     ///
170     fn set_gsi_routing(&self, irq_routing: &IrqRouting) -> vm::Result<()> {
171         self.fd
172             .set_gsi_routing(irq_routing)
173             .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
174     }
175     ///
176     /// Creates a memory region structure that can be used with set_user_memory_region
177     ///
178     fn make_user_memory_region(
179         &self,
180         slot: u32,
181         guest_phys_addr: u64,
182         memory_size: u64,
183         userspace_addr: u64,
184         readonly: bool,
185     ) -> MemoryRegion {
186         MemoryRegion {
187             slot,
188             guest_phys_addr,
189             memory_size,
190             userspace_addr,
191             flags: if readonly { KVM_MEM_READONLY } else { 0 },
192         }
193     }
194     ///
195     /// Creates/modifies a guest physical memory slot.
196     ///
197     fn set_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
198         // Safe because guest regions are guaranteed not to overlap.
199         unsafe {
200             self.fd
201                 .set_user_memory_region(user_memory_region)
202                 .map_err(|e| vm::HypervisorVmError::SetUserMemory(e.into()))
203         }
204     }
205     ///
206     /// Creates an emulated device in the kernel.
207     ///
208     /// See the documentation for `KVM_CREATE_DEVICE`.
209     fn create_device(&self, device: &mut CreateDevice) -> vm::Result<DeviceFd> {
210         self.fd
211             .create_device(device)
212             .map_err(|e| vm::HypervisorVmError::CreateDevice(e.into()))
213     }
214     ///
215     /// Returns the preferred CPU target type which can be emulated by KVM on underlying host.
216     ///
217     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
218     fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> {
219         self.fd
220             .get_preferred_target(kvi)
221             .map_err(|e| vm::HypervisorVmError::GetPreferredTarget(e.into()))
222     }
223     #[cfg(target_arch = "x86_64")]
224     fn enable_split_irq(&self) -> vm::Result<()> {
225         // Set TSS
226         self.fd
227             .set_tss_address(KVM_TSS_ADDRESS.raw_value() as usize)
228             .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
229         // Create split irqchip
230         // Only the local APIC is emulated in kernel, both PICs and IOAPIC
231         // are not.
232         let mut cap: kvm_enable_cap = Default::default();
233         cap.cap = KVM_CAP_SPLIT_IRQCHIP;
234         cap.args[0] = NUM_IOAPIC_PINS as u64;
235         self.fd
236             .enable_cap(&cap)
237             .map_err(|e| vm::HypervisorVmError::EnableSplitIrq(e.into()))?;
238         Ok(())
239     }
240     /// Retrieve guest clock.
241     #[cfg(target_arch = "x86_64")]
242     fn get_clock(&self) -> vm::Result<ClockData> {
243         self.fd
244             .get_clock()
245             .map_err(|e| vm::HypervisorVmError::GetClock(e.into()))
246     }
247     /// Set guest clock.
248     #[cfg(target_arch = "x86_64")]
249     fn set_clock(&self, data: &ClockData) -> vm::Result<()> {
250         self.fd
251             .set_clock(data)
252             .map_err(|e| vm::HypervisorVmError::SetClock(e.into()))
253     }
254     /// Checks if a particular `Cap` is available.
255     fn check_extension(&self, c: Cap) -> bool {
256         self.fd.check_extension(c)
257     }
258 }
259 /// Wrapper over KVM system ioctls.
260 pub struct KvmHypervisor {
261     kvm: Kvm,
262 }
263 /// Enum for KVM related error
264 #[derive(Debug)]
265 pub enum KvmError {
266     CapabilityMissing(Cap),
267 }
268 pub type KvmResult<T> = result::Result<T, KvmError>;
269 impl KvmHypervisor {
270     /// Create a hypervisor based on Kvm
271     pub fn new() -> hypervisor::Result<KvmHypervisor> {
272         let kvm_obj = Kvm::new().map_err(|e| hypervisor::HypervisorError::VmCreate(e.into()))?;
273         Ok(KvmHypervisor { kvm: kvm_obj })
274     }
275 }
276 /// Implementation of Hypervisor trait for KVM
277 /// Example:
278 /// #[cfg(feature = "kvm")]
279 /// extern crate hypervisor
280 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
281 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
282 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
283 ///
284 impl hypervisor::Hypervisor for KvmHypervisor {
285     /// Create a KVM vm object and return the object as Vm trait object
286     /// Example
287     /// # extern crate hypervisor;
288     /// # use hypervisor::KvmHypervisor;
289     /// use hypervisor::KvmVm;
290     /// let hypervisor = KvmHypervisor::new().unwrap();
291     /// let vm = hypervisor.create_vm().unwrap()
292     ///
293     fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
294         let fd: VmFd;
295         loop {
296             match self.kvm.create_vm() {
297                 Ok(res) => fd = res,
298                 Err(e) => {
299                     if e.errno() == libc::EINTR {
300                         // If the error returned is EINTR, which means the
301                         // ioctl has been interrupted, we have to retry as
302                         // this can't be considered as a regular error.
303                         continue;
304                     } else {
305                         return Err(hypervisor::HypervisorError::VmCreate(e.into()));
306                     }
307                 }
308             }
309             break;
310         }
311 
312         let vm_fd = Arc::new(fd);
313 
314         #[cfg(target_arch = "x86_64")]
315         {
316             let msr_list = self.get_msr_list()?;
317             let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
318             let mut msrs = MsrEntries::new(num_msrs);
319             let indices = msr_list.as_slice();
320             let msr_entries = msrs.as_mut_slice();
321             for (pos, index) in indices.iter().enumerate() {
322                 msr_entries[pos].index = *index;
323             }
324 
325             Ok(Arc::new(KvmVm { fd: vm_fd, msrs }))
326         }
327 
328         #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
329         {
330             Ok(Arc::new(KvmVm { fd: vm_fd }))
331         }
332     }
333 
334     fn check_required_extensions(&self) -> hypervisor::Result<()> {
335         check_required_kvm_extensions(&self.kvm).expect("Missing KVM capabilities");
336         Ok(())
337     }
338 
339     ///
340     /// Returns the KVM API version.
341     ///
342     fn get_api_version(&self) -> i32 {
343         self.kvm.get_api_version()
344     }
345     ///
346     ///  Returns the size of the memory mapping required to use the vcpu's `kvm_run` structure.
347     ///
348     fn get_vcpu_mmap_size(&self) -> hypervisor::Result<usize> {
349         self.kvm
350             .get_vcpu_mmap_size()
351             .map_err(|e| hypervisor::HypervisorError::GetVcpuMmap(e.into()))
352     }
353     ///
354     /// Gets the recommended maximum number of VCPUs per VM.
355     ///
356     fn get_max_vcpus(&self) -> hypervisor::Result<usize> {
357         Ok(self.kvm.get_max_vcpus())
358     }
359     ///
360     /// Gets the recommended number of VCPUs per VM.
361     ///
362     fn get_nr_vcpus(&self) -> hypervisor::Result<usize> {
363         Ok(self.kvm.get_nr_vcpus())
364     }
365     #[cfg(target_arch = "x86_64")]
366     ///
367     /// Checks if a particular `Cap` is available.
368     ///
369     fn check_capability(&self, c: Cap) -> bool {
370         self.kvm.check_extension(c)
371     }
372     #[cfg(target_arch = "x86_64")]
373     ///
374     /// X86 specific call to get the system supported CPUID values.
375     ///
376     fn get_cpuid(&self) -> hypervisor::Result<CpuId> {
377         self.kvm
378             .get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
379             .map_err(|e| hypervisor::HypervisorError::GetCpuId(e.into()))
380     }
381     #[cfg(target_arch = "x86_64")]
382     ///
383     /// Retrieve the list of MSRs supported by KVM.
384     ///
385     fn get_msr_list(&self) -> hypervisor::Result<MsrList> {
386         self.kvm
387             .get_msr_index_list()
388             .map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into()))
389     }
390 }
391 /// Vcpu struct for KVM
392 pub struct KvmVcpu {
393     fd: VcpuFd,
394     #[cfg(target_arch = "x86_64")]
395     msrs: MsrEntries,
396 }
397 /// Implementation of Vcpu trait for KVM
398 /// Example:
399 /// #[cfg(feature = "kvm")]
400 /// extern crate hypervisor
401 /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
402 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
403 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
404 /// let vcpu = vm.create_vcpu(0).unwrap();
405 /// vcpu.get/set().unwrap()
406 ///
407 impl cpu::Vcpu for KvmVcpu {
408     #[cfg(target_arch = "x86_64")]
409     ///
410     /// Returns the vCPU general purpose registers.
411     ///
412     fn get_regs(&self) -> cpu::Result<StandardRegisters> {
413         self.fd
414             .get_regs()
415             .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))
416     }
417     #[cfg(target_arch = "x86_64")]
418     ///
419     /// Sets the vCPU general purpose registers using the `KVM_SET_REGS` ioctl.
420     ///
421     fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
422         self.fd
423             .set_regs(regs)
424             .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
425     }
426     #[cfg(target_arch = "x86_64")]
427     ///
428     /// Returns the vCPU special registers.
429     ///
430     fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
431         self.fd
432             .get_sregs()
433             .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))
434     }
435     #[cfg(target_arch = "x86_64")]
436     ///
437     /// Sets the vCPU special registers using the `KVM_SET_SREGS` ioctl.
438     ///
439     fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
440         self.fd
441             .set_sregs(sregs)
442             .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
443     }
444     #[cfg(target_arch = "x86_64")]
445     ///
446     /// Returns the floating point state (FPU) from the vCPU.
447     ///
448     fn get_fpu(&self) -> cpu::Result<FpuState> {
449         self.fd
450             .get_fpu()
451             .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))
452     }
453     #[cfg(target_arch = "x86_64")]
454     ///
455     /// Set the floating point state (FPU) of a vCPU using the `KVM_SET_FPU` ioct.
456     ///
457     fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> {
458         self.fd
459             .set_fpu(fpu)
460             .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
461     }
462     #[cfg(target_arch = "x86_64")]
463     ///
464     /// X86 specific call to setup the CPUID registers.
465     ///
466     fn set_cpuid2(&self, cpuid: &CpuId) -> cpu::Result<()> {
467         self.fd
468             .set_cpuid2(cpuid)
469             .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
470     }
471     ///
472     /// X86 specific call to retrieve the CPUID registers.
473     ///
474     #[cfg(target_arch = "x86_64")]
475     fn get_cpuid2(&self, num_entries: usize) -> cpu::Result<CpuId> {
476         self.fd
477             .get_cpuid2(num_entries)
478             .map_err(|e| cpu::HypervisorCpuError::GetCpuid(e.into()))
479     }
480     #[cfg(target_arch = "x86_64")]
481     ///
482     /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
483     ///
484     fn get_lapic(&self) -> cpu::Result<LapicState> {
485         self.fd
486             .get_lapic()
487             .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))
488     }
489     #[cfg(target_arch = "x86_64")]
490     ///
491     /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
492     ///
493     fn set_lapic(&self, klapic: &LapicState) -> cpu::Result<()> {
494         self.fd
495             .set_lapic(klapic)
496             .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
497     }
498     #[cfg(target_arch = "x86_64")]
499     ///
500     /// Returns the model-specific registers (MSR) for this vCPU.
501     ///
502     fn get_msrs(&self, msrs: &mut MsrEntries) -> cpu::Result<usize> {
503         self.fd
504             .get_msrs(msrs)
505             .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))
506     }
507     #[cfg(target_arch = "x86_64")]
508     ///
509     /// Setup the model-specific registers (MSR) for this vCPU.
510     /// Returns the number of MSR entries actually written.
511     ///
512     fn set_msrs(&self, msrs: &MsrEntries) -> cpu::Result<usize> {
513         self.fd
514             .set_msrs(msrs)
515             .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
516     }
517     ///
518     /// Returns the vcpu's current "multiprocessing state".
519     ///
520     fn get_mp_state(&self) -> cpu::Result<MpState> {
521         self.fd
522             .get_mp_state()
523             .map_err(|e| cpu::HypervisorCpuError::GetMpState(e.into()))
524     }
525     ///
526     /// Sets the vcpu's current "multiprocessing state".
527     ///
528     fn set_mp_state(&self, mp_state: MpState) -> cpu::Result<()> {
529         self.fd
530             .set_mp_state(mp_state)
531             .map_err(|e| cpu::HypervisorCpuError::SetMpState(e.into()))
532     }
533     #[cfg(target_arch = "x86_64")]
534     ///
535     /// X86 specific call that returns the vcpu's current "xsave struct".
536     ///
537     fn get_xsave(&self) -> cpu::Result<Xsave> {
538         self.fd
539             .get_xsave()
540             .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
541     }
542     #[cfg(target_arch = "x86_64")]
543     ///
544     /// X86 specific call that sets the vcpu's current "xsave struct".
545     ///
546     fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
547         self.fd
548             .set_xsave(xsave)
549             .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
550     }
551     #[cfg(target_arch = "x86_64")]
552     ///
553     /// X86 specific call that returns the vcpu's current "xcrs".
554     ///
555     fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> {
556         self.fd
557             .get_xcrs()
558             .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
559     }
560     #[cfg(target_arch = "x86_64")]
561     ///
562     /// X86 specific call that sets the vcpu's current "xcrs".
563     ///
564     fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
565         self.fd
566             .set_xcrs(&xcrs)
567             .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
568     }
569     ///
570     /// Triggers the running of the current virtual CPU returning an exit reason.
571     ///
572     fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
573         match self.fd.run() {
574             Ok(run) => match run {
575                 #[cfg(target_arch = "x86_64")]
576                 VcpuExit::IoIn(addr, data) => Ok(cpu::VmExit::IoIn(addr, data)),
577                 #[cfg(target_arch = "x86_64")]
578                 VcpuExit::IoOut(addr, data) => Ok(cpu::VmExit::IoOut(addr, data)),
579                 #[cfg(target_arch = "x86_64")]
580                 VcpuExit::IoapicEoi(vector) => Ok(cpu::VmExit::IoapicEoi(vector)),
581                 #[cfg(target_arch = "x86_64")]
582                 VcpuExit::Shutdown | VcpuExit::Hlt => Ok(cpu::VmExit::Reset),
583 
584                 #[cfg(target_arch = "aarch64")]
585                 VcpuExit::SystemEvent(event_type, flags) => {
586                     use kvm_bindings::KVM_SYSTEM_EVENT_SHUTDOWN;
587                     // On Aarch64, when the VM is shutdown, run() returns
588                     // VcpuExit::SystemEvent with reason KVM_SYSTEM_EVENT_SHUTDOWN
589                     if event_type == KVM_SYSTEM_EVENT_SHUTDOWN {
590                         Ok(cpu::VmExit::Reset)
591                     } else {
592                         Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
593                             "Unexpected system event with type 0x{:x}, flags 0x{:x}",
594                             event_type,
595                             flags
596                         )))
597                     }
598                 }
599 
600                 VcpuExit::MmioRead(addr, data) => Ok(cpu::VmExit::MmioRead(addr, data)),
601                 VcpuExit::MmioWrite(addr, data) => Ok(cpu::VmExit::MmioWrite(addr, data)),
602 
603                 r => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
604                     "Unexpected exit reason on vcpu run: {:?}",
605                     r
606                 ))),
607             },
608 
609             Err(ref e) => match e.errno() {
610                 libc::EAGAIN | libc::EINTR => Ok(cpu::VmExit::Ignore),
611                 _ => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
612                     "VCPU error {:?}",
613                     e
614                 ))),
615             },
616         }
617     }
618     #[cfg(target_arch = "x86_64")]
619     ///
620     /// Returns currently pending exceptions, interrupts, and NMIs as well as related
621     /// states of the vcpu.
622     ///
623     fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> {
624         self.fd
625             .get_vcpu_events()
626             .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
627     }
628     #[cfg(target_arch = "x86_64")]
629     ///
630     /// Sets pending exceptions, interrupts, and NMIs as well as related states
631     /// of the vcpu.
632     ///
633     fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> {
634         self.fd
635             .set_vcpu_events(events)
636             .map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
637     }
638     #[cfg(target_arch = "x86_64")]
639     ///
640     /// Let the guest know that it has been paused, which prevents from
641     /// potential soft lockups when being resumed.
642     ///
643     fn notify_guest_clock_paused(&self) -> cpu::Result<()> {
644         self.fd
645             .kvmclock_ctrl()
646             .map_err(|e| cpu::HypervisorCpuError::NotifyGuestClockPaused(e.into()))
647     }
648     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
649     fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
650         self.fd
651             .vcpu_init(kvi)
652             .map_err(|e| cpu::HypervisorCpuError::VcpuInit(e.into()))
653     }
654     ///
655     /// Sets the value of one register for this vCPU.
656     ///
657     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
658     fn set_one_reg(&self, reg_id: u64, data: u64) -> cpu::Result<()> {
659         self.fd
660             .set_one_reg(reg_id, data)
661             .map_err(|e| cpu::HypervisorCpuError::SetOneReg(e.into()))
662     }
663     ///
664     /// Gets the value of one register for this vCPU.
665     ///
666     #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
667     fn get_one_reg(&self, reg_id: u64) -> cpu::Result<u64> {
668         self.fd
669             .get_one_reg(reg_id)
670             .map_err(|e| cpu::HypervisorCpuError::GetOneReg(e.into()))
671     }
672     #[cfg(target_arch = "x86_64")]
673     ///
674     /// Get the current CPU state
675     ///
676     /// Ordering requirements:
677     ///
678     /// KVM_GET_MP_STATE calls kvm_apic_accept_events(), which might modify
679     /// vCPU/LAPIC state. As such, it must be done before most everything
680     /// else, otherwise we cannot restore everything and expect it to work.
681     ///
682     /// KVM_GET_VCPU_EVENTS/KVM_SET_VCPU_EVENTS is unsafe if other vCPUs are
683     /// still running.
684     ///
685     /// KVM_GET_LAPIC may change state of LAPIC before returning it.
686     ///
687     /// GET_VCPU_EVENTS should probably be last to save. The code looks as
688     /// it might as well be affected by internal state modifications of the
689     /// GET ioctls.
690     ///
691     /// SREGS saves/restores a pending interrupt, similar to what
692     /// VCPU_EVENTS also does.
693     ///
694     /// GET_MSRS requires a pre-populated data structure to do something
695     /// meaningful. For SET_MSRS it will then contain good data.
696     ///
697     /// # Example
698     ///
699     /// ```rust
700     /// # extern crate hypervisor;
701     /// # use hypervisor::KvmHypervisor;
702     /// # use std::sync::Arc;
703     /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
704     /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
705     /// let vm = hv.create_vm().expect("new VM fd creation failed");
706     /// vm.enable_split_irq().unwrap();
707     /// let vcpu = vm.create_vcpu(0).unwrap();
708     /// let state = vcpu.state().unwrap();
709     /// ```
710     fn state(&self) -> cpu::Result<CpuState> {
711         let mp_state = self.get_mp_state()?;
712         let regs = self.get_regs()?;
713         let sregs = self.get_sregs()?;
714         let xsave = self.get_xsave()?;
715         let xcrs = self.get_xcrs()?;
716         let lapic_state = self.get_lapic()?;
717         let fpu = self.get_fpu()?;
718         let mut msrs = self.msrs.clone();
719         self.get_msrs(&mut msrs)?;
720         let vcpu_events = self.get_vcpu_events()?;
721 
722         Ok(CpuState {
723             msrs,
724             vcpu_events,
725             regs,
726             sregs,
727             fpu,
728             lapic_state,
729             xsave,
730             xcrs,
731             mp_state,
732         })
733     }
734     #[cfg(target_arch = "aarch64")]
735     fn state(&self) -> cpu::Result<CpuState> {
736         unimplemented!();
737     }
738     #[cfg(target_arch = "x86_64")]
739     ///
740     /// Restore the previously saved CPU state
741     ///
742     /// Ordering requirements:
743     ///
744     /// KVM_GET_VCPU_EVENTS/KVM_SET_VCPU_EVENTS is unsafe if other vCPUs are
745     /// still running.
746     ///
747     /// Some SET ioctls (like set_mp_state) depend on kvm_vcpu_is_bsp(), so
748     /// if we ever change the BSP, we have to do that before restoring anything.
749     /// The same seems to be true for CPUID stuff.
750     ///
751     /// SREGS saves/restores a pending interrupt, similar to what
752     /// VCPU_EVENTS also does.
753     ///
754     /// SET_REGS clears pending exceptions unconditionally, thus, it must be
755     /// done before SET_VCPU_EVENTS, which restores it.
756     ///
757     /// SET_LAPIC must come after SET_SREGS, because the latter restores
758     /// the apic base msr.
759     ///
760     /// SET_LAPIC must come before SET_MSRS, because the TSC deadline MSR
761     /// only restores successfully, when the LAPIC is correctly configured.
762     ///
763     /// Arguments: CpuState
764     /// # Example
765     ///
766     /// ```rust
767     /// # extern crate hypervisor;
768     /// # use hypervisor::KvmHypervisor;
769     /// # use std::sync::Arc;
770     /// let kvm = hypervisor::kvm::KvmHypervisor::new().unwrap();
771     /// let hv: Arc<dyn hypervisor::Hypervisor> = Arc::new(kvm);
772     /// let vm = hv.create_vm().expect("new VM fd creation failed");
773     /// vm.enable_split_irq().unwrap();
774     /// let vcpu = vm.create_vcpu(0).unwrap();
775     /// let state = vcpu.state().unwrap();
776     /// vcpu.set_state(&state).unwrap();
777     /// ```
778     fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
779         self.set_mp_state(state.mp_state)?;
780         self.set_regs(&state.regs)?;
781         self.set_sregs(&state.sregs)?;
782         self.set_xsave(&state.xsave)?;
783         self.set_xcrs(&state.xcrs)?;
784         self.set_lapic(&state.lapic_state)?;
785         self.set_fpu(&state.fpu)?;
786         self.set_msrs(&state.msrs)?;
787         self.set_vcpu_events(&state.vcpu_events)?;
788 
789         Ok(())
790     }
791     #[allow(unused_variables)]
792     #[cfg(target_arch = "aarch64")]
793     fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
794         Ok(())
795     }
796 }
797