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