summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock10
-rw-r--r--crosvm_plugin/Cargo.toml2
-rw-r--r--crosvm_plugin/crosvm.h10
-rw-r--r--crosvm_plugin/src/lib.rs28
-rw-r--r--kvm/src/lib.rs35
-rw-r--r--plugin_proto/Cargo.toml2
-rw-r--r--plugin_proto/protos/plugin.proto13
-rw-r--r--src/plugin/vcpu.rs11
-rw-r--r--tests/plugins.rs13
9 files changed, 110 insertions, 14 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 2717631..9a9bbe7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -53,7 +53,7 @@ dependencies = [
  "aarch64 0.1.0",
  "arch 0.1.0",
  "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "crosvm_plugin 0.14.0",
+ "crosvm_plugin 0.15.0",
  "data_model 0.1.0",
  "devices 0.1.0",
  "gpu_buffer 0.1.0",
@@ -66,7 +66,7 @@ dependencies = [
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
  "net_util 0.1.0",
  "p9 0.1.0",
- "plugin_proto 0.14.0",
+ "plugin_proto 0.15.0",
  "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "qcow 0.1.0",
  "qcow_utils 0.1.0",
@@ -80,12 +80,12 @@ dependencies = [
 
 [[package]]
 name = "crosvm_plugin"
-version = "0.14.0"
+version = "0.15.0"
 dependencies = [
  "kvm 0.1.0",
  "kvm_sys 0.1.0",
  "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
- "plugin_proto 0.14.0",
+ "plugin_proto 0.15.0",
  "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "sys_util 0.1.0",
 ]
@@ -221,7 +221,7 @@ dependencies = [
 
 [[package]]
 name = "plugin_proto"
-version = "0.14.0"
+version = "0.15.0"
 dependencies = [
  "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
  "kvm_sys 0.1.0",
diff --git a/crosvm_plugin/Cargo.toml b/crosvm_plugin/Cargo.toml
index 3c61aa4..c203f4d 100644
--- a/crosvm_plugin/Cargo.toml
+++ b/crosvm_plugin/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "crosvm_plugin"
-version = "0.14.0"
+version = "0.15.0"
 authors = ["The Chromium OS Authors"]
 
 [lib]
diff --git a/crosvm_plugin/crosvm.h b/crosvm_plugin/crosvm.h
index 42c979a..947a198 100644
--- a/crosvm_plugin/crosvm.h
+++ b/crosvm_plugin/crosvm.h
@@ -47,7 +47,7 @@ extern "C" {
  * do not indicate anything about what version of crosvm is running.
  */
 #define CROSVM_API_MAJOR 0
-#define CROSVM_API_MINOR 13
+#define CROSVM_API_MINOR 15
 #define CROSVM_API_PATCH 0
 
 enum crosvm_address_space {
@@ -525,6 +525,14 @@ int crosvm_vcpu_get_mp_state(struct crosvm_vcpu *,
 int crosvm_vcpu_set_mp_state(struct crosvm_vcpu *,
                              const struct kvm_mp_state *__mp_state);
 
+/* Gets currently pending exceptions, interrupts, NMIs, etc for VCPU. */
+int crosvm_vcpu_get_vcpu_events(struct crosvm_vcpu *,
+                                struct kvm_vcpu_events *);
+
+/* Sets currently pending exceptions, interrupts, NMIs, etc for VCPU. */
+int crosvm_vcpu_set_vcpu_events(struct crosvm_vcpu *,
+                                const struct kvm_vcpu_events *);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs
index 231ee25..24d99ca 100644
--- a/crosvm_plugin/src/lib.rs
+++ b/crosvm_plugin/src/lib.rs
@@ -46,7 +46,7 @@ use kvm::dirty_log_bitmap_size;
 
 use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_xcrs, kvm_msr_entry,
               kvm_cpuid_entry2, kvm_lapic_state, kvm_mp_state, kvm_pic_state, kvm_ioapic_state,
-              kvm_pit_state2};
+              kvm_pit_state2, kvm_vcpu_events};
 
 use plugin_proto::*;
 
@@ -172,6 +172,8 @@ enum Stat {
     VcpuSetLapicState,
     VcpuGetMpState,
     VcpuSetMpState,
+    VcpuGetVcpuEvents,
+    VcpuSetVcpuEvents,
     NewConnection,
 
     Count,
@@ -1487,3 +1489,27 @@ pub unsafe extern "C" fn crosvm_vcpu_set_mp_state(this: *mut crosvm_vcpu,
     let ret = this.set_state(VcpuRequest_StateSet::MP, state);
     to_crosvm_rc(ret)
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_get_vcpu_events(this: *mut crosvm_vcpu,
+                                                     events: *mut kvm_vcpu_events)
+                                                     -> c_int {
+    let _u = STATS.record(Stat::VcpuGetVcpuEvents);
+    let this = &mut *this;
+    let events = from_raw_parts_mut(events as *mut u8,
+                                    size_of::<kvm_vcpu_events>());
+    let ret = this.get_state(VcpuRequest_StateSet::EVENTS, events);
+    to_crosvm_rc(ret)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_vcpu_events(this: *mut crosvm_vcpu,
+                                                     events: *const kvm_vcpu_events)
+                                                     -> c_int {
+    let _u = STATS.record(Stat::VcpuSetVcpuEvents);
+    let this = &mut *this;
+    let events = from_raw_parts(events as *mut u8,
+                                size_of::<kvm_vcpu_events>());
+    let ret = this.set_state(VcpuRequest_StateSet::EVENTS, events);
+    to_crosvm_rc(ret)
+}
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
index adac9fb..ea288eb 100644
--- a/kvm/src/lib.rs
+++ b/kvm/src/lib.rs
@@ -1169,6 +1169,41 @@ impl Vcpu {
         Ok(())
     }
 
+    /// Gets the vcpu's currently pending exceptions, interrupts, NMIs, etc
+    ///
+    /// See the documentation for KVM_GET_VCPU_EVENTS.
+    ///
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn get_vcpu_events(&self) -> Result<kvm_vcpu_events> {
+        // Safe because we know that our file is a VCPU fd, we know the kernel
+        // will only write correct amount of memory to our pointer, and we
+        // verify the return result.
+        let mut events: kvm_vcpu_events = unsafe { std::mem::zeroed() };
+        let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_VCPU_EVENTS(),
+                                              &mut events) };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(events)
+    }
+
+    /// Sets the vcpu's currently pending exceptions, interrupts, NMIs, etc
+    ///
+    /// See the documentation for KVM_SET_VCPU_EVENTS.
+    ///
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_vcpu_events(&self, events: &kvm_vcpu_events) -> Result<()> {
+        let ret = unsafe {
+            // The ioctl is safe because the kernel will only read from the
+            // kvm_vcpu_events.
+            ioctl_with_ref(self, KVM_SET_VCPU_EVENTS(), events)
+        };
+        if ret < 0 {
+            return errno_result();
+        }
+        Ok(())
+    }
+
     /// Specifies set of signals that are blocked during execution of KVM_RUN.
     /// Signals that are not blocked will will cause KVM_RUN to return
     /// with -EINTR.
diff --git a/plugin_proto/Cargo.toml b/plugin_proto/Cargo.toml
index f751a80..441cb2a 100644
--- a/plugin_proto/Cargo.toml
+++ b/plugin_proto/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "plugin_proto"
-version = "0.14.0"
+version = "0.15.0"
 authors = ["The Chromium OS Authors"]
 build = "build.rs"
 
diff --git a/plugin_proto/protos/plugin.proto b/plugin_proto/protos/plugin.proto
index 399e02a..699b478 100644
--- a/plugin_proto/protos/plugin.proto
+++ b/plugin_proto/protos/plugin.proto
@@ -277,6 +277,8 @@ message VcpuRequest {
         MP = 5;
         // struct kvm_xcrs
         XCREGS = 6;
+        // struct kvm_vcpu_events
+        EVENTS = 7;
     }
 
     message GetState {
@@ -285,7 +287,9 @@ message VcpuRequest {
 
     message SetState {
         StateSet set = 1;
-        // The in memory representation of a struct kvm_regs, struct kvm_sregs, or struct kvm_fpu,
+        // The in memory representation of a struct kvm_regs, struct kvm_sregs,
+        // struct kvm_fpu, struct kvm_debugregs, struct kvm_lapic_state,
+        // struct kvm_mp_state, struct kvm_xcrs or struct kvm_vcpu_events
         // depending on the value of the StateSet.
         bytes state = 2;
     }
@@ -355,9 +359,10 @@ message VcpuResponse  {
     message Resume {}
 
     message GetState {
-        // The in memory representation of a struct kvm_regs, struct kvm_sregs, struct kvm_fpu,
-        // struct kvm_lapic_state, or struct kvm_mp_state, depending on what StateSet was
-        // requested in GetState.
+        // The in memory representation of a struct kvm_regs, struct kvm_sregs,
+        // struct kvm_fpu, struct kvm_debugregs, struct kvm_lapic_state,
+        // struct kvm_mp_state, struct kvm_xcrs or struct kvm_vcpu_events
+        // depending on the value of the StateSet.
         bytes state = 1;
     }
 
diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs
index 4ea6482..5ff5366 100644
--- a/src/plugin/vcpu.rs
+++ b/src/plugin/vcpu.rs
@@ -18,7 +18,7 @@ use protobuf::Message;
 use data_model::DataInit;
 use kvm::{Vcpu, CpuId};
 use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_xcrs, kvm_msrs, kvm_msr_entry,
-              KVM_CPUID_FLAG_SIGNIFCANT_INDEX, kvm_lapic_state, kvm_mp_state};
+              KVM_CPUID_FLAG_SIGNIFCANT_INDEX, kvm_lapic_state, kvm_mp_state, kvm_vcpu_events};
 use plugin_proto::*;
 
 use super::*;
@@ -75,6 +75,9 @@ unsafe impl DataInit for VcpuLapicState {}
 #[derive(Copy, Clone)]
 struct VcpuMpState(kvm_mp_state);
 unsafe impl DataInit for VcpuMpState {}
+#[derive(Copy, Clone)]
+struct VcpuEvents(kvm_vcpu_events);
+unsafe impl DataInit for VcpuEvents {}
 
 fn get_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet) -> SysResult<Vec<u8>> {
     Ok(match state_set {
@@ -87,6 +90,7 @@ fn get_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet) -> SysResult<Vec
            VcpuRequest_StateSet::XCREGS => VcpuXcregs(vcpu.get_xcrs()?).as_slice().to_vec(),
            VcpuRequest_StateSet::LAPIC => VcpuLapicState(vcpu.get_lapic()?).as_slice().to_vec(),
            VcpuRequest_StateSet::MP => VcpuMpState(vcpu.get_mp_state()?).as_slice().to_vec(),
+           VcpuRequest_StateSet::EVENTS => VcpuEvents(vcpu.get_vcpu_events()?).as_slice().to_vec(),
        })
 }
 
@@ -127,6 +131,11 @@ fn set_vcpu_state(vcpu: &Vcpu, state_set: VcpuRequest_StateSet, state: &[u8]) ->
                                    .ok_or(SysError::new(EINVAL))?
                                    .0)
         }
+        VcpuRequest_StateSet::EVENTS => {
+            vcpu.set_vcpu_events(&VcpuEvents::from_slice(state)
+                                    .ok_or(SysError::new(EINVAL))?
+                                    .0)
+        }
     }
 }
 
diff --git a/tests/plugins.rs b/tests/plugins.rs
index b1d8e4d..c760875 100644
--- a/tests/plugins.rs
+++ b/tests/plugins.rs
@@ -644,6 +644,19 @@ fn test_vcpu_state_manipulation() {
                     return 1;
                 }
 
+                struct kvm_vcpu_events events;
+                ret = crosvm_vcpu_get_vcpu_events(vcpu, &events);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to get VCPU events: %d\n", ret);
+                    return 1;
+                }
+
+                ret = crosvm_vcpu_set_vcpu_events(vcpu, &events);
+                if (ret < 0) {
+                    fprintf(stderr, "failed to set VCPU events: %d\n", ret);
+                    return 1;
+                }
+
                 success = true;
                 return 0;
             }