xref: /cloud-hypervisor/hypervisor/src/mshv/mod.rs (revision 9af2968a7dc47b89bf07ea9dc5e735084efcfa3a)
1 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
2 //
3 // Copyright © 2020, Microsoft Corporation
4 //
5 
6 use crate::arch::emulator::{PlatformEmulator, PlatformError};
7 
8 #[cfg(target_arch = "x86_64")]
9 use crate::arch::x86::emulator::{Emulator, EmulatorCpuState};
10 use crate::cpu;
11 use crate::cpu::Vcpu;
12 use crate::hypervisor;
13 use crate::vec_with_array_field;
14 use crate::vm::{self, VmmOps};
15 pub use mshv_bindings::*;
16 pub use mshv_ioctls::IoEventAddress;
17 use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
18 use serde_derive::{Deserialize, Serialize};
19 use std::sync::Arc;
20 use vm::DataMatch;
21 // x86_64 dependencies
22 #[cfg(target_arch = "x86_64")]
23 pub mod x86_64;
24 use crate::device;
25 use vmm_sys_util::eventfd::EventFd;
26 #[cfg(target_arch = "x86_64")]
27 pub use x86_64::VcpuMshvState as CpuState;
28 #[cfg(target_arch = "x86_64")]
29 pub use x86_64::*;
30 
31 #[cfg(target_arch = "x86_64")]
32 use std::fs::File;
33 use std::os::unix::io::AsRawFd;
34 use std::sync::RwLock;
35 
36 pub const PAGE_SHIFT: usize = 12;
37 
38 #[derive(Debug, Default, Copy, Clone, Serialize, Deserialize)]
39 pub struct HvState {
40     hypercall_page: u64,
41 }
42 
43 pub use HvState as VmState;
44 
45 /// Wrapper over mshv system ioctls.
46 pub struct MshvHypervisor {
47     mshv: Mshv,
48 }
49 
50 impl MshvHypervisor {
51     /// Create a hypervisor based on Mshv
52     pub fn new() -> hypervisor::Result<MshvHypervisor> {
53         let mshv_obj =
54             Mshv::new().map_err(|e| hypervisor::HypervisorError::HypervisorCreate(e.into()))?;
55         Ok(MshvHypervisor { mshv: mshv_obj })
56     }
57 }
58 /// Implementation of Hypervisor trait for Mshv
59 /// Example:
60 /// #[cfg(feature = "mshv")]
61 /// extern crate hypervisor
62 /// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
63 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
64 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
65 ///
66 impl hypervisor::Hypervisor for MshvHypervisor {
67     /// Create a mshv vm object and return the object as Vm trait object
68     /// Example
69     /// # extern crate hypervisor;
70     /// # use hypervisor::MshvHypervisor;
71     /// use hypervisor::MshvVm;
72     /// let hypervisor = MshvHypervisor::new().unwrap();
73     /// let vm = hypervisor.create_vm().unwrap()
74     ///
75     fn create_vm(&self) -> hypervisor::Result<Arc<dyn vm::Vm>> {
76         let fd: VmFd;
77         loop {
78             match self.mshv.create_vm() {
79                 Ok(res) => fd = res,
80                 Err(e) => {
81                     if e.errno() == libc::EINTR {
82                         // If the error returned is EINTR, which means the
83                         // ioctl has been interrupted, we have to retry as
84                         // this can't be considered as a regular error.
85                         continue;
86                     } else {
87                         return Err(hypervisor::HypervisorError::VmCreate(e.into()));
88                     }
89                 }
90             }
91             break;
92         }
93 
94         let msr_list = self.get_msr_list()?;
95         let num_msrs = msr_list.as_fam_struct_ref().nmsrs as usize;
96         let mut msrs = MsrEntries::new(num_msrs).unwrap();
97         let indices = msr_list.as_slice();
98         let msr_entries = msrs.as_mut_slice();
99         for (pos, index) in indices.iter().enumerate() {
100             msr_entries[pos].index = *index;
101         }
102         let vm_fd = Arc::new(fd);
103 
104         Ok(Arc::new(MshvVm {
105             fd: vm_fd,
106             msrs,
107             hv_state: hv_state_init(),
108             vmmops: None,
109         }))
110     }
111     ///
112     /// Get the supported CpuID
113     ///
114     fn get_cpuid(&self) -> hypervisor::Result<CpuId> {
115         Ok(CpuId::new(1).unwrap())
116     }
117     #[cfg(target_arch = "x86_64")]
118     ///
119     /// Retrieve the list of MSRs supported by KVM.
120     ///
121     fn get_msr_list(&self) -> hypervisor::Result<MsrList> {
122         self.mshv
123             .get_msr_index_list()
124             .map_err(|e| hypervisor::HypervisorError::GetMsrList(e.into()))
125     }
126 }
127 
128 #[allow(dead_code)]
129 /// Vcpu struct for Microsoft Hypervisor
130 pub struct MshvVcpu {
131     fd: VcpuFd,
132     vp_index: u8,
133     cpuid: CpuId,
134     msrs: MsrEntries,
135     hv_state: Arc<RwLock<HvState>>, // Mshv State
136     vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
137 }
138 
139 /// Implementation of Vcpu trait for Microsoft Hypervisor
140 /// Example:
141 /// #[cfg(feature = "mshv")]
142 /// extern crate hypervisor
143 /// let mshv = hypervisor::mshv::MshvHypervisor::new().unwrap();
144 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
145 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
146 /// let vcpu = vm.create_vcpu(0).unwrap();
147 /// vcpu.get/set().unwrap()
148 ///
149 impl cpu::Vcpu for MshvVcpu {
150     #[cfg(target_arch = "x86_64")]
151     ///
152     /// Returns the vCPU general purpose registers.
153     ///
154     fn get_regs(&self) -> cpu::Result<StandardRegisters> {
155         self.fd
156             .get_regs()
157             .map_err(|e| cpu::HypervisorCpuError::GetStandardRegs(e.into()))
158     }
159     #[cfg(target_arch = "x86_64")]
160     ///
161     /// Sets the vCPU general purpose registers.
162     ///
163     fn set_regs(&self, regs: &StandardRegisters) -> cpu::Result<()> {
164         self.fd
165             .set_regs(regs)
166             .map_err(|e| cpu::HypervisorCpuError::SetStandardRegs(e.into()))
167     }
168     #[cfg(target_arch = "x86_64")]
169     ///
170     /// Returns the vCPU special registers.
171     ///
172     fn get_sregs(&self) -> cpu::Result<SpecialRegisters> {
173         self.fd
174             .get_sregs()
175             .map_err(|e| cpu::HypervisorCpuError::GetSpecialRegs(e.into()))
176     }
177     #[cfg(target_arch = "x86_64")]
178     ///
179     /// Sets the vCPU special registers.
180     ///
181     fn set_sregs(&self, sregs: &SpecialRegisters) -> cpu::Result<()> {
182         self.fd
183             .set_sregs(sregs)
184             .map_err(|e| cpu::HypervisorCpuError::SetSpecialRegs(e.into()))
185     }
186     #[cfg(target_arch = "x86_64")]
187     ///
188     /// Returns the floating point state (FPU) from the vCPU.
189     ///
190     fn get_fpu(&self) -> cpu::Result<FpuState> {
191         self.fd
192             .get_fpu()
193             .map_err(|e| cpu::HypervisorCpuError::GetFloatingPointRegs(e.into()))
194     }
195     #[cfg(target_arch = "x86_64")]
196     ///
197     /// Set the floating point state (FPU) of a vCPU.
198     ///
199     fn set_fpu(&self, fpu: &FpuState) -> cpu::Result<()> {
200         self.fd
201             .set_fpu(fpu)
202             .map_err(|e| cpu::HypervisorCpuError::SetFloatingPointRegs(e.into()))
203     }
204 
205     #[cfg(target_arch = "x86_64")]
206     ///
207     /// Returns the model-specific registers (MSR) for this vCPU.
208     ///
209     fn get_msrs(&self, msrs: &mut MsrEntries) -> cpu::Result<usize> {
210         self.fd
211             .get_msrs(msrs)
212             .map_err(|e| cpu::HypervisorCpuError::GetMsrEntries(e.into()))
213     }
214     #[cfg(target_arch = "x86_64")]
215     ///
216     /// Setup the model-specific registers (MSR) for this vCPU.
217     /// Returns the number of MSR entries actually written.
218     ///
219     fn set_msrs(&self, msrs: &MsrEntries) -> cpu::Result<usize> {
220         self.fd
221             .set_msrs(msrs)
222             .map_err(|e| cpu::HypervisorCpuError::SetMsrEntries(e.into()))
223     }
224 
225     #[cfg(target_arch = "x86_64")]
226     ///
227     /// X86 specific call that returns the vcpu's current "xcrs".
228     ///
229     fn get_xcrs(&self) -> cpu::Result<ExtendedControlRegisters> {
230         self.fd
231             .get_xcrs()
232             .map_err(|e| cpu::HypervisorCpuError::GetXcsr(e.into()))
233     }
234     #[cfg(target_arch = "x86_64")]
235     ///
236     /// X86 specific call that sets the vcpu's current "xcrs".
237     ///
238     fn set_xcrs(&self, xcrs: &ExtendedControlRegisters) -> cpu::Result<()> {
239         self.fd
240             .set_xcrs(xcrs)
241             .map_err(|e| cpu::HypervisorCpuError::SetXcsr(e.into()))
242     }
243     #[cfg(target_arch = "x86_64")]
244     ///
245     /// Returns currently pending exceptions, interrupts, and NMIs as well as related
246     /// states of the vcpu.
247     ///
248     fn get_vcpu_events(&self) -> cpu::Result<VcpuEvents> {
249         self.fd
250             .get_vcpu_events()
251             .map_err(|e| cpu::HypervisorCpuError::GetVcpuEvents(e.into()))
252     }
253     #[cfg(target_arch = "x86_64")]
254     ///
255     /// Sets pending exceptions, interrupts, and NMIs as well as related states
256     /// of the vcpu.
257     ///
258     fn set_vcpu_events(&self, events: &VcpuEvents) -> cpu::Result<()> {
259         self.fd
260             .set_vcpu_events(events)
261             .map_err(|e| cpu::HypervisorCpuError::SetVcpuEvents(e.into()))
262     }
263     #[cfg(target_arch = "x86_64")]
264     ///
265     /// X86 specific call to enable HyperV SynIC
266     ///
267     fn enable_hyperv_synic(&self) -> cpu::Result<()> {
268         /* We always have SynIC enabled on MSHV */
269         Ok(())
270     }
271     #[allow(non_upper_case_globals)]
272     fn run(&self) -> std::result::Result<cpu::VmExit, cpu::HypervisorCpuError> {
273         // Safe because this is just only done during initialization.
274         // TODO don't zero it everytime we enter this function.
275         let hv_message: hv_message = unsafe { std::mem::zeroed() };
276         match self.fd.run(hv_message) {
277             Ok(x) => match x.header.message_type {
278                 hv_message_type_HVMSG_X64_HALT => {
279                     debug!("HALT");
280                     Ok(cpu::VmExit::Reset)
281                 }
282                 hv_message_type_HVMSG_UNRECOVERABLE_EXCEPTION => {
283                     warn!("TRIPLE FAULT");
284                     Ok(cpu::VmExit::Shutdown)
285                 }
286                 hv_message_type_HVMSG_X64_IO_PORT_INTERCEPT => {
287                     let info = x.to_ioport_info().unwrap();
288                     let access_info = info.access_info;
289                     let len = unsafe { access_info.__bindgen_anon_1.access_size() } as usize;
290                     let is_write = info.header.intercept_access_type == 1;
291                     let port = info.port_number;
292                     let mut data: [u8; 4] = [0; 4];
293                     let mut ret_rax = info.rax;
294 
295                     /*
296                      * XXX: Ignore QEMU fw_cfg (0x5xx) and debug console (0x402) ports.
297                      *
298                      * Cloud Hypervisor doesn't support fw_cfg at the moment. It does support 0x402
299                      * under the "fwdebug" feature flag. But that feature is not enabled by default
300                      * and is considered legacy.
301                      *
302                      * OVMF unconditionally pokes these IO ports with string IO.
303                      *
304                      * Instead of trying to implement string IO support now which does not do much
305                      * now, skip those ports explicitly to avoid panicking.
306                      *
307                      * Proper string IO support can be added once we gain the ability to translate
308                      * guest virtual addresses to guest physical addresses on MSHV.
309                      */
310                     match port {
311                         0x402 | 0x510 | 0x511 | 0x514 => {
312                             let insn_len = info.header.instruction_length() as u64;
313 
314                             /* Advance RIP and update RAX */
315                             let arr_reg_name_value = [
316                                 (
317                                     hv_register_name::HV_X64_REGISTER_RIP,
318                                     info.header.rip + insn_len,
319                                 ),
320                                 (hv_register_name::HV_X64_REGISTER_RAX, ret_rax),
321                             ];
322                             set_registers_64!(self.fd, arr_reg_name_value)
323                                 .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
324                             return Ok(cpu::VmExit::Ignore);
325                         }
326                         _ => {}
327                     }
328 
329                     if unsafe { access_info.__bindgen_anon_1.string_op() } == 1 {
330                         panic!("String IN/OUT not supported");
331                     }
332                     if unsafe { access_info.__bindgen_anon_1.rep_prefix() } == 1 {
333                         panic!("Rep IN/OUT not supported");
334                     }
335 
336                     if is_write {
337                         let data = (info.rax as u32).to_le_bytes();
338                         if let Some(vmmops) = &self.vmmops {
339                             vmmops
340                                 .pio_write(port.into(), &data[0..len])
341                                 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
342                         }
343                     } else {
344                         if let Some(vmmops) = &self.vmmops {
345                             vmmops
346                                 .pio_read(port.into(), &mut data[0..len])
347                                 .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
348                         }
349 
350                         let v = u32::from_le_bytes(data);
351                         /* Preserve high bits in EAX but clear out high bits in RAX */
352                         let mask = 0xffffffff >> (32 - len * 8);
353                         let eax = (info.rax as u32 & !mask) | (v & mask);
354                         ret_rax = eax as u64;
355                     }
356 
357                     let insn_len = info.header.instruction_length() as u64;
358 
359                     /* Advance RIP and update RAX */
360                     let arr_reg_name_value = [
361                         (
362                             hv_register_name::HV_X64_REGISTER_RIP,
363                             info.header.rip + insn_len,
364                         ),
365                         (hv_register_name::HV_X64_REGISTER_RAX, ret_rax),
366                     ];
367                     set_registers_64!(self.fd, arr_reg_name_value)
368                         .map_err(|e| cpu::HypervisorCpuError::SetRegister(e.into()))?;
369                     Ok(cpu::VmExit::Ignore)
370                 }
371                 hv_message_type_HVMSG_UNMAPPED_GPA => {
372                     let info = x.to_memory_info().unwrap();
373                     let insn_len = info.instruction_byte_count as usize;
374                     assert!(insn_len > 0 && insn_len <= 16);
375 
376                     let mut context = MshvEmulatorContext {
377                         vcpu: self,
378                         map: (info.guest_virtual_address, info.guest_physical_address),
379                     };
380 
381                     // Create a new emulator.
382                     let mut emul = Emulator::new(&mut context);
383 
384                     // Emulate the trapped instruction, and only the first one.
385                     let new_state = emul
386                         .emulate_first_insn(self.vp_index as usize, &info.instruction_bytes)
387                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
388 
389                     // Set CPU state back.
390                     context
391                         .set_cpu_state(self.vp_index as usize, new_state)
392                         .map_err(|e| cpu::HypervisorCpuError::RunVcpu(e.into()))?;
393 
394                     Ok(cpu::VmExit::Ignore)
395                 }
396                 hv_message_type_HVMSG_X64_CPUID_INTERCEPT => {
397                     let info = x.to_cpuid_info().unwrap();
398                     debug!("cpuid eax: {:x}", { info.rax });
399                     Ok(cpu::VmExit::Ignore)
400                 }
401                 hv_message_type_HVMSG_X64_MSR_INTERCEPT => {
402                     let info = x.to_msr_info().unwrap();
403                     if info.header.intercept_access_type == 0 {
404                         debug!("msr read: {:x}", { info.msr_number });
405                     } else {
406                         debug!("msr write: {:x}", { info.msr_number });
407                     }
408                     Ok(cpu::VmExit::Ignore)
409                 }
410                 hv_message_type_HVMSG_X64_EXCEPTION_INTERCEPT => {
411                     //TODO: Handler for VMCALL here.
412                     let info = x.to_exception_info().unwrap();
413                     debug!("Exception Info {:?}", { info.exception_vector });
414                     Ok(cpu::VmExit::Ignore)
415                 }
416                 exit => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
417                     "Unhandled VCPU exit {:?}",
418                     exit
419                 ))),
420             },
421 
422             Err(e) => match e.errno() {
423                 libc::EAGAIN | libc::EINTR => Ok(cpu::VmExit::Ignore),
424                 _ => Err(cpu::HypervisorCpuError::RunVcpu(anyhow!(
425                     "VCPU error {:?}",
426                     e
427                 ))),
428             },
429         }
430     }
431     #[cfg(target_arch = "x86_64")]
432     ///
433     /// X86 specific call to setup the CPUID registers.
434     ///
435     fn set_cpuid2(&self, _cpuid: &CpuId) -> cpu::Result<()> {
436         Ok(())
437     }
438     #[cfg(target_arch = "x86_64")]
439     ///
440     /// X86 specific call to retrieve the CPUID registers.
441     ///
442     fn get_cpuid2(&self, _num_entries: usize) -> cpu::Result<CpuId> {
443         Ok(self.cpuid.clone())
444     }
445     #[cfg(target_arch = "x86_64")]
446     ///
447     /// Returns the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
448     ///
449     fn get_lapic(&self) -> cpu::Result<LapicState> {
450         self.fd
451             .get_lapic()
452             .map_err(|e| cpu::HypervisorCpuError::GetlapicState(e.into()))
453     }
454     #[cfg(target_arch = "x86_64")]
455     ///
456     /// Sets the state of the LAPIC (Local Advanced Programmable Interrupt Controller).
457     ///
458     fn set_lapic(&self, lapic: &LapicState) -> cpu::Result<()> {
459         self.fd
460             .set_lapic(lapic)
461             .map_err(|e| cpu::HypervisorCpuError::SetLapicState(e.into()))
462     }
463     #[cfg(target_arch = "x86_64")]
464     ///
465     /// X86 specific call that returns the vcpu's current "xsave struct".
466     ///
467     fn get_xsave(&self) -> cpu::Result<Xsave> {
468         self.fd
469             .get_xsave()
470             .map_err(|e| cpu::HypervisorCpuError::GetXsaveState(e.into()))
471     }
472     #[cfg(target_arch = "x86_64")]
473     ///
474     /// X86 specific call that sets the vcpu's current "xsave struct".
475     ///
476     fn set_xsave(&self, xsave: &Xsave) -> cpu::Result<()> {
477         self.fd
478             .set_xsave(xsave)
479             .map_err(|e| cpu::HypervisorCpuError::SetXsaveState(e.into()))
480     }
481     ///
482     /// Set CPU state
483     ///
484     fn set_state(&self, state: &CpuState) -> cpu::Result<()> {
485         self.set_msrs(&state.msrs)?;
486         self.set_vcpu_events(&state.vcpu_events)?;
487         self.set_regs(&state.regs)?;
488         self.set_sregs(&state.sregs)?;
489         self.set_fpu(&state.fpu)?;
490         self.set_xcrs(&state.xcrs)?;
491         self.set_lapic(&state.lapic)?;
492         self.set_xsave(&state.xsave)?;
493         self.fd
494             .set_debug_regs(&state.dbg)
495             .map_err(|e| cpu::HypervisorCpuError::SetDebugRegs(e.into()))?;
496         Ok(())
497     }
498     ///
499     /// Get CPU State
500     ///
501     fn state(&self) -> cpu::Result<CpuState> {
502         let regs = self.get_regs()?;
503         let sregs = self.get_sregs()?;
504         let xcrs = self.get_xcrs()?;
505         let fpu = self.get_fpu()?;
506         let vcpu_events = self.get_vcpu_events()?;
507         let mut msrs = self.msrs.clone();
508         self.get_msrs(&mut msrs)?;
509         let lapic = self.get_lapic()?;
510         let xsave = self.get_xsave()?;
511         let dbg = self
512             .fd
513             .get_debug_regs()
514             .map_err(|e| cpu::HypervisorCpuError::GetDebugRegs(e.into()))?;
515         Ok(CpuState {
516             msrs,
517             vcpu_events,
518             regs,
519             sregs,
520             fpu,
521             xcrs,
522             lapic,
523             dbg,
524             xsave,
525         })
526     }
527     #[cfg(target_arch = "x86_64")]
528     ///
529     /// Translate guest virtual address to guest physical address
530     ///
531     fn translate_gva(&self, gva: u64, flags: u64) -> cpu::Result<(u64, hv_translate_gva_result)> {
532         let r = self
533             .fd
534             .translate_gva(gva, flags)
535             .map_err(|e| cpu::HypervisorCpuError::TranslateVirtualAddress(e.into()))?;
536 
537         Ok(r)
538     }
539     #[cfg(target_arch = "x86_64")]
540     ///
541     /// X86 specific call that returns the vcpu's current "suspend registers".
542     ///
543     fn get_suspend_regs(&self) -> cpu::Result<SuspendRegisters> {
544         self.fd
545             .get_suspend_regs()
546             .map_err(|e| cpu::HypervisorCpuError::GetSuspendRegs(e.into()))
547     }
548 }
549 
550 struct MshvEmulatorContext<'a> {
551     vcpu: &'a MshvVcpu,
552     map: (u64, u64), // Initial GVA to GPA mapping provided by the hypervisor
553 }
554 
555 impl<'a> MshvEmulatorContext<'a> {
556     // Do the actual gva -> gpa translation
557     #[allow(non_upper_case_globals)]
558     fn translate(&self, gva: u64) -> Result<u64, PlatformError> {
559         if self.map.0 == gva {
560             return Ok(self.map.1);
561         }
562 
563         // TODO: More fine-grained control for the flags
564         let flags = HV_TRANSLATE_GVA_VALIDATE_READ | HV_TRANSLATE_GVA_VALIDATE_WRITE;
565 
566         let r = self
567             .vcpu
568             .translate_gva(gva, flags.into())
569             .map_err(|e| PlatformError::TranslateVirtualAddress(anyhow!(e)))?;
570 
571         let result_code = unsafe { r.1.__bindgen_anon_1.result_code };
572         match result_code {
573             hv_translate_gva_result_code_HV_TRANSLATE_GVA_SUCCESS => Ok(r.0),
574             _ => Err(PlatformError::TranslateVirtualAddress(anyhow!(result_code))),
575         }
576     }
577 }
578 
579 /// Platform emulation for Hyper-V
580 impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
581     type CpuState = EmulatorCpuState;
582 
583     fn read_memory(&self, gva: u64, data: &mut [u8]) -> Result<(), PlatformError> {
584         let gpa = self.translate(gva)?;
585         debug!(
586             "mshv emulator: memory read {} bytes from [{:#x} -> {:#x}]",
587             data.len(),
588             gva,
589             gpa
590         );
591 
592         if let Some(vmmops) = &self.vcpu.vmmops {
593             if vmmops.guest_mem_read(gpa, data).is_err() {
594                 vmmops
595                     .mmio_read(gpa, data)
596                     .map_err(|e| PlatformError::MemoryReadFailure(e.into()))?;
597             }
598         }
599 
600         Ok(())
601     }
602 
603     fn write_memory(&mut self, gva: u64, data: &[u8]) -> Result<(), PlatformError> {
604         let gpa = self.translate(gva)?;
605         debug!(
606             "mshv emulator: memory write {} bytes at [{:#x} -> {:#x}]",
607             data.len(),
608             gva,
609             gpa
610         );
611 
612         if let Some(vmmops) = &self.vcpu.vmmops {
613             if vmmops.guest_mem_write(gpa, data).is_err() {
614                 vmmops
615                     .mmio_write(gpa, data)
616                     .map_err(|e| PlatformError::MemoryWriteFailure(e.into()))?;
617             }
618         }
619 
620         Ok(())
621     }
622 
623     fn cpu_state(&self, cpu_id: usize) -> Result<Self::CpuState, PlatformError> {
624         if cpu_id != self.vcpu.vp_index as usize {
625             return Err(PlatformError::GetCpuStateFailure(anyhow!(
626                 "CPU id mismatch {:?} {:?}",
627                 cpu_id,
628                 self.vcpu.vp_index
629             )));
630         }
631 
632         let regs = self
633             .vcpu
634             .get_regs()
635             .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?;
636         let sregs = self
637             .vcpu
638             .get_sregs()
639             .map_err(|e| PlatformError::GetCpuStateFailure(e.into()))?;
640 
641         debug!("mshv emulator: Getting new CPU state");
642         debug!("mshv emulator: {:#x?}", regs);
643 
644         Ok(EmulatorCpuState { regs, sregs })
645     }
646 
647     fn set_cpu_state(&self, cpu_id: usize, state: Self::CpuState) -> Result<(), PlatformError> {
648         if cpu_id != self.vcpu.vp_index as usize {
649             return Err(PlatformError::SetCpuStateFailure(anyhow!(
650                 "CPU id mismatch {:?} {:?}",
651                 cpu_id,
652                 self.vcpu.vp_index
653             )));
654         }
655 
656         debug!("mshv emulator: Setting new CPU state");
657         debug!("mshv emulator: {:#x?}", state.regs);
658 
659         self.vcpu
660             .set_regs(&state.regs)
661             .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))?;
662         self.vcpu
663             .set_sregs(&state.sregs)
664             .map_err(|e| PlatformError::SetCpuStateFailure(e.into()))
665     }
666 
667     fn gva_to_gpa(&self, gva: u64) -> Result<u64, PlatformError> {
668         self.translate(gva)
669     }
670 
671     fn fetch(&self, _ip: u64, _instruction_bytes: &mut [u8]) -> Result<(), PlatformError> {
672         Err(PlatformError::MemoryReadFailure(anyhow!("unimplemented")))
673     }
674 }
675 
676 #[allow(dead_code)]
677 /// Wrapper over Mshv VM ioctls.
678 pub struct MshvVm {
679     fd: Arc<VmFd>,
680     msrs: MsrEntries,
681     // Hypervisor State
682     hv_state: Arc<RwLock<HvState>>,
683     vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
684 }
685 
686 fn hv_state_init() -> Arc<RwLock<HvState>> {
687     Arc::new(RwLock::new(HvState { hypercall_page: 0 }))
688 }
689 
690 ///
691 /// Implementation of Vm trait for Mshv
692 /// Example:
693 /// #[cfg(feature = "mshv")]
694 /// # extern crate hypervisor;
695 /// # use hypervisor::MshvHypervisor;
696 /// let mshv = MshvHypervisor::new().unwrap();
697 /// let hypervisor: Arc<dyn hypervisor::Hypervisor> = Arc::new(mshv);
698 /// let vm = hypervisor.create_vm().expect("new VM fd creation failed");
699 /// vm.set/get().unwrap()
700 ///
701 impl vm::Vm for MshvVm {
702     #[cfg(target_arch = "x86_64")]
703     ///
704     /// Sets the address of the three-page region in the VM's address space.
705     ///
706     fn set_tss_address(&self, _offset: usize) -> vm::Result<()> {
707         Ok(())
708     }
709     ///
710     /// Creates an in-kernel interrupt controller.
711     ///
712     fn create_irq_chip(&self) -> vm::Result<()> {
713         Ok(())
714     }
715     ///
716     /// Registers an event that will, when signaled, trigger the `gsi` IRQ.
717     ///
718     fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
719         debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
720 
721         self.fd
722             .register_irqfd(fd, gsi)
723             .map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
724 
725         Ok(())
726     }
727     ///
728     /// Unregisters an event that will, when signaled, trigger the `gsi` IRQ.
729     ///
730     fn unregister_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
731         debug!("unregister_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
732 
733         self.fd
734             .unregister_irqfd(fd, gsi)
735             .map_err(|e| vm::HypervisorVmError::UnregisterIrqFd(e.into()))?;
736 
737         Ok(())
738     }
739     ///
740     /// Creates a VcpuFd object from a vcpu RawFd.
741     ///
742     fn create_vcpu(
743         &self,
744         id: u8,
745         vmmops: Option<Arc<Box<dyn VmmOps>>>,
746     ) -> vm::Result<Arc<dyn cpu::Vcpu>> {
747         let vcpu_fd = self
748             .fd
749             .create_vcpu(id)
750             .map_err(|e| vm::HypervisorVmError::CreateVcpu(e.into()))?;
751         let vcpu = MshvVcpu {
752             fd: vcpu_fd,
753             vp_index: id,
754             cpuid: CpuId::new(1).unwrap(),
755             msrs: self.msrs.clone(),
756             hv_state: self.hv_state.clone(),
757             vmmops,
758         };
759         Ok(Arc::new(vcpu))
760     }
761     #[cfg(target_arch = "x86_64")]
762     fn enable_split_irq(&self) -> vm::Result<()> {
763         Ok(())
764     }
765     #[cfg(target_arch = "x86_64")]
766     fn enable_sgx_attribute(&self, _file: File) -> vm::Result<()> {
767         Ok(())
768     }
769     fn register_ioevent(
770         &self,
771         fd: &EventFd,
772         addr: &IoEventAddress,
773         datamatch: Option<DataMatch>,
774     ) -> vm::Result<()> {
775         debug!(
776             "register_ioevent fd {} addr {:x?} datamatch {:?}",
777             fd.as_raw_fd(),
778             addr,
779             datamatch
780         );
781         if let Some(dm) = datamatch {
782             match dm {
783                 vm::DataMatch::DataMatch32(mshv_dm32) => self
784                     .fd
785                     .register_ioevent(fd, addr, mshv_dm32)
786                     .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())),
787                 vm::DataMatch::DataMatch64(mshv_dm64) => self
788                     .fd
789                     .register_ioevent(fd, addr, mshv_dm64)
790                     .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into())),
791             }
792         } else {
793             self.fd
794                 .register_ioevent(fd, addr, NoDatamatch)
795                 .map_err(|e| vm::HypervisorVmError::RegisterIoEvent(e.into()))
796         }
797     }
798     /// Unregister an event from a certain address it has been previously registered to.
799     fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> vm::Result<()> {
800         debug!("unregister_ioevent fd {} addr {:x?}", fd.as_raw_fd(), addr);
801 
802         self.fd
803             .unregister_ioevent(fd, addr, NoDatamatch)
804             .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into()))
805     }
806 
807     /// Creates a guest physical memory region.
808     fn create_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
809         self.fd
810             .map_user_memory(user_memory_region)
811             .map_err(|e| vm::HypervisorVmError::CreateUserMemory(e.into()))?;
812         Ok(())
813     }
814 
815     /// Removes a guest physical memory region.
816     fn remove_user_memory_region(&self, user_memory_region: MemoryRegion) -> vm::Result<()> {
817         self.fd
818             .unmap_user_memory(user_memory_region)
819             .map_err(|e| vm::HypervisorVmError::RemoveUserMemory(e.into()))?;
820         Ok(())
821     }
822 
823     fn make_user_memory_region(
824         &self,
825         _slot: u32,
826         guest_phys_addr: u64,
827         memory_size: u64,
828         userspace_addr: u64,
829         readonly: bool,
830         _log_dirty_pages: bool,
831     ) -> MemoryRegion {
832         let mut flags = HV_MAP_GPA_READABLE | HV_MAP_GPA_EXECUTABLE;
833         if !readonly {
834             flags |= HV_MAP_GPA_WRITABLE;
835         }
836 
837         mshv_user_mem_region {
838             flags,
839             guest_pfn: guest_phys_addr >> PAGE_SHIFT,
840             size: memory_size,
841             userspace_addr: userspace_addr as u64,
842         }
843     }
844 
845     fn create_passthrough_device(&self) -> vm::Result<Arc<dyn device::Device>> {
846         Err(vm::HypervisorVmError::CreatePassthroughDevice(anyhow!(
847             "No passthrough support"
848         )))
849     }
850 
851     fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
852         let mut msi_routing =
853             vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len());
854         msi_routing[0].nr = entries.len() as u32;
855 
856         unsafe {
857             let entries_slice: &mut [mshv_msi_routing_entry] =
858                 msi_routing[0].entries.as_mut_slice(entries.len());
859             entries_slice.copy_from_slice(entries);
860         }
861 
862         self.fd
863             .set_msi_routing(&msi_routing[0])
864             .map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
865     }
866     ///
867     /// Get the Vm state. Return VM specific data
868     ///
869     fn state(&self) -> vm::Result<VmState> {
870         Ok(*self.hv_state.read().unwrap())
871     }
872     ///
873     /// Set the VM state
874     ///
875     fn set_state(&self, state: VmState) -> vm::Result<()> {
876         self.hv_state.write().unwrap().hypercall_page = state.hypercall_page;
877         Ok(())
878     }
879     ///
880     /// Get dirty pages bitmap (one bit per page)
881     ///
882     fn get_dirty_log(&self, _slot: u32, _memory_size: u64) -> vm::Result<Vec<u64>> {
883         Err(vm::HypervisorVmError::GetDirtyLog(anyhow!(
884             "get_dirty_log not implemented"
885         )))
886     }
887 }
888 pub use hv_cpuid_entry as CpuIdEntry;
889 
890 pub type IrqRoutingEntry = mshv_msi_routing_entry;
891 
892 pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
893