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