summary refs log tree commit diff
path: root/kvm/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'kvm/src/lib.rs')
-rw-r--r--kvm/src/lib.rs54
1 files changed, 51 insertions, 3 deletions
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
index 2d951f2..b8cd12b 100644
--- a/kvm/src/lib.rs
+++ b/kvm/src/lib.rs
@@ -1124,6 +1124,16 @@ pub enum VcpuExit {
     IoapicEoi {
         vector: u8,
     },
+    HypervSynic {
+        msr: u32,
+        control: u64,
+        evt_page: u64,
+        msg_page: u64,
+    },
+    HypervHcall {
+        input: u64,
+        params: [u64; 2],
+    },
     Unknown,
     Exception,
     Hypercall,
@@ -1243,10 +1253,10 @@ impl Vcpu {
         &self.guest_mem
     }
 
-    /// Sets the data received by an mmio or ioport read/in instruction.
+    /// Sets the data received by a mmio read, ioport in, or hypercall instruction.
     ///
-    /// This function should be called after `Vcpu::run` returns an `VcpuExit::IoIn` or
-    /// `Vcpu::MmioRead`.
+    /// This function should be called after `Vcpu::run` returns an `VcpuExit::IoIn`,
+    /// `VcpuExit::MmioRead`, or 'VcpuExit::HypervHcall`.
     #[allow(clippy::cast_ptr_alignment)]
     pub fn set_data(&self, data: &[u8]) -> Result<()> {
         // Safe because we know we mapped enough memory to hold the kvm_run struct because the
@@ -1288,6 +1298,20 @@ impl Vcpu {
                 mmio.data[..len].copy_from_slice(data);
                 Ok(())
             }
+            KVM_EXIT_HYPERV => {
+                // Safe because the exit_reason (which comes from the kernel) told us which
+                // union field to use.
+                let hyperv = unsafe { &mut run.__bindgen_anon_1.hyperv };
+                if hyperv.type_ != KVM_EXIT_HYPERV_HCALL {
+                    return Err(Error::new(EINVAL));
+                }
+                let hcall = unsafe { &mut hyperv.u.hcall };
+                if data.len() != std::mem::size_of::<u64>() {
+                    return Err(Error::new(EINVAL));
+                }
+                hcall.result.to_ne_bytes().copy_from_slice(data);
+                Ok(())
+            }
             _ => Err(Error::new(EINVAL)),
         }
     }
@@ -1840,6 +1864,30 @@ impl RunnableVcpu {
                     let vector = unsafe { run.__bindgen_anon_1.eoi.vector };
                     Ok(VcpuExit::IoapicEoi { vector })
                 }
+                KVM_EXIT_HYPERV => {
+                    // Safe because the exit_reason (which comes from the kernel) told us which
+                    // union field to use.
+                    let hyperv = unsafe { &run.__bindgen_anon_1.hyperv };
+                    match hyperv.type_ as u32 {
+                        KVM_EXIT_HYPERV_SYNIC => {
+                            let synic = unsafe { &hyperv.u.synic };
+                            Ok(VcpuExit::HypervSynic {
+                                msr: synic.msr,
+                                control: synic.control,
+                                evt_page: synic.evt_page,
+                                msg_page: synic.msg_page,
+                            })
+                        }
+                        KVM_EXIT_HYPERV_HCALL => {
+                            let hcall = unsafe { &hyperv.u.hcall };
+                            Ok(VcpuExit::HypervHcall {
+                                input: hcall.input,
+                                params: hcall.params,
+                            })
+                        }
+                        _ => Err(Error::new(EINVAL)),
+                    }
+                }
                 KVM_EXIT_UNKNOWN => Ok(VcpuExit::Unknown),
                 KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception),
                 KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall),