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