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