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