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