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