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