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