xref: /cloud-hypervisor/hypervisor/src/mshv/mod.rs (revision 50bac1694f5bb305f00f02dc257896536eac5e0f)
1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
2 //
3 // Copyright © 2020, Microsoft Corporation
4 //
5 
6 use std::any::Any;
7 use std::collections::HashMap;
8 #[cfg(feature = "sev_snp")]
9 use std::num::NonZeroUsize;
10 use std::sync::{Arc, RwLock};
11 
12 #[cfg(feature = "sev_snp")]
13 use arc_swap::ArcSwap;
14 use mshv_bindings::*;
15 use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd, VmType};
16 use vfio_ioctls::VfioDeviceFd;
17 use vm::DataMatch;
18 #[cfg(feature = "sev_snp")]
19 use vm_memory::bitmap::AtomicBitmap;
20 
21 use crate::arch::emulator::PlatformEmulator;
22 #[cfg(target_arch = "x86_64")]
23 use crate::arch::x86::emulator::Emulator;
24 use crate::mshv::emulator::MshvEmulatorContext;
25 use crate::vm::{self, InterruptSourceConfig, VmOps};
26 use crate::{cpu, hypervisor, vec_with_array_field, HypervisorType};
27 #[cfg(feature = "sev_snp")]
28 mod snp_constants;
29 // x86_64 dependencies
30 #[cfg(target_arch = "x86_64")]
31 pub mod x86_64;
32 #[cfg(target_arch = "x86_64")]
33 use std::fs::File;
34 use std::os::unix::io::AsRawFd;
35 
36 #[cfg(feature = "sev_snp")]
37 use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
38 #[cfg(feature = "sev_snp")]
39 use snp_constants::*;
40 use vmm_sys_util::eventfd::EventFd;
41 #[cfg(target_arch = "x86_64")]
42 pub use x86_64::*;
43 #[cfg(target_arch = "x86_64")]
44 pub use x86_64::{emulator, VcpuMshvState};
45 ///
46 /// Export generically-named wrappers of mshv-bindings for Unix-based platforms
47 ///
48 pub use {
49     mshv_bindings::mshv_create_device as CreateDevice,
50     mshv_bindings::mshv_device_attr as DeviceAttr, mshv_ioctls, mshv_ioctls::DeviceFd,
51 };
52 
53 #[cfg(target_arch = "x86_64")]
54 use crate::arch::x86::{CpuIdEntry, FpuState, MsrEntry};
55 #[cfg(target_arch = "x86_64")]
56 use crate::ClockData;
57 use crate::{
58     CpuState, IoEventAddress, IrqRoutingEntry, MpState, UserMemoryRegion,
59     USER_MEMORY_REGION_ADJUSTABLE, USER_MEMORY_REGION_EXECUTE, USER_MEMORY_REGION_READ,
60     USER_MEMORY_REGION_WRITE,
61 };
62 
63 pub const PAGE_SHIFT: usize = 12;
64 
65 impl From<mshv_user_mem_region> for UserMemoryRegion {
66     fn from(region: mshv_user_mem_region) -> Self {
67         let mut flags: u32 = USER_MEMORY_REGION_READ | USER_MEMORY_REGION_ADJUSTABLE;
68         if region.flags & (1 << MSHV_SET_MEM_BIT_WRITABLE) != 0 {
69             flags |= USER_MEMORY_REGION_WRITE;
70         }
71         if region.flags & (1 << MSHV_SET_MEM_BIT_EXECUTABLE) != 0 {
72             flags |= USER_MEMORY_REGION_EXECUTE;
73         }
74 
75         UserMemoryRegion {
76             guest_phys_addr: (region.guest_pfn << PAGE_SHIFT as u64)
77                 + (region.userspace_addr & ((1 << PAGE_SHIFT) - 1)),
78             memory_size: region.size,
79             userspace_addr: region.userspace_addr,
80             flags,
81             ..Default::default()
82         }
83     }
84 }
85 
86 #[cfg(target_arch = "x86_64")]
87 impl From<MshvClockData> for ClockData {
88     fn from(d: MshvClockData) -> Self {
89         ClockData::Mshv(d)
90     }
91 }
92 
93 #[cfg(target_arch = "x86_64")]
94 impl From<ClockData> for MshvClockData {
95     fn from(ms: ClockData) -> Self {
96         match ms {
97             ClockData::Mshv(s) => s,
98             /* Needed in case other hypervisors are enabled */
99             #[allow(unreachable_patterns)]
100             _ => unreachable!("MSHV clock data is not valid"),
101         }
102     }
103 }
104 
105 impl From<UserMemoryRegion> for mshv_user_mem_region {
106     fn from(region: UserMemoryRegion) -> Self {
107         let mut flags: u8 = 0;
108         if region.flags & USER_MEMORY_REGION_WRITE != 0 {
109             flags |= 1 << MSHV_SET_MEM_BIT_WRITABLE;
110         }
111         if region.flags & USER_MEMORY_REGION_EXECUTE != 0 {
112             flags |= 1 << MSHV_SET_MEM_BIT_EXECUTABLE;
113         }
114 
115         mshv_user_mem_region {
116             guest_pfn: region.guest_phys_addr >> PAGE_SHIFT,
117             size: region.memory_size,
118             userspace_addr: region.userspace_addr,
119             flags,
120             ..Default::default()
121         }
122     }
123 }
124 
125 impl From<mshv_ioctls::IoEventAddress> for IoEventAddress {
126     fn from(a: mshv_ioctls::IoEventAddress) -> Self {
127         match a {
128             mshv_ioctls::IoEventAddress::Pio(x) => Self::Pio(x),
129             mshv_ioctls::IoEventAddress::Mmio(x) => Self::Mmio(x),
130         }
131     }
132 }
133 
134 impl From<IoEventAddress> for mshv_ioctls::IoEventAddress {
135     fn from(a: IoEventAddress) -> Self {
136         match a {
137             IoEventAddress::Pio(x) => Self::Pio(x),
138             IoEventAddress::Mmio(x) => Self::Mmio(x),
139         }
140     }
141 }
142 
143 impl From<VcpuMshvState> for CpuState {
144     fn from(s: VcpuMshvState) -> Self {
145         CpuState::Mshv(s)
146     }
147 }
148 
149 impl From<CpuState> for VcpuMshvState {
150     fn from(s: CpuState) -> Self {
151         match s {
152             CpuState::Mshv(s) => s,
153             /* Needed in case other hypervisors are enabled */
154             #[allow(unreachable_patterns)]
155             _ => panic!("CpuState is not valid"),
156         }
157     }
158 }
159 
160 impl From<mshv_bindings::StandardRegisters> for crate::StandardRegisters {
161     fn from(s: mshv_bindings::StandardRegisters) -> Self {
162         crate::StandardRegisters::Mshv(s)
163     }
164 }
165 
166 impl From<crate::StandardRegisters> for mshv_bindings::StandardRegisters {
167     fn from(e: crate::StandardRegisters) -> Self {
168         match e {
169             crate::StandardRegisters::Mshv(e) => e,
170             /* Needed in case other hypervisors are enabled */
171             #[allow(unreachable_patterns)]
172             _ => panic!("StandardRegisters are not valid"),
173         }
174     }
175 }
176 
177 impl From<mshv_user_irq_entry> for IrqRoutingEntry {
178     fn from(s: mshv_user_irq_entry) -> Self {
179         IrqRoutingEntry::Mshv(s)
180     }
181 }
182 
183 impl From<IrqRoutingEntry> for mshv_user_irq_entry {
184     fn from(e: IrqRoutingEntry) -> Self {
185         match e {
186             IrqRoutingEntry::Mshv(e) => e,
187             /* Needed in case other hypervisors are enabled */
188             #[allow(unreachable_patterns)]
189             _ => panic!("IrqRoutingEntry is not valid"),
190         }
191     }
192 }
193 
194 struct MshvDirtyLogSlot {
195     guest_pfn: u64,
196     memory_size: u64,
197 }
198 
199 /// Wrapper over mshv system ioctls.
200 pub struct MshvHypervisor {
201     mshv: Mshv,
202 }
203 
204 impl MshvHypervisor {
205     #[cfg(target_arch = "x86_64")]
206     ///
207     /// Retrieve the list of MSRs supported by MSHV.
208     ///
209     fn get_msr_list(&self) -> hypervisor::Result<MsrList> {
210         self.mshv
211             .get_msr_index_list()
212             .map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into()))
213     }
214 
215     fn create_vm_with_type_and_memory_int(
216         &self,
217         vm_type: u64,
218         #[cfg(feature = "sev_snp")] _mem_size: Option<u64>,
219     ) -> hypervisor::Result<Arc<dyn crate::Vm>> {
220         let mshv_vm_type: VmType = match VmType::try_from(vm_type) {
221             Ok(vm_type) => vm_type,
222             Err(_) => return Err(hypervisor::HypervisorError::UnsupportedVmType()),
223         };
224         let fd: VmFd;
225         loop {
226             match self.mshv.create_vm_with_type(mshv_vm_type) {
227                 Ok(res) => fd = res,
228                 Err(e) => {
229                     if e.errno() == libc::EINTR {
230                         // If the error returned is EINTR, which means the
231                         // ioctl has been interrupted, we have to retry as
232                         // this can't be considered as a regular error.
233                         continue;
234                     } else {
235                         return Err(hypervisor::HypervisorError::VmCreate(e.into()));
236                     }
237                 }
238             }
239             break;
240         }
241 
242         // Set additional partition property for SEV-SNP partition.
243         #[cfg(target_arch = "x86_64")]
244         if mshv_vm_type == VmType::Snp {
245             let snp_policy = snp::get_default_snp_guest_policy();
246             let vmgexit_offloads = snp::get_default_vmgexit_offload_features();
247             // SAFETY: access union fields
248             unsafe {
249                 debug!(
250                     "Setting the partition isolation policy as: 0x{:x}",
251                     snp_policy.as_uint64
252                 );
253                 fd.set_partition_property(
254                     hv_partition_property_code_HV_PARTITION_PROPERTY_ISOLATION_POLICY,
255                     snp_policy.as_uint64,
256                 )
257                 .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
258                 debug!(
259                     "Setting the partition property to enable VMGEXIT offloads as : 0x{:x}",
260                     vmgexit_offloads.as_uint64
261                 );
262                 fd.set_partition_property(
263                     hv_partition_property_code_HV_PARTITION_PROPERTY_SEV_VMGEXIT_OFFLOADS,
264                     vmgexit_offloads.as_uint64,
265                 )
266                 .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
267             }
268         }
269 
270         // Default Microsoft Hypervisor behavior for unimplemented MSR is to
271         // send a fault to the guest if it tries to access it. It is possible
272         // to override this behavior with a more suitable option i.e., ignore
273         // writes from the guest and return zero in attempt to read unimplemented
274         // MSR.
275         #[cfg(target_arch = "x86_64")]
276         fd.set_partition_property(
277             hv_partition_property_code_HV_PARTITION_PROPERTY_UNIMPLEMENTED_MSR_ACTION,
278             hv_unimplemented_msr_action_HV_UNIMPLEMENTED_MSR_ACTION_IGNORE_WRITE_READ_ZERO as u64,
279         )
280         .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
281 
282         // Always create a frozen partition
283         fd.set_partition_property(
284             hv_partition_property_code_HV_PARTITION_PROPERTY_TIME_FREEZE,
285             1u64,
286         )
287         .map_err(|e| hypervisor::HypervisorError::SetPartitionProperty(e.into()))?;
288 
289         let vm_fd = Arc::new(fd);
290 
291         #[cfg(target_arch = "x86_64")]
292         {
293             let msr_list = self.get_msr_list()?;
294             let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
295             let mut msrs: Vec<MsrEntry> = vec![
296                 MsrEntry {
297                     ..Default::default()
298                 };
299                 num_msrs
300             ];
301             let indices = msr_list.as_slice();
302             for (pos, index) in indices.iter().enumerate() {
303                 msrs[pos].index = *index;
304             }
305 
306             Ok(Arc::new(MshvVm {
307                 fd: vm_fd,
308                 msrs,
309                 dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
310                 #[cfg(feature = "sev_snp")]
311                 sev_snp_enabled: mshv_vm_type == VmType::Snp,
312                 #[cfg(feature = "sev_snp")]
313                 host_access_pages: ArcSwap::new(
314                     AtomicBitmap::new(
315                         _mem_size.unwrap_or_default() as usize,
316                         NonZeroUsize::new(HV_PAGE_SIZE).unwrap(),
317                     )
318                     .into(),
319                 ),
320             }))
321         }
322 
323         #[cfg(target_arch = "aarch64")]
324         {
325             Ok(Arc::new(MshvVm {
326                 fd: vm_fd,
327                 dirty_log_slots: Arc::new(RwLock::new(HashMap::new())),
328             }))
329         }
330     }
331 }
332 
333 impl MshvHypervisor {
334     /// Create a hypervisor based on Mshv
335     #[allow(clippy::new_ret_no_self)]
336     pub fn new() -> hypervisor::Result<Arc<dyn hypervisor::Hypervisor>> {
337         let mshv_obj =
338             Mshv::new().map_err(|e| hypervisor::HypervisorError::HypervisorCreate(e.into()))?;
339         Ok(Arc::new(MshvHypervisor { mshv: mshv_obj }))
340     }
341     /// Check if the hypervisor is available
342     pub fn is_available() -> hypervisor::Result<bool> {
343         match std::fs::metadata("/dev/mshv") {
344             Ok(_) => Ok(true),
345             Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false),
346             Err(err) => Err(hypervisor::HypervisorError::HypervisorAvailableCheck(
347                 err.into(),
348             )),
349         }
350     }
351 }
352 
353 /// Implementation of Hypervisor trait for Mshv
354 ///
355 /// # Examples
356 ///
357 /// ```
358 /// use hypervisor::mshv::MshvHypervisor;
359 /// use std::sync::Arc;
360 /// let mshv = MshvHypervisor::new().unwrap();
361 /// let hypervisor = Arc::new(mshv);
362 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
363 /// ```
364 impl hypervisor::Hypervisor for MshvHypervisor {
365     ///
366     /// Returns the type of the hypervisor
367     ///
368     fn hypervisor_type(&self) -> HypervisorType {
369         HypervisorType::Mshv
370     }
371 
372     ///
373     /// Create a Vm of a specific type using the underlying hypervisor, passing memory size
374     /// Return a hypervisor-agnostic Vm trait object
375     ///
376     /// # Examples
377     ///
378     /// ```
379     /// use hypervisor::kvm::KvmHypervisor;
380     /// use hypervisor::kvm::KvmVm;
381     /// let hypervisor = KvmHypervisor::new().unwrap();
382     /// let vm = hypervisor.create_vm_with_type(0, 512*1024*1024).unwrap();
383     /// ```
384     fn create_vm_with_type_and_memory(
385         &self,
386         vm_type: u64,
387         #[cfg(feature = "sev_snp")] _mem_size: u64,
388     ) -> hypervisor::Result<Arc<dyn vm::Vm>> {
389         self.create_vm_with_type_and_memory_int(
390             vm_type,
391             #[cfg(feature = "sev_snp")]
392             Some(_mem_size),
393         )
394     }
395 
396     fn create_vm_with_type(&self, vm_type: u64) -> hypervisor::Result<Arc<dyn crate::Vm>> {
397         self.create_vm_with_type_and_memory_int(
398             vm_type,
399             #[cfg(feature = "sev_snp")]
400             None,
401         )
402     }
403 
404     /// Create a mshv vm object and return the object as Vm trait object
405     ///
406     /// # Examples
407     ///
408     /// ```
409     /// # extern crate hypervisor;
410     /// use hypervisor::mshv::MshvHypervisor;
411     /// use hypervisor::mshv::MshvVm;
412     /// let hypervisor = MshvHypervisor::new().unwrap();
413     /// let vm = hypervisor.create_vm().unwrap();
414     /// ```
415     fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
416         let vm_type = 0;
417         self.create_vm_with_type(vm_type)
418     }
419     #[cfg(target_arch = "x86_64")]
420     ///
421     /// Get the supported CpuID
422     ///
423     fn get_supported_cpuid(&self) -> hypervisor::Result<Vec<CpuIdEntry>> {
424         let mut cpuid = Vec::new();
425         let functions: [u32; 2] = [0x1, 0xb];
426 
427         for function in functions {
428             cpuid.push(CpuIdEntry {
429                 function,
430                 ..Default::default()
431             });
432         }
433         Ok(cpuid)
434     }
435 
436     /// Get maximum number of vCPUs
437     fn get_max_vcpus(&self) -> u32 {
438         // TODO: Using HV_MAXIMUM_PROCESSORS would be better
439         // but the ioctl API is limited to u8
440         256
441     }
442 
443     fn get_guest_debug_hw_bps(&self) -> usize {
444         0
445     }
446 }
447 
448 #[cfg(feature = "sev_snp")]
449 struct Ghcb(*mut svm_ghcb_base);
450 
451 #[cfg(feature = "sev_snp")]
452 // SAFETY: struct is based on GHCB page in the hypervisor,
453 // safe to Send across threads
454 unsafe impl Send for Ghcb {}
455 
456 #[cfg(feature = "sev_snp")]
457 // SAFETY: struct is based on GHCB page in the hypervisor,
458 // safe to Sync across threads as this is only required for Vcpu trait
459 // functionally not used anyway
460 unsafe impl Sync for Ghcb {}
461 
462 /// Vcpu struct for Microsoft Hypervisor
463 pub struct MshvVcpu {
464     fd: VcpuFd,
465     vp_index: u8,
466     #[cfg(target_arch = "x86_64")]
467     cpuid: Vec<CpuIdEntry>,
468     #[cfg(target_arch = "x86_64")]
469     msrs: Vec<MsrEntry>,
470     vm_ops: Option<Arc<dyn vm::VmOps>>,
471     vm_fd: Arc<VmFd>,
472     #[cfg(feature = "sev_snp")]
473     ghcb: Option<Ghcb>,
474     #[cfg(feature = "sev_snp")]
475     host_access_pages: ArcSwap<AtomicBitmap>,
476 }
477 
478 /// Implementation of Vcpu trait for Microsoft Hypervisor
479 ///
480 /// # Examples
481 ///
482 /// ```
483 /// use hypervisor::mshv::MshvHypervisor;
484 /// use std::sync::Arc;
485 /// let mshv = MshvHypervisor::new().unwrap();
486 /// let hypervisor = Arc::new(mshv);
487 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
488 /// let vcpu = vm.create_vcpu(0, None).unwrap();
489 /// ```
490 impl cpu::Vcpu for MshvVcpu {
491     ///
492     /// Returns StandardRegisters with default value set
493     ///
494     #[cfg(target_arch = "x86_64")]
495     fn create_standard_regs(&self) -> crate::StandardRegisters {
496         mshv_bindings::StandardRegisters::default().into()
497     }
498     #[cfg(target_arch = "x86_64")]
499     ///
500     /// Returns the vCPU general purpose registers.
501     ///
502     fn get_regs(&self) -> cpu::Result<crate::StandardRegisters> {
503         Ok(self
504             .fd
505             .get_regs()
506             .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))?
507             .into())
508     }
509 
510     #[cfg(target_arch = "x86_64")]
511     ///
512     /// Sets the vCPU general purpose registers.
513     ///
514     fn set_regs(&self, regs: &crate::StandardRegisters) -> cpu::Result<()> {
515         let regs = (*regs).into();
516         self.fd
517             .set_regs(&regs)
518             .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
519     }
520 
521     #[cfg(target_arch = "x86_64")]
522     ///
523     /// Returns the vCPU special registers.
524     ///
525     fn get_sregs(&self) -> cpu::Result<crate::arch::x86::SpecialRegisters> {
526         Ok(self
527             .fd
528             .get_sregs()
529             .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))?
530             .into())
531     }
532 
533     #[cfg(target_arch = "x86_64")]
534     ///
535     /// Sets the vCPU special registers.
536     ///
537     fn set_sregs(&self, sregs: &crate::arch::x86::SpecialRegisters) -> cpu::Result<()> {
538         let sregs = (*sregs).into();
539         self.fd
540             .set_sregs(&sregs)
541             .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
542     }
543 
544     #[cfg(target_arch = "x86_64")]
545     ///
546     /// Returns the floating point state (FPU) from the vCPU.
547     ///
548     fn get_fpu(&self) -> cpu::Result<FpuState> {
549         Ok(self
550             .fd
551             .get_fpu()
552             .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))?
553             .into())
554     }
555 
556     #[cfg(target_arch = "x86_64")]
557     ///
558     /// Set the floating point state (FPU) of a vCPU.
559     ///
560     fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> {
561         let fpu: mshv_bindings::FloatingPointUnit = (*fpu).clone().into();
562         self.fd
563             .set_fpu(&fpu)
564             .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
565     }
566 
567     #[cfg(target_arch = "x86_64")]
568     ///
569     /// Returns the model-specific registers (MSR) for this vCPU.
570     ///
571     fn get_msrs(&self, msrs: &mut Vec<MsrEntry>) -> cpu::Result<usize> {
572         let mshv_msrs: Vec<msr_entry> = msrs.iter().map(|e| (*e).into()).collect();
573         let mut mshv_msrs = MsrEntries::from_entries(&mshv_msrs).unwrap();
574         let succ = self
575             .fd
576             .get_msrs(&mut mshv_msrs)
577             .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))?;
578 
579         msrs[..succ].copy_from_slice(
580             &mshv_msrs.as_slice()[..succ]
581                 .iter()
582                 .map(|e| (*e).into())
583                 .collect::<Vec<MsrEntry>>(),
584         );
585 
586         Ok(succ)
587     }
588 
589     #[cfg(target_arch = "x86_64")]
590     ///
591     /// Setup the model-specific registers (MSR) for this vCPU.
592     /// Returns the number of MSR entries actually written.
593     ///
594     fn set_msrs(&self, msrs: &[MsrEntry]) -> cpu::Result<usize> {
595         let mshv_msrs: Vec<msr_entry> = msrs.iter().map(|e| (*e).into()).collect();
596         let mshv_msrs = MsrEntries::from_entries(&mshv_msrs).unwrap();
597         self.fd
598             .set_msrs(&mshv_msrs)
599             .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
600     }
601 
602     #[cfg(target_arch = "x86_64")]
603     ///
604     /// X86 specific call to enable HyperV SynIC
605     ///
606     fn enable_hyperv_synic(&self) -> cpu::Result<()> {
607         /* We always have SynIC enabled on MSHV */
608         Ok(())
609     }
610 
611     #[allow(non_upper_case_globals)]
612     fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
613         match self.fd.run() {
614             Ok(x) => match x.header.message_type {
615                 hv_message_type_HVMSG_X64_HALT => {
616                     debug!("HALT");
617                     Ok(cpu::VmExit::Reset)
618                 }
619                 hv_message_type_HVMSG_UNRECOVERABLE_EXCEPTION => {
620                     warn!("TRIPLE FAULT");
621                     Ok(cpu::VmExit::Shutdown)
622                 }
623                 #[cfg(target_arch = "x86_64")]
624                 hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => {
625                     let info = x.to_ioport_info().unwrap();
626                     let access_info = info.access_info;
627                     // SAFETY: access_info is valid, otherwise we won't be here
628                     let len = unsafe { access_info.__bindgen_anon_1.access_size() } as usize;
629                     let is_write = info.header.intercept_access_type == 1;
630                     let port = info.port_number;
631                     let mut data: [u8; 4] = [0; 4];
632                     let mut ret_rax = info.rax;
633 
634                     /*
635                      * XXX: Ignore QEMU fw_cfg (0x5xx) and debug console (0x402) ports.
636                      *
637                      * Cloud Hypervisor doesn't support fw_cfg at the moment. It does support 0x402
638                      * under the "fwdebug" feature flag. But that feature is not enabled by default
639                      * and is considered legacy.
640                      *
641                      * OVMF unconditionally pokes these IO ports with string IO.
642                      *
643                      * Instead of trying to implement string IO support now which does not do much
644                      * now, skip those ports explicitly to avoid panicking.
645                      *
646                      * Proper string IO support can be added once we gain the ability to translate
647                      * guest virtual addresses to guest physical addresses on MSHV.
648                      */
649                     match port {
650                         0x402 | 0x510 | 0x511 | 0x514 => {
651                             let insn_len = info.header.instruction_length() as u64;
652 
653                             /* Advance RIP and update RAX */
654                             let arr_reg_name_value = [
655                                 (
656                                     hv_register_name_HV_X64_REGISTER_RIP,
657                                     info.header.rip + insn_len,
658                                 ),
659                                 (hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
660                             ];
661                             set_registers_64!(self.fd, arr_reg_name_value)
662                                 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
663                             return Ok(cpu::VmExit::Ignore);
664                         }
665                         _ => {}
666                     }
667 
668                     assert!(
669                         // SAFETY: access_info is valid, otherwise we won't be here
670                         (unsafe { access_info.__bindgen_anon_1.string_op() } != 1),
671                         "String IN/OUT not supported"
672                     );
673                     assert!(
674                         // SAFETY: access_info is valid, otherwise we won't be here
675                         (unsafe { access_info.__bindgen_anon_1.rep_prefix() } != 1),
676                         "Rep IN/OUT not supported"
677                     );
678 
679                     if is_write {
680                         let data = (info.rax as u32).to_le_bytes();
681                         if let Some(vm_ops) = &self.vm_ops {
682                             vm_ops
683                                 .pio_write(port.into(), &data[0..len])
684                                 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
685                         }
686                     } else {
687                         if let Some(vm_ops) = &self.vm_ops {
688                             vm_ops
689                                 .pio_read(port.into(), &mut data[0..len])
690                                 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
691                         }
692 
693                         let v = u32::from_le_bytes(data);
694                         /* Preserve high bits in EAX but clear out high bits in RAX */
695                         let mask = 0xffffffff >> (32 - len * 8);
696                         let eax = (info.rax as u32 & !mask) | (v & mask);
697                         ret_rax = eax as u64;
698                     }
699 
700                     let insn_len = info.header.instruction_length() as u64;
701 
702                     /* Advance RIP and update RAX */
703                     let arr_reg_name_value = [
704                         (
705                             hv_register_name_HV_X64_REGISTER_RIP,
706                             info.header.rip + insn_len,
707                         ),
708                         (hv_register_name_HV_X64_REGISTER_RAX, ret_rax),
709                     ];
710                     set_registers_64!(self.fd, arr_reg_name_value)
711                         .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
712                     Ok(cpu::VmExit::Ignore)
713                 }
714                 #[cfg(target_arch = "x86_64")]
715                 msg_type @ (hv_message_type_HVMSG_UNMAPPED_GPA
716                 | hv_message_type_HVMSG_GPA_INTERCEPT) => {
717                     let info = x.to_memory_info().unwrap();
718                     let insn_len = info.instruction_byte_count as usize;
719                     let gva = info.guest_virtual_address;
720                     let gpa = info.guest_physical_address;
721 
722                     debug!("Exit ({:?}) GVA {:x} GPA {:x}", msg_type, gva, gpa);
723 
724                     let mut context = MshvEmulatorContext {
725                         vcpu: self,
726                         map: (gva, gpa),
727                     };
728 
729                     // Create a new emulator.
730                     let mut emul = Emulator::new(&mut context);
731 
732                     // Emulate the trapped instruction, and only the first one.
733                     let new_state = emul
734                         .emulate_first_insn(
735                             self.vp_index as usize,
736                             &info.instruction_bytes[..insn_len],
737                         )
738                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
739 
740                     // Set CPU state back.
741                     context
742                         .set_cpu_state(self.vp_index as usize, new_state)
743                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
744 
745                     Ok(cpu::VmExit::Ignore)
746                 }
747                 #[cfg(feature = "sev_snp")]
748                 hv_message_type_HVMSG_GPA_ATTRIBUTE_INTERCEPT => {
749                     let info = x.to_gpa_attribute_info().unwrap();
750                     let host_vis = info.__bindgen_anon_1.host_visibility();
751                     if host_vis >= HV_MAP_GPA_READABLE | HV_MAP_GPA_WRITABLE {
752                         warn!("Ignored attribute intercept with full host visibility");
753                         return Ok(cpu::VmExit::Ignore);
754                     }
755 
756                     let num_ranges = info.__bindgen_anon_1.range_count();
757                     assert!(num_ranges >= 1);
758                     if num_ranges > 1 {
759                         return Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
760                             "Unhandled VCPU exit(GPA_ATTRIBUTE_INTERCEPT): Expected num_ranges to be 1 but found num_ranges {:?}",
761                             num_ranges
762                         )));
763                     }
764 
765                     // TODO: we could also deny the request with HvCallCompleteIntercept
766                     let mut gpas = Vec::new();
767                     let ranges = info.ranges;
768                     let (gfn_start, gfn_count) = snp::parse_gpa_range(ranges[0]).unwrap();
769                     debug!(
770                         "Releasing pages: gfn_start: {:x?}, gfn_count: {:?}",
771                         gfn_start, gfn_count
772                     );
773                     let gpa_start = gfn_start * HV_PAGE_SIZE as u64;
774                     for i in 0..gfn_count {
775                         gpas.push(gpa_start + i * HV_PAGE_SIZE as u64);
776                     }
777 
778                     let mut gpa_list =
779                         vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len());
780                     gpa_list[0].page_count = gpas.len() as u64;
781                     gpa_list[0].flags = 0;
782                     if host_vis & HV_MAP_GPA_READABLE != 0 {
783                         gpa_list[0].flags |= 1 << MSHV_GPA_HOST_ACCESS_BIT_READABLE;
784                     }
785                     if host_vis & HV_MAP_GPA_WRITABLE != 0 {
786                         gpa_list[0].flags |= 1 << MSHV_GPA_HOST_ACCESS_BIT_WRITABLE;
787                     }
788 
789                     // SAFETY: gpa_list initialized with gpas.len() and now it is being turned into
790                     // gpas_slice with gpas.len() again. It is guaranteed to be large enough to hold
791                     // everything from gpas.
792                     unsafe {
793                         let gpas_slice: &mut [u64] =
794                             gpa_list[0].guest_pfns.as_mut_slice(gpas.len());
795                         gpas_slice.copy_from_slice(gpas.as_slice());
796                     }
797 
798                     self.vm_fd
799                         .modify_gpa_host_access(&gpa_list[0])
800                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(anyhow!(
801                             "Unhandled VCPU exit: attribute intercept - couldn't modify host access {}", e
802                         )))?;
803                     // Guest is revoking the shared access, so we need to update the bitmap
804                     self.host_access_pages.rcu(|_bitmap| {
805                         let bm = self.host_access_pages.load().as_ref().clone();
806                         bm.reset_addr_range(gpa_start as usize, gfn_count as usize);
807                         bm
808                     });
809                     Ok(cpu::VmExit::Ignore)
810                 }
811                 #[cfg(target_arch = "x86_64")]
812                 hv_message_type_HVMSG_UNACCEPTED_GPA => {
813                     let info = x.to_memory_info().unwrap();
814                     let gva = info.guest_virtual_address;
815                     let gpa = info.guest_physical_address;
816 
817                     Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
818                         "Unhandled VCPU exit: Unaccepted GPA({:x}) found at GVA({:x})",
819                         gpa,
820                         gva,
821                     )))
822                 }
823                 #[cfg(target_arch = "x86_64")]
824                 hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
825                     let info = x.to_cpuid_info().unwrap();
826                     debug!("cpuid eax: {:x}", { info.rax });
827                     Ok(cpu::VmExit::Ignore)
828                 }
829                 #[cfg(target_arch = "x86_64")]
830                 hv_message_type_HVMSG_X64_MSR_INTERCEPT => {
831                     let info = x.to_msr_info().unwrap();
832                     if info.header.intercept_access_type == 0 {
833                         debug!("msr read: {:x}", { info.msr_number });
834                     } else {
835                         debug!("msr write: {:x}", { info.msr_number });
836                     }
837                     Ok(cpu::VmExit::Ignore)
838                 }
839                 #[cfg(target_arch = "x86_64")]
840                 hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => {
841                     //TODO: Handler for VMCALL here.
842                     let info = x.to_exception_info().unwrap();
843                     debug!("Exception Info {:?}", { info.exception_vector });
844                     Ok(cpu::VmExit::Ignore)
845                 }
846                 #[cfg(target_arch = "x86_64")]
847                 hv_message_type_HVMSG_X64_APIC_EOI => {
848                     let info = x.to_apic_eoi_info().unwrap();
849                     // The kernel should dispatch the EOI to the correct thread.
850                     // Check the VP index is the same as the one we have.
851                     assert!(info.vp_index == self.vp_index as u32);
852                     // The interrupt vector in info is u32, but x86 only supports 256 vectors.
853                     // There is no good way to recover from this if the hypervisor messes around.
854                     // Just unwrap.
855                     Ok(cpu::VmExit::IoapicEoi(
856                         info.interrupt_vector.try_into().unwrap(),
857                     ))
858                 }
859                 #[cfg(feature = "sev_snp")]
860                 hv_message_type_HVMSG_X64_SEV_VMGEXIT_INTERCEPT => {
861                     let info = x.to_vmg_intercept_info().unwrap();
862                     let ghcb_data = info.ghcb_msr >> GHCB_INFO_BIT_WIDTH;
863                     let ghcb_msr = svm_ghcb_msr {
864                         as_uint64: info.ghcb_msr,
865                     };
866                     // Safe to use unwrap, for sev_snp guest we already have the
867                     // GHCB pointer wrapped in the option, otherwise this place is not reached.
868                     let ghcb = self.ghcb.as_ref().unwrap().0;
869 
870                     // SAFETY: Accessing a union element from bindgen generated bindings.
871                     let ghcb_op = unsafe { ghcb_msr.__bindgen_anon_2.ghcb_info() as u32 };
872                     // Sanity check on the header fields before handling other operations.
873                     assert!(info.header.intercept_access_type == HV_INTERCEPT_ACCESS_EXECUTE as u8);
874 
875                     match ghcb_op {
876                         GHCB_INFO_HYP_FEATURE_REQUEST => {
877                             // Pre-condition: GHCB data must be zero
878                             assert!(ghcb_data == 0);
879                             let mut ghcb_response = GHCB_INFO_HYP_FEATURE_RESPONSE as u64;
880                             // Indicate support for basic SEV-SNP features
881                             ghcb_response |=
882                                 (GHCB_HYP_FEATURE_SEV_SNP << GHCB_INFO_BIT_WIDTH) as u64;
883                             // Indicate support for SEV-SNP AP creation
884                             ghcb_response |= (GHCB_HYP_FEATURE_SEV_SNP_AP_CREATION
885                                 << GHCB_INFO_BIT_WIDTH)
886                                 as u64;
887                             debug!(
888                                 "GHCB_INFO_HYP_FEATURE_REQUEST: Supported features: {:0x}",
889                                 ghcb_response
890                             );
891                             let arr_reg_name_value =
892                                 [(hv_register_name_HV_X64_REGISTER_GHCB, ghcb_response)];
893                             set_registers_64!(self.fd, arr_reg_name_value)
894                                 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
895                         }
896                         GHCB_INFO_REGISTER_REQUEST => {
897                             let mut ghcb_gpa = hv_x64_register_sev_ghcb::default();
898 
899                             // Disable the previously used GHCB page.
900                             self.disable_prev_ghcb_page()?;
901 
902                             // SAFETY: Accessing a union element from bindgen generated bindings.
903                             unsafe {
904                                 ghcb_gpa.__bindgen_anon_1.set_enabled(1);
905                                 ghcb_gpa
906                                     .__bindgen_anon_1
907                                     .set_page_number(ghcb_msr.__bindgen_anon_2.gpa_page_number());
908                             }
909                             // SAFETY: Accessing a union element from bindgen generated bindings.
910                             let reg_name_value = unsafe {
911                                 [(
912                                     hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA,
913                                     ghcb_gpa.as_uint64,
914                                 )]
915                             };
916 
917                             set_registers_64!(self.fd, reg_name_value)
918                                 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
919 
920                             let mut resp_ghcb_msr = svm_ghcb_msr::default();
921                             // SAFETY: Accessing a union element from bindgen generated bindings.
922                             unsafe {
923                                 resp_ghcb_msr
924                                     .__bindgen_anon_2
925                                     .set_ghcb_info(GHCB_INFO_REGISTER_RESPONSE as u64);
926                                 resp_ghcb_msr.__bindgen_anon_2.set_gpa_page_number(
927                                     ghcb_msr.__bindgen_anon_2.gpa_page_number(),
928                                 );
929                                 debug!("GHCB GPA is {:x}", ghcb_gpa.as_uint64);
930                             }
931                             // SAFETY: Accessing a union element from bindgen generated bindings.
932                             let reg_name_value = unsafe {
933                                 [(
934                                     hv_register_name_HV_X64_REGISTER_GHCB,
935                                     resp_ghcb_msr.as_uint64,
936                                 )]
937                             };
938 
939                             set_registers_64!(self.fd, reg_name_value)
940                                 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
941                         }
942                         GHCB_INFO_SEV_INFO_REQUEST => {
943                             let sev_cpuid_function = 0x8000_001F;
944                             let cpu_leaf = self
945                                 .fd
946                                 .get_cpuid_values(sev_cpuid_function, 0, 0, 0)
947                                 .unwrap();
948                             let ebx = cpu_leaf[1];
949                             // First 6-byte of EBX represents page table encryption bit number
950                             let pbit_encryption = (ebx & 0x3f) as u8;
951                             let mut ghcb_response = GHCB_INFO_SEV_INFO_RESPONSE as u64;
952 
953                             // GHCBData[63:48] specifies the maximum GHCB protocol version supported
954                             ghcb_response |= (GHCB_PROTOCOL_VERSION_MAX as u64) << 48;
955                             // GHCBData[47:32] specifies the minimum GHCB protocol version supported
956                             ghcb_response |= (GHCB_PROTOCOL_VERSION_MIN as u64) << 32;
957                             // GHCBData[31:24] specifies the SEV page table encryption bit number.
958                             ghcb_response |= (pbit_encryption as u64) << 24;
959 
960                             let arr_reg_name_value =
961                                 [(hv_register_name_HV_X64_REGISTER_GHCB, ghcb_response)];
962                             set_registers_64!(self.fd, arr_reg_name_value)
963                                 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
964                         }
965                         GHCB_INFO_NORMAL => {
966                             let exit_code =
967                                 info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_code as u32;
968 
969                             match exit_code {
970                                 SVM_EXITCODE_HV_DOORBELL_PAGE => {
971                                     let exit_info1 =
972                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32;
973                                     match exit_info1 {
974                                         SVM_NAE_HV_DOORBELL_PAGE_GET_PREFERRED => {
975                                             // Hypervisor does not have any preference for doorbell GPA.
976                                             let preferred_doorbell_gpa: u64 = 0xFFFFFFFFFFFFFFFF;
977                                             set_svm_field_u64_ptr!(
978                                                 ghcb,
979                                                 exit_info2,
980                                                 preferred_doorbell_gpa
981                                             );
982                                         }
983                                         SVM_NAE_HV_DOORBELL_PAGE_SET => {
984                                             let exit_info2 = info
985                                                 .__bindgen_anon_2
986                                                 .__bindgen_anon_1
987                                                 .sw_exit_info2;
988                                             let mut ghcb_doorbell_gpa =
989                                                 hv_x64_register_sev_hv_doorbell::default();
990                                             // SAFETY: Accessing a union element from bindgen generated bindings.
991                                             unsafe {
992                                                 ghcb_doorbell_gpa.__bindgen_anon_1.set_enabled(1);
993                                                 ghcb_doorbell_gpa
994                                                     .__bindgen_anon_1
995                                                     .set_page_number(exit_info2 >> PAGE_SHIFT);
996                                             }
997                                             // SAFETY: Accessing a union element from bindgen generated bindings.
998                                             let reg_names = unsafe {
999                                                 [(
1000                                                     hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA,
1001                                                     ghcb_doorbell_gpa.as_uint64,
1002                                                 )]
1003                                             };
1004                                             set_registers_64!(self.fd, reg_names).map_err(|e| {
1005                                                 cpu::HypervisorCpuError::SetRegister(e.into())
1006                                             })?;
1007 
1008                                             set_svm_field_u64_ptr!(ghcb, exit_info2, exit_info2);
1009 
1010                                             // Clear the SW_EXIT_INFO1 register to indicate no error
1011                                             self.clear_swexit_info1()?;
1012                                         }
1013                                         SVM_NAE_HV_DOORBELL_PAGE_QUERY => {
1014                                             let mut reg_assocs = [ hv_register_assoc {
1015                                                 name: hv_register_name_HV_X64_REGISTER_SEV_DOORBELL_GPA,
1016                                                 ..Default::default()
1017                                             } ];
1018                                             self.fd.get_reg(&mut reg_assocs).unwrap();
1019                                             // SAFETY: Accessing a union element from bindgen generated bindings.
1020                                             let doorbell_gpa = unsafe { reg_assocs[0].value.reg64 };
1021 
1022                                             set_svm_field_u64_ptr!(ghcb, exit_info2, doorbell_gpa);
1023 
1024                                             // Clear the SW_EXIT_INFO1 register to indicate no error
1025                                             self.clear_swexit_info1()?;
1026                                         }
1027                                         SVM_NAE_HV_DOORBELL_PAGE_CLEAR => {
1028                                             set_svm_field_u64_ptr!(ghcb, exit_info2, 0);
1029                                         }
1030                                         _ => {
1031                                             panic!(
1032                                                 "SVM_EXITCODE_HV_DOORBELL_PAGE: Unhandled exit code: {:0x}",
1033                                                 exit_info1
1034                                             );
1035                                         }
1036                                     }
1037                                 }
1038                                 SVM_EXITCODE_IOIO_PROT => {
1039                                     let exit_info1 =
1040                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 as u32;
1041                                     let port_info = hv_sev_vmgexit_port_info {
1042                                         as_uint32: exit_info1,
1043                                     };
1044 
1045                                     let port =
1046                                         // SAFETY: Accessing a union element from bindgen generated bindings.
1047                                         unsafe { port_info.__bindgen_anon_1.intercepted_port() };
1048                                     let mut len = 4;
1049                                     // SAFETY: Accessing a union element from bindgen generated bindings.
1050                                     unsafe {
1051                                         if port_info.__bindgen_anon_1.operand_size_16bit() == 1 {
1052                                             len = 2;
1053                                         } else if port_info.__bindgen_anon_1.operand_size_8bit()
1054                                             == 1
1055                                         {
1056                                             len = 1;
1057                                         }
1058                                     }
1059                                     let is_write =
1060                                         // SAFETY: Accessing a union element from bindgen generated bindings.
1061                                         unsafe { port_info.__bindgen_anon_1.access_type() == 0 };
1062                                     // SAFETY: Accessing the field from a mapped address
1063                                     let mut data = unsafe { (*ghcb).rax.to_le_bytes() };
1064 
1065                                     if is_write {
1066                                         if let Some(vm_ops) = &self.vm_ops {
1067                                             vm_ops.pio_write(port.into(), &data[..len]).map_err(
1068                                                 |e| cpu::HypervisorCpuError::RunVcpu(e.into()),
1069                                             )?;
1070                                         }
1071                                     } else {
1072                                         if let Some(vm_ops) = &self.vm_ops {
1073                                             vm_ops
1074                                                 .pio_read(port.into(), &mut data[..len])
1075                                                 .map_err(|e| {
1076                                                     cpu::HypervisorCpuError::RunVcpu(e.into())
1077                                                 })?;
1078                                         }
1079                                         set_svm_field_u64_ptr!(ghcb, rax, u64::from_le_bytes(data));
1080                                     }
1081 
1082                                     // Clear the SW_EXIT_INFO1 register to indicate no error
1083                                     self.clear_swexit_info1()?;
1084                                 }
1085                                 SVM_EXITCODE_MMIO_READ => {
1086                                     let src_gpa =
1087                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
1088                                     let data_len =
1089                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2
1090                                             as usize;
1091                                     // Sanity check to make sure data len is within supported range.
1092                                     assert!(data_len <= 0x8);
1093 
1094                                     let mut data: Vec<u8> = vec![0; data_len];
1095                                     if let Some(vm_ops) = &self.vm_ops {
1096                                         vm_ops.mmio_read(src_gpa, &mut data).map_err(|e| {
1097                                             cpu::HypervisorCpuError::RunVcpu(e.into())
1098                                         })?;
1099                                     }
1100                                     // Copy the data to the shared buffer of the GHCB page
1101                                     let mut buffer_data = [0; 8];
1102                                     buffer_data[..data_len].copy_from_slice(&data[..data_len]);
1103                                     // SAFETY: Updating the value of mapped area
1104                                     unsafe { (*ghcb).shared[0] = u64::from_le_bytes(buffer_data) };
1105 
1106                                     // Clear the SW_EXIT_INFO1 register to indicate no error
1107                                     self.clear_swexit_info1()?;
1108                                 }
1109                                 SVM_EXITCODE_MMIO_WRITE => {
1110                                     let dst_gpa =
1111                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
1112                                     let data_len =
1113                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2
1114                                             as usize;
1115                                     // Sanity check to make sure data len is within supported range.
1116                                     assert!(data_len <= 0x8);
1117 
1118                                     let mut data = vec![0; data_len];
1119                                     // SAFETY: Accessing data from a mapped address
1120                                     let bytes_shared_ghcb =
1121                                         unsafe { (*ghcb).shared[0].to_le_bytes() };
1122                                     data.copy_from_slice(&bytes_shared_ghcb[..data_len]);
1123 
1124                                     if let Some(vm_ops) = &self.vm_ops {
1125                                         vm_ops.mmio_write(dst_gpa, &data).map_err(|e| {
1126                                             cpu::HypervisorCpuError::RunVcpu(e.into())
1127                                         })?;
1128                                     }
1129 
1130                                     // Clear the SW_EXIT_INFO1 register to indicate no error
1131                                     self.clear_swexit_info1()?;
1132                                 }
1133                                 SVM_EXITCODE_SNP_GUEST_REQUEST
1134                                 | SVM_EXITCODE_SNP_EXTENDED_GUEST_REQUEST => {
1135                                     if exit_code == SVM_EXITCODE_SNP_EXTENDED_GUEST_REQUEST {
1136                                         info!("Fetching extended guest request is not supported");
1137                                         // We don't support extended guest request, so we just write empty data.
1138                                         // This matches the behavior of KVM in Linux 6.11.
1139 
1140                                         // Read RBX from the GHCB.
1141                                         // SAFETY: Accessing data from a mapped address
1142                                         let data_gpa = unsafe { (*ghcb).rax };
1143                                         // SAFETY: Accessing data from a mapped address
1144                                         let data_npages = unsafe { (*ghcb).rbx };
1145 
1146                                         if data_npages > 0 {
1147                                             // The certificates are terminated by 24 zero bytes.
1148                                             // TODO: Need to check if data_gpa is the address of the shared buffer in the GHCB page
1149                                             // in that case we should clear the shared buffer(24 bytes)
1150                                             self.gpa_write(data_gpa, &[0; 24])?;
1151                                         }
1152                                     }
1153 
1154                                     let req_gpa =
1155                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1;
1156                                     let rsp_gpa =
1157                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2;
1158 
1159                                     let mshv_psp_req =
1160                                         mshv_issue_psp_guest_request { req_gpa, rsp_gpa };
1161                                     self.vm_fd
1162                                         .psp_issue_guest_request(&mshv_psp_req)
1163                                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
1164 
1165                                     debug!(
1166                                         "SNP guest request: req_gpa {:0x} rsp_gpa {:0x}",
1167                                         req_gpa, rsp_gpa
1168                                     );
1169 
1170                                     set_svm_field_u64_ptr!(ghcb, exit_info2, 0);
1171                                 }
1172                                 SVM_EXITCODE_SNP_AP_CREATION => {
1173                                     let vmsa_gpa =
1174                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info2;
1175                                     let apic_id =
1176                                         info.__bindgen_anon_2.__bindgen_anon_1.sw_exit_info1 >> 32;
1177                                     debug!(
1178                                         "SNP AP CREATE REQUEST with VMSA GPA {:0x}, and APIC ID {:?}",
1179                                         vmsa_gpa, apic_id
1180                                     );
1181 
1182                                     let mshv_ap_create_req = mshv_sev_snp_ap_create {
1183                                         vp_id: apic_id,
1184                                         vmsa_gpa,
1185                                     };
1186                                     self.vm_fd
1187                                         .sev_snp_ap_create(&mshv_ap_create_req)
1188                                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
1189 
1190                                     // Clear the SW_EXIT_INFO1 register to indicate no error
1191                                     self.clear_swexit_info1()?;
1192                                 }
1193                                 _ => panic!(
1194                                     "GHCB_INFO_NORMAL: Unhandled exit code: {:0x}",
1195                                     exit_code
1196                                 ),
1197                             }
1198                         }
1199                         _ => panic!("Unsupported VMGEXIT operation: {:0x}", ghcb_op),
1200                     }
1201 
1202                     Ok(cpu::VmExit::Ignore)
1203                 }
1204                 exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
1205                     "Unhandled VCPU exit {:?}",
1206                     exit
1207                 ))),
1208             },
1209 
1210             Err(e) => match e.errno() {
1211                 libc::EAGAIN | libc::EINTR => Ok(cpu::VmExit::Ignore),
1212                 _ => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
1213                     "VCPU error {:?}",
1214                     e
1215                 ))),
1216             },
1217         }
1218     }
1219 
1220     #[cfg(target_arch = "aarch64")]
1221     fn init_pmu(&self, irq: u32) -> cpu::Result<()> {
1222         unimplemented!()
1223     }
1224 
1225     #[cfg(target_arch = "aarch64")]
1226     fn has_pmu_support(&self) -> bool {
1227         unimplemented!()
1228     }
1229 
1230     #[cfg(target_arch = "aarch64")]
1231     fn setup_regs(&self, cpu_id: u8, boot_ip: u64, fdt_start: u64) -> cpu::Result<()> {
1232         unimplemented!()
1233     }
1234 
1235     #[cfg(target_arch = "aarch64")]
1236     fn get_sys_reg(&self, sys_reg: u32) -> cpu::Result<u64> {
1237         unimplemented!()
1238     }
1239 
1240     #[cfg(target_arch = "aarch64")]
1241     fn get_reg_list(&self, reg_list: &mut RegList) -> cpu::Result<()> {
1242         unimplemented!()
1243     }
1244 
1245     #[cfg(target_arch = "aarch64")]
1246     fn vcpu_init(&self, kvi: &VcpuInit) -> cpu::Result<()> {
1247         unimplemented!()
1248     }
1249 
1250     #[cfg(target_arch = "aarch64")]
1251     fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
1252         unimplemented!()
1253     }
1254 
1255     #[cfg(target_arch = "aarch64")]
1256     fn get_regs(&self) -> cpu::Result<StandardRegisters> {
1257         unimplemented!()
1258     }
1259 
1260     #[cfg(target_arch = "x86_64")]
1261     ///
1262     /// X86 specific call to setup the CPUID registers.
1263     ///
1264     fn set_cpuid2(&self, cpuid: &[CpuIdEntry]) -> cpu::Result<()> {
1265         let cpuid: Vec<mshv_bindings::hv_cpuid_entry> = cpuid.iter().map(|e| (*e).into()).collect();
1266         let mshv_cpuid = <CpuId>::from_entries(&cpuid)
1267             .map_err(|_| cpu::HypervisorCpuError::SetCpuid(anyhow!("failed to create CpuId")))?;
1268 
1269         self.fd
1270             .register_intercept_result_cpuid(&mshv_cpuid)
1271             .map_err(|e| cpu::HypervisorCpuError::SetCpuid(e.into()))
1272     }
1273 
1274     #[cfg(target_arch = "x86_64")]
1275     ///
1276     /// X86 specific call to retrieve the CPUID registers.
1277     ///
1278     fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<Vec<CpuIdEntry>> {
1279         Ok(self.cpuid.clone())
1280     }
1281 
1282     #[cfg(target_arch = "x86_64")]
1283     ///
1284     /// X86 specific call to retrieve cpuid leaf
1285     ///
1286     fn get_cpuid_values(
1287         &self,
1288         function: u32,
1289         index: u32,
1290         xfem: u64,
1291         xss: u64,
1292     ) -> cpu::Result<[u32; 4]> {
1293         self.fd
1294             .get_cpuid_values(function, index, xfem, xss)
1295             .map_err(|e| cpu::HypervisorCpuError::GetCpuidVales(e.into()))
1296     }
1297 
1298     #[cfg(target_arch = "x86_64")]
1299     ///
1300     /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
1301     ///
1302     fn get_lapic(&self) -> cpu::Result<crate::arch::x86::LapicState> {
1303         Ok(self
1304             .fd
1305             .get_lapic()
1306             .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))?
1307             .into())
1308     }
1309 
1310     #[cfg(target_arch = "x86_64")]
1311     ///
1312     /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
1313     ///
1314     fn set_lapic(&self, lapic: &crate::arch::x86::LapicState) -> cpu::Result<()> {
1315         let lapic: mshv_bindings::LapicState = (*lapic).clone().into();
1316         self.fd
1317             .set_lapic(&lapic)
1318             .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
1319     }
1320 
1321     ///
1322     /// Returns the vcpu's current "multiprocessing state".
1323     ///
1324     fn get_mp_state(&self) -> cpu::Result<MpState> {
1325         Ok(MpState::Mshv)
1326     }
1327 
1328     ///
1329     /// Sets the vcpu's current "multiprocessing state".
1330     ///
1331     fn set_mp_state(&self, _mp_state: MpState) -> cpu::Result<()> {
1332         Ok(())
1333     }
1334 
1335     #[cfg(target_arch = "x86_64")]
1336     ///
1337     /// Set CPU state for x86_64 guest.
1338     ///
1339     fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
1340         let mut state: VcpuMshvState = state.clone().into();
1341         self.set_msrs(&state.msrs)?;
1342         self.set_vcpu_events(&state.vcpu_events)?;
1343         self.set_regs(&state.regs.into())?;
1344         self.set_sregs(&state.sregs.into())?;
1345         self.set_fpu(&state.fpu)?;
1346         self.set_xcrs(&state.xcrs)?;
1347         // These registers are global and needed to be set only for first VCPU
1348         // as Microsoft Hypervisor allows setting this register for only one VCPU
1349         if self.vp_index == 0 {
1350             self.fd
1351                 .set_misc_regs(&state.misc)
1352                 .map_err(|e| cpu::HypervisorCpuError::SetMiscRegs(e.into()))?
1353         }
1354         self.fd
1355             .set_debug_regs(&state.dbg)
1356             .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
1357         self.fd
1358             .set_all_vp_state_components(&mut state.vp_states)
1359             .map_err(|e| cpu::HypervisorCpuError::SetAllVpStateComponents(e.into()))?;
1360         Ok(())
1361     }
1362 
1363     #[cfg(target_arch = "aarch64")]
1364     ///
1365     /// Set CPU state for aarch64 guest.
1366     ///
1367     fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
1368         unimplemented!()
1369     }
1370 
1371     #[cfg(target_arch = "x86_64")]
1372     ///
1373     /// Get CPU State for x86_64 guest
1374     ///
1375     fn state(&self) -> cpu::Result<CpuState> {
1376         let regs = self.get_regs()?;
1377         let sregs = self.get_sregs()?;
1378         let xcrs = self.get_xcrs()?;
1379         let fpu = self.get_fpu()?;
1380         let vcpu_events = self.get_vcpu_events()?;
1381         let mut msrs = self.msrs.clone();
1382         self.get_msrs(&mut msrs)?;
1383         let misc = self
1384             .fd
1385             .get_misc_regs()
1386             .map_err(|e| cpu::HypervisorCpuError::GetMiscRegs(e.into()))?;
1387         let dbg = self
1388             .fd
1389             .get_debug_regs()
1390             .map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?;
1391         let vp_states = self
1392             .fd
1393             .get_all_vp_state_components()
1394             .map_err(|e| cpu::HypervisorCpuError::GetAllVpStateComponents(e.into()))?;
1395 
1396         Ok(VcpuMshvState {
1397             msrs,
1398             vcpu_events,
1399             regs: regs.into(),
1400             sregs: sregs.into(),
1401             fpu,
1402             xcrs,
1403             dbg,
1404             misc,
1405             vp_states,
1406         }
1407         .into())
1408     }
1409 
1410     #[cfg(target_arch = "aarch64")]
1411     ///
1412     /// Get CPU state for aarch64 guest.
1413     ///
1414     fn state(&self) -> cpu::Result<CpuState> {
1415         unimplemented!()
1416     }
1417 
1418     #[cfg(target_arch = "x86_64")]
1419     ///
1420     /// Translate guest virtual address to guest physical address
1421     ///
1422     fn translate_gva(&self, gva: u64, flags: u64) -> cpu::Result<(u64, u32)> {
1423         let r = self
1424             .fd
1425             .translate_gva(gva, flags)
1426             .map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
1427 
1428         let gpa = r.0;
1429         // SAFETY: r is valid, otherwise this function will have returned
1430         let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
1431 
1432         Ok((gpa, result_code))
1433     }
1434 
1435     #[cfg(target_arch = "x86_64")]
1436     ///
1437     /// Return the list of initial MSR entries for a VCPU
1438     ///
1439     fn boot_msr_entries(&self) -> Vec<MsrEntry> {
1440         use crate::arch::x86::{msr_index, MTRR_ENABLE, MTRR_MEM_TYPE_WB};
1441 
1442         [
1443             msr!(msr_index::MSR_IA32_SYSENTER_CS),
1444             msr!(msr_index::MSR_IA32_SYSENTER_ESP),
1445             msr!(msr_index::MSR_IA32_SYSENTER_EIP),
1446             msr!(msr_index::MSR_STAR),
1447             msr!(msr_index::MSR_CSTAR),
1448             msr!(msr_index::MSR_LSTAR),
1449             msr!(msr_index::MSR_KERNEL_GS_BASE),
1450             msr!(msr_index::MSR_SYSCALL_MASK),
1451             msr_data!(msr_index::MSR_MTRRdefType, MTRR_ENABLE | MTRR_MEM_TYPE_WB),
1452         ]
1453         .to_vec()
1454     }
1455 
1456     ///
1457     /// Sets the AMD specific vcpu's sev control register.
1458     ///
1459     #[cfg(feature = "sev_snp")]
1460     fn set_sev_control_register(&self, vmsa_pfn: u64) -> cpu::Result<()> {
1461         let sev_control_reg = snp::get_sev_control_register(vmsa_pfn);
1462 
1463         self.fd
1464             .set_sev_control_register(sev_control_reg)
1465             .map_err(|e| cpu::HypervisorCpuError::SetSevControlRegister(e.into()))
1466     }
1467     #[cfg(target_arch = "x86_64")]
1468     ///
1469     /// Trigger NMI interrupt
1470     ///
1471     fn nmi(&self) -> cpu::Result<()> {
1472         let cfg = InterruptRequest {
1473             interrupt_type: hv_interrupt_type_HV_X64_INTERRUPT_TYPE_NMI,
1474             apic_id: self.vp_index as u64,
1475             level_triggered: false,
1476             vector: 0,
1477             logical_destination_mode: false,
1478             long_mode: false,
1479         };
1480         self.vm_fd
1481             .request_virtual_interrupt(&cfg)
1482             .map_err(|e| cpu::HypervisorCpuError::Nmi(e.into()))
1483     }
1484 }
1485 
1486 impl MshvVcpu {
1487     ///
1488     /// Deactivate previously used GHCB page.
1489     ///
1490     #[cfg(feature = "sev_snp")]
1491     fn disable_prev_ghcb_page(&self) -> cpu::Result<()> {
1492         let mut reg_assocs = [hv_register_assoc {
1493             name: hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA,
1494             ..Default::default()
1495         }];
1496         self.fd.get_reg(&mut reg_assocs).unwrap();
1497         // SAFETY: Accessing a union element from bindgen generated bindings.
1498         let prev_ghcb_gpa = unsafe { reg_assocs[0].value.reg64 };
1499 
1500         debug!("Prev GHCB GPA is {:x}", prev_ghcb_gpa);
1501 
1502         let mut ghcb_gpa = hv_x64_register_sev_ghcb::default();
1503 
1504         // SAFETY: Accessing a union element from bindgen generated bindings.
1505         unsafe {
1506             ghcb_gpa.__bindgen_anon_1.set_enabled(0);
1507             ghcb_gpa.__bindgen_anon_1.set_page_number(prev_ghcb_gpa);
1508         }
1509 
1510         // SAFETY: Accessing a union element from bindgen generated bindings.
1511         let reg_name_value = unsafe {
1512             [(
1513                 hv_register_name_HV_X64_REGISTER_SEV_GHCB_GPA,
1514                 ghcb_gpa.as_uint64,
1515             )]
1516         };
1517 
1518         set_registers_64!(self.fd, reg_name_value)
1519             .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
1520 
1521         Ok(())
1522     }
1523     #[cfg(target_arch = "x86_64")]
1524     ///
1525     /// X86 specific call that returns the vcpu's current "xcrs".
1526     ///
1527     fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> {
1528         self.fd
1529             .get_xcrs()
1530             .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
1531     }
1532 
1533     #[cfg(target_arch = "x86_64")]
1534     ///
1535     /// X86 specific call that sets the vcpu's current "xcrs".
1536     ///
1537     fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
1538         self.fd
1539             .set_xcrs(xcrs)
1540             .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
1541     }
1542 
1543     #[cfg(target_arch = "x86_64")]
1544     ///
1545     /// Returns currently pending exceptions, interrupts, and NMIs as well as related
1546     /// states of the vcpu.
1547     ///
1548     fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> {
1549         self.fd
1550             .get_vcpu_events()
1551             .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
1552     }
1553 
1554     #[cfg(target_arch = "x86_64")]
1555     ///
1556     /// Sets pending exceptions, interrupts, and NMIs as well as related states
1557     /// of the vcpu.
1558     ///
1559     fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> {
1560         self.fd
1561             .set_vcpu_events(events)
1562             .map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
1563     }
1564 
1565     ///
1566     /// Clear SW_EXIT_INFO1 register for SEV-SNP guests.
1567     ///
1568     #[cfg(feature = "sev_snp")]
1569     fn clear_swexit_info1(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
1570         // Clear the SW_EXIT_INFO1 register to indicate no error
1571         // Safe to use unwrap, for sev_snp guest we already have the
1572         // GHCB pointer wrapped in the option, otherwise this place is not reached.
1573         let ghcb = self.ghcb.as_ref().unwrap().0;
1574         set_svm_field_u64_ptr!(ghcb, exit_info1, 0);
1575 
1576         Ok(cpu::VmExit::Ignore)
1577     }
1578 
1579     #[cfg(feature = "sev_snp")]
1580     fn gpa_write(&self, gpa: u64, data: &[u8]) -> cpu::Result<()> {
1581         for (gpa, chunk) in (gpa..)
1582             .step_by(HV_READ_WRITE_GPA_MAX_SIZE as usize)
1583             .zip(data.chunks(HV_READ_WRITE_GPA_MAX_SIZE as usize))
1584         {
1585             let mut data = [0; HV_READ_WRITE_GPA_MAX_SIZE as usize];
1586             data[..chunk.len()].copy_from_slice(chunk);
1587 
1588             let mut rw_gpa_arg = mshv_bindings::mshv_read_write_gpa {
1589                 base_gpa: gpa,
1590                 byte_count: chunk.len() as u32,
1591                 data,
1592                 ..Default::default()
1593             };
1594             self.fd
1595                 .gpa_write(&mut rw_gpa_arg)
1596                 .map_err(|e| cpu::HypervisorCpuError::GpaWrite(e.into()))?;
1597         }
1598 
1599         Ok(())
1600     }
1601 }
1602 
1603 /// Wrapper over Mshv VM ioctls.
1604 pub struct MshvVm {
1605     fd: Arc<VmFd>,
1606     #[cfg(target_arch = "x86_64")]
1607     msrs: Vec<MsrEntry>,
1608     dirty_log_slots: Arc<RwLock<HashMap<u64, MshvDirtyLogSlot>>>,
1609     #[cfg(feature = "sev_snp")]
1610     sev_snp_enabled: bool,
1611     #[cfg(feature = "sev_snp")]
1612     host_access_pages: ArcSwap<AtomicBitmap>,
1613 }
1614 
1615 impl MshvVm {
1616     ///
1617     /// Creates an in-kernel device.
1618     ///
1619     /// See the documentation for `MSHV_CREATE_DEVICE`.
1620     fn create_device(&self, device: &mut CreateDevice) -> vm::Result<VfioDeviceFd> {
1621         let device_fd = self
1622             .fd
1623             .create_device(device)
1624             .map_err(|e| vm::HypervisorVmError::CreateDevice(e.into()))?;
1625         Ok(VfioDeviceFd::new_from_mshv(device_fd))
1626     }
1627 }
1628 
1629 ///
1630 /// Implementation of Vm trait for Mshv
1631 ///
1632 /// # Examples
1633 ///
1634 /// ```
1635 /// extern crate hypervisor;
1636 /// use hypervisor::mshv::MshvHypervisor;
1637 /// use std::sync::Arc;
1638 /// let mshv = MshvHypervisor::new().unwrap();
1639 /// let hypervisor = Arc::new(mshv);
1640 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
1641 /// ```
1642 impl vm::Vm for MshvVm {
1643     #[cfg(target_arch = "x86_64")]
1644     ///
1645     /// Sets the address of the one-page region in the VM's address space.
1646     ///
1647     fn set_identity_map_address(&self, _address: u64) -> vm::Result<()> {
1648         Ok(())
1649     }
1650 
1651     #[cfg(target_arch = "x86_64")]
1652     ///
1653     /// Sets the address of the three-page region in the VM's address space.
1654     ///
1655     fn set_tss_address(&self, _offset: usize) -> vm::Result<()> {
1656         Ok(())
1657     }
1658 
1659     ///
1660     /// Creates an in-kernel interrupt controller.
1661     ///
1662     fn create_irq_chip(&self) -> vm::Result<()> {
1663         Ok(())
1664     }
1665 
1666     ///
1667     /// Registers an event that will, when signaled, trigger the `gsi` IRQ.
1668     ///
1669     fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
1670         debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
1671 
1672         self.fd
1673             .register_irqfd(fd, gsi)
1674             .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
1675 
1676         Ok(())
1677     }
1678 
1679     ///
1680     /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
1681     ///
1682     fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
1683         debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
1684 
1685         self.fd
1686             .unregister_irqfd(fd, gsi)
1687             .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?;
1688 
1689         Ok(())
1690     }
1691 
1692     ///
1693     /// Creates a VcpuFd object from a vcpu RawFd.
1694     ///
1695     fn create_vcpu(
1696         &self,
1697         id: u8,
1698         vm_ops: Option<Arc<dyn VmOps>>,
1699     ) -> vm::Result<Arc<dyn cpu::Vcpu>> {
1700         let vcpu_fd = self
1701             .fd
1702             .create_vcpu(id)
1703             .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
1704 
1705         /* Map the GHCB page to the VMM(root) address space
1706          * The map is available after the vcpu creation. This address is mapped
1707          * to the overlay ghcb page of the Microsoft Hypervisor, don't have
1708          * to worry about the scenario when a guest changes the GHCB mapping.
1709          */
1710         #[cfg(feature = "sev_snp")]
1711         let ghcb = if self.sev_snp_enabled {
1712             // SAFETY: Safe to call as VCPU has this map already available upon creation
1713             let addr = unsafe {
1714                 libc::mmap(
1715                     std::ptr::null_mut(),
1716                     HV_PAGE_SIZE,
1717                     libc::PROT_READ | libc::PROT_WRITE,
1718                     libc::MAP_SHARED,
1719                     vcpu_fd.as_raw_fd(),
1720                     MSHV_VP_MMAP_OFFSET_GHCB as i64 * libc::sysconf(libc::_SC_PAGE_SIZE),
1721                 )
1722             };
1723             if addr == libc::MAP_FAILED {
1724                 // No point of continuing, without this mmap VMGEXIT will fail anyway
1725                 // Return error
1726                 return Err(vm::HypervisorVmError::MmapToRoot);
1727             }
1728             Some(Ghcb(addr as *mut svm_ghcb_base))
1729         } else {
1730             None
1731         };
1732         let vcpu = MshvVcpu {
1733             fd: vcpu_fd,
1734             vp_index: id,
1735             #[cfg(target_arch = "x86_64")]
1736             cpuid: Vec::new(),
1737             #[cfg(target_arch = "x86_64")]
1738             msrs: self.msrs.clone(),
1739             vm_ops,
1740             vm_fd: self.fd.clone(),
1741             #[cfg(feature = "sev_snp")]
1742             ghcb,
1743             #[cfg(feature = "sev_snp")]
1744             host_access_pages: ArcSwap::new(self.host_access_pages.load().clone()),
1745         };
1746         Ok(Arc::new(vcpu))
1747     }
1748 
1749     #[cfg(target_arch = "x86_64")]
1750     fn enable_split_irq(&self) -> vm::Result<()> {
1751         Ok(())
1752     }
1753 
1754     #[cfg(target_arch = "x86_64")]
1755     fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> {
1756         Ok(())
1757     }
1758 
1759     fn register_ioevent(
1760         &self,
1761         fd: &EventFd,
1762         addr: &IoEventAddress,
1763         datamatch: Option<DataMatch>,
1764     ) -> vm::Result<()> {
1765         #[cfg(feature = "sev_snp")]
1766         if self.sev_snp_enabled {
1767             return Ok(());
1768         }
1769 
1770         let addr = &mshv_ioctls::IoEventAddress::from(*addr);
1771         debug!(
1772             "register_ioevent fd {} addr {:x?} datamatch {:?}",
1773             fd.as_raw_fd(),
1774             addr,
1775             datamatch
1776         );
1777         if let Some(dm) = datamatch {
1778             match dm {
1779                 vm::DataMatch::DataMatch32(mshv_dm32) => self
1780                     .fd
1781                     .register_ioevent(fd, addr, mshv_dm32)
1782                     .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())),
1783                 vm::DataMatch::DataMatch64(mshv_dm64) => self
1784                     .fd
1785                     .register_ioevent(fd, addr, mshv_dm64)
1786                     .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())),
1787             }
1788         } else {
1789             self.fd
1790                 .register_ioevent(fd, addr, NoDatamatch)
1791                 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
1792         }
1793     }
1794 
1795     /// Unregister an event from a certain address it has been previously registered to.
1796     fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
1797         #[cfg(feature = "sev_snp")]
1798         if self.sev_snp_enabled {
1799             return Ok(());
1800         }
1801 
1802         let addr = &mshv_ioctls::IoEventAddress::from(*addr);
1803         debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr);
1804 
1805         self.fd
1806             .unregister_ioevent(fd, addr, NoDatamatch)
1807             .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
1808     }
1809 
1810     /// Creates a guest physical memory region.
1811     fn create_user_memory_region(&self, user_memory_region: UserMemoryRegion) -> vm::Result<()> {
1812         let user_memory_region: mshv_user_mem_region = user_memory_region.into();
1813         // No matter read only or not we keep track the slots.
1814         // For readonly hypervisor can enable the dirty bits,
1815         // but a VM exit happens before setting the dirty bits
1816         self.dirty_log_slots.write().unwrap().insert(
1817             user_memory_region.guest_pfn,
1818             MshvDirtyLogSlot {
1819                 guest_pfn: user_memory_region.guest_pfn,
1820                 memory_size: user_memory_region.size,
1821             },
1822         );
1823 
1824         self.fd
1825             .map_user_memory(user_memory_region)
1826             .map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?;
1827         Ok(())
1828     }
1829 
1830     /// Removes a guest physical memory region.
1831     fn remove_user_memory_region(&self, user_memory_region: UserMemoryRegion) -> vm::Result<()> {
1832         let user_memory_region: mshv_user_mem_region = user_memory_region.into();
1833         // Remove the corresponding entry from "self.dirty_log_slots" if needed
1834         self.dirty_log_slots
1835             .write()
1836             .unwrap()
1837             .remove(&user_memory_region.guest_pfn);
1838 
1839         self.fd
1840             .unmap_user_memory(user_memory_region)
1841             .map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?;
1842         Ok(())
1843     }
1844 
1845     fn make_user_memory_region(
1846         &self,
1847         _slot: u32,
1848         guest_phys_addr: u64,
1849         memory_size: u64,
1850         userspace_addr: u64,
1851         readonly: bool,
1852         _log_dirty_pages: bool,
1853     ) -> UserMemoryRegion {
1854         let mut flags = 1 << MSHV_SET_MEM_BIT_EXECUTABLE;
1855         if !readonly {
1856             flags |= 1 << MSHV_SET_MEM_BIT_WRITABLE;
1857         }
1858 
1859         mshv_user_mem_region {
1860             flags,
1861             guest_pfn: guest_phys_addr >> PAGE_SHIFT,
1862             size: memory_size,
1863             userspace_addr,
1864             ..Default::default()
1865         }
1866         .into()
1867     }
1868 
1869     fn create_passthrough_device(&self) -> vm::Result<VfioDeviceFd> {
1870         let mut vfio_dev = mshv_create_device {
1871             type_: mshv_device_type_MSHV_DEV_TYPE_VFIO,
1872             fd: 0,
1873             flags: 0,
1874         };
1875 
1876         self.create_device(&mut vfio_dev)
1877             .map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into()))
1878     }
1879 
1880     ///
1881     /// Constructs a routing entry
1882     ///
1883     fn make_routing_entry(&self, gsi: u32, config: &InterruptSourceConfig) -> IrqRoutingEntry {
1884         match config {
1885             InterruptSourceConfig::MsiIrq(cfg) => mshv_user_irq_entry {
1886                 gsi,
1887                 address_lo: cfg.low_addr,
1888                 address_hi: cfg.high_addr,
1889                 data: cfg.data,
1890             }
1891             .into(),
1892             _ => {
1893                 unreachable!()
1894             }
1895         }
1896     }
1897 
1898     fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
1899         let mut msi_routing =
1900             vec_with_array_field::<mshv_user_irq_table, mshv_user_irq_entry>(entries.len());
1901         msi_routing[0].nr = entries.len() as u32;
1902 
1903         let entries: Vec<mshv_user_irq_entry> = entries
1904             .iter()
1905             .map(|entry| match entry {
1906                 IrqRoutingEntry::Mshv(e) => *e,
1907                 #[allow(unreachable_patterns)]
1908                 _ => panic!("IrqRoutingEntry type is wrong"),
1909             })
1910             .collect();
1911 
1912         // SAFETY: msi_routing initialized with entries.len() and now it is being turned into
1913         // entries_slice with entries.len() again. It is guaranteed to be large enough to hold
1914         // everything from entries.
1915         unsafe {
1916             let entries_slice: &mut [mshv_user_irq_entry] =
1917                 msi_routing[0].entries.as_mut_slice(entries.len());
1918             entries_slice.copy_from_slice(&entries);
1919         }
1920 
1921         self.fd
1922             .set_msi_routing(&msi_routing[0])
1923             .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
1924     }
1925 
1926     ///
1927     /// Start logging dirty pages
1928     ///
1929     fn start_dirty_log(&self) -> vm::Result<()> {
1930         self.fd
1931             .enable_dirty_page_tracking()
1932             .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))
1933     }
1934 
1935     ///
1936     /// Stop logging dirty pages
1937     ///
1938     fn stop_dirty_log(&self) -> vm::Result<()> {
1939         let dirty_log_slots = self.dirty_log_slots.read().unwrap();
1940         // Before disabling the dirty page tracking we need
1941         // to set the dirty bits in the Hypervisor
1942         // This is a requirement from Microsoft Hypervisor
1943         for (_, s) in dirty_log_slots.iter() {
1944             self.fd
1945                 .get_dirty_log(
1946                     s.guest_pfn,
1947                     s.memory_size as usize,
1948                     MSHV_GPAP_ACCESS_OP_SET as u8,
1949                 )
1950                 .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
1951         }
1952         self.fd
1953             .disable_dirty_page_tracking()
1954             .map_err(|e| vm::HypervisorVmError::StartDirtyLog(e.into()))?;
1955         Ok(())
1956     }
1957 
1958     ///
1959     /// Get dirty pages bitmap (one bit per page)
1960     ///
1961     fn get_dirty_log(&self, _slot: u32, base_gpa: u64, memory_size: u64) -> vm::Result<Vec<u64>> {
1962         self.fd
1963             .get_dirty_log(
1964                 base_gpa >> PAGE_SHIFT,
1965                 memory_size as usize,
1966                 MSHV_GPAP_ACCESS_OP_CLEAR as u8,
1967             )
1968             .map_err(|e| vm::HypervisorVmError::GetDirtyLog(e.into()))
1969     }
1970 
1971     /// Retrieve guest clock.
1972     #[cfg(target_arch = "x86_64")]
1973     fn get_clock(&self) -> vm::Result<ClockData> {
1974         let val = self
1975             .fd
1976             .get_partition_property(hv_partition_property_code_HV_PARTITION_PROPERTY_REFERENCE_TIME)
1977             .map_err(|e| vm::HypervisorVmError::GetClock(e.into()))?;
1978         Ok(MshvClockData { ref_time: val }.into())
1979     }
1980 
1981     /// Set guest clock.
1982     #[cfg(target_arch = "x86_64")]
1983     fn set_clock(&self, data: &ClockData) -> vm::Result<()> {
1984         let data: MshvClockData = (*data).into();
1985         self.fd
1986             .set_partition_property(
1987                 hv_partition_property_code_HV_PARTITION_PROPERTY_REFERENCE_TIME,
1988                 data.ref_time,
1989             )
1990             .map_err(|e| vm::HypervisorVmError::SetClock(e.into()))
1991     }
1992 
1993     /// Downcast to the underlying MshvVm type
1994     fn as_any(&self) -> &dyn Any {
1995         self
1996     }
1997 
1998     /// Initialize the SEV-SNP VM
1999     #[cfg(feature = "sev_snp")]
2000     fn sev_snp_init(&self) -> vm::Result<()> {
2001         self.fd
2002             .set_partition_property(
2003                 hv_partition_property_code_HV_PARTITION_PROPERTY_ISOLATION_STATE,
2004                 hv_partition_isolation_state_HV_PARTITION_ISOLATION_SECURE as u64,
2005             )
2006             .map_err(|e| vm::HypervisorVmError::InitializeSevSnp(e.into()))
2007     }
2008 
2009     ///
2010     /// Importing isolated pages, these pages will be used
2011     /// for the PSP(Platform Security Processor) measurement.
2012     #[cfg(feature = "sev_snp")]
2013     fn import_isolated_pages(
2014         &self,
2015         page_type: u32,
2016         page_size: u32,
2017         pages: &[u64],
2018     ) -> vm::Result<()> {
2019         debug_assert!(page_size == hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB);
2020         if pages.is_empty() {
2021             return Ok(());
2022         }
2023 
2024         let mut isolated_pages =
2025             vec_with_array_field::<mshv_import_isolated_pages, u64>(pages.len());
2026         isolated_pages[0].page_type = page_type as u8;
2027         isolated_pages[0].page_count = pages.len() as u64;
2028         // SAFETY: isolated_pages initialized with pages.len() and now it is being turned into
2029         // pages_slice with pages.len() again. It is guaranteed to be large enough to hold
2030         // everything from pages.
2031         unsafe {
2032             let pages_slice: &mut [u64] = isolated_pages[0].guest_pfns.as_mut_slice(pages.len());
2033             pages_slice.copy_from_slice(pages);
2034         }
2035         self.fd
2036             .import_isolated_pages(&isolated_pages[0])
2037             .map_err(|e| vm::HypervisorVmError::ImportIsolatedPages(e.into()))
2038     }
2039 
2040     ///
2041     /// Complete isolated import, telling the hypervisor that
2042     /// importing the pages to guest memory is complete.
2043     ///
2044     #[cfg(feature = "sev_snp")]
2045     fn complete_isolated_import(
2046         &self,
2047         snp_id_block: IGVM_VHS_SNP_ID_BLOCK,
2048         host_data: [u8; 32],
2049         id_block_enabled: u8,
2050     ) -> vm::Result<()> {
2051         let mut auth_info = hv_snp_id_auth_info {
2052             id_key_algorithm: snp_id_block.id_key_algorithm,
2053             auth_key_algorithm: snp_id_block.author_key_algorithm,
2054             ..Default::default()
2055         };
2056         // Each of r/s component is 576 bits long
2057         auth_info.id_block_signature[..SIG_R_COMPONENT_SIZE_IN_BYTES]
2058             .copy_from_slice(snp_id_block.id_key_signature.r_comp.as_ref());
2059         auth_info.id_block_signature
2060             [SIG_R_COMPONENT_SIZE_IN_BYTES..SIG_R_AND_S_COMPONENT_SIZE_IN_BYTES]
2061             .copy_from_slice(snp_id_block.id_key_signature.s_comp.as_ref());
2062         auth_info.id_key[..ECDSA_CURVE_ID_SIZE_IN_BYTES]
2063             .copy_from_slice(snp_id_block.id_public_key.curve.to_le_bytes().as_ref());
2064         auth_info.id_key[ECDSA_SIG_X_COMPONENT_START..ECDSA_SIG_X_COMPONENT_END]
2065             .copy_from_slice(snp_id_block.id_public_key.qx.as_ref());
2066         auth_info.id_key[ECDSA_SIG_Y_COMPONENT_START..ECDSA_SIG_Y_COMPONENT_END]
2067             .copy_from_slice(snp_id_block.id_public_key.qy.as_ref());
2068 
2069         let data = mshv_complete_isolated_import {
2070             import_data: hv_partition_complete_isolated_import_data {
2071                 psp_parameters: hv_psp_launch_finish_data {
2072                     id_block: hv_snp_id_block {
2073                         launch_digest: snp_id_block.ld,
2074                         family_id: snp_id_block.family_id,
2075                         image_id: snp_id_block.image_id,
2076                         version: snp_id_block.version,
2077                         guest_svn: snp_id_block.guest_svn,
2078                         policy: get_default_snp_guest_policy(),
2079                     },
2080                     id_auth_info: auth_info,
2081                     host_data,
2082                     id_block_enabled,
2083                     author_key_enabled: 0,
2084                 },
2085             },
2086         };
2087         self.fd
2088             .complete_isolated_import(&data)
2089             .map_err(|e| vm::HypervisorVmError::CompleteIsolatedImport(e.into()))
2090     }
2091 
2092     #[cfg(target_arch = "aarch64")]
2093     fn create_vgic(&self, config: VgicConfig) -> vm::Result<Arc<Mutex<dyn Vgic>>> {
2094         unimplemented!()
2095     }
2096 
2097     #[cfg(target_arch = "aarch64")]
2098     fn get_preferred_target(&self, kvi: &mut VcpuInit) -> vm::Result<()> {
2099         unimplemented!()
2100     }
2101 
2102     /// Pause the VM
2103     fn pause(&self) -> vm::Result<()> {
2104         // Freeze the partition
2105         self.fd
2106             .set_partition_property(
2107                 hv_partition_property_code_HV_PARTITION_PROPERTY_TIME_FREEZE,
2108                 1u64,
2109             )
2110             .map_err(|e| {
2111                 vm::HypervisorVmError::SetVmProperty(anyhow!(
2112                     "Failed to set partition property: {}",
2113                     e
2114                 ))
2115             })
2116     }
2117 
2118     /// Resume the VM
2119     fn resume(&self) -> vm::Result<()> {
2120         // Resuming the partition using TIME_FREEZE property
2121         self.fd
2122             .set_partition_property(
2123                 hv_partition_property_code_HV_PARTITION_PROPERTY_TIME_FREEZE,
2124                 0u64,
2125             )
2126             .map_err(|e| {
2127                 vm::HypervisorVmError::SetVmProperty(anyhow!(
2128                     "Failed to set partition property: {}",
2129                     e
2130                 ))
2131             })
2132     }
2133 
2134     #[cfg(feature = "sev_snp")]
2135     fn gain_page_access(&self, gpa: u64, size: u32) -> vm::Result<()> {
2136         use mshv_ioctls::set_bits;
2137         const ONE_GB: usize = 1024 * 1024 * 1024;
2138 
2139         if !self.sev_snp_enabled {
2140             return Ok(());
2141         }
2142 
2143         let start_gpfn: u64 = gpa >> PAGE_SHIFT;
2144         let end_gpfn: u64 = (gpa + size as u64 - 1) >> PAGE_SHIFT;
2145 
2146         // Enlarge the bitmap if the PFN is greater than the bitmap length
2147         if end_gpfn >= self.host_access_pages.load().as_ref().len() as u64 {
2148             self.host_access_pages.rcu(|bitmap| {
2149                 let mut bm = bitmap.as_ref().clone();
2150                 bm.enlarge(ONE_GB);
2151                 bm
2152             });
2153         }
2154 
2155         let gpas: Vec<u64> = (start_gpfn..=end_gpfn)
2156             .filter(|x| {
2157                 !self
2158                     .host_access_pages
2159                     .load()
2160                     .as_ref()
2161                     .is_bit_set(*x as usize)
2162             })
2163             .map(|x| x << PAGE_SHIFT)
2164             .collect();
2165 
2166         if !gpas.is_empty() {
2167             let mut gpa_list = vec_with_array_field::<mshv_modify_gpa_host_access, u64>(gpas.len());
2168             gpa_list[0].page_count = gpas.len() as u64;
2169             gpa_list[0].flags = set_bits!(
2170                 u8,
2171                 MSHV_GPA_HOST_ACCESS_BIT_ACQUIRE,
2172                 MSHV_GPA_HOST_ACCESS_BIT_READABLE,
2173                 MSHV_GPA_HOST_ACCESS_BIT_WRITABLE
2174             );
2175 
2176             // SAFETY: gpa_list initialized with gpas.len() and now it is being turned into
2177             // gpas_slice with gpas.len() again. It is guaranteed to be large enough to hold
2178             // everything from gpas.
2179             unsafe {
2180                 let gpas_slice: &mut [u64] = gpa_list[0].guest_pfns.as_mut_slice(gpas.len());
2181                 gpas_slice.copy_from_slice(gpas.as_slice());
2182             }
2183 
2184             self.fd
2185                 .modify_gpa_host_access(&gpa_list[0])
2186                 .map_err(|e| vm::HypervisorVmError::ModifyGpaHostAccess(e.into()))?;
2187 
2188             for acquired_gpa in gpas {
2189                 self.host_access_pages.rcu(|bitmap| {
2190                     let bm = bitmap.clone();
2191                     bm.set_bit((acquired_gpa >> PAGE_SHIFT) as usize);
2192                     bm
2193                 });
2194             }
2195         }
2196 
2197         Ok(())
2198     }
2199 }
2200