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