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