plugin: allow retrieving and setting VCPU events

Add crosvm plugin API to allow fetching and setting VCPU events.

BUG=b:110056268
TEST=cargo test --features plugin -p kvm

Change-Id: Id66230f180f4bdb95bd1850ed050e439083701cc
Reviewed-on: https://chromium-review.googlesource.com/1128045
Commit-Ready: Slava Malyugin <slavamn@chromium.org>
Tested-by: Slava Malyugin <slavamn@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
This commit is contained in:
Slava Malyugin 2018-07-06 09:52:05 -07:00 committed by chrome-bot
parent cc08cdbd83
commit d1e391b8d4
9 changed files with 110 additions and 14 deletions

10
Cargo.lock generated
View file

@ -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",

View file

@ -1,6 +1,6 @@
[package]
name = "crosvm_plugin"
version = "0.14.0"
version = "0.15.0"
authors = ["The Chromium OS Authors"]
[lib]

View file

@ -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

View file

@ -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)
}

View file

@ -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.

View file

@ -1,6 +1,6 @@
[package]
name = "plugin_proto"
version = "0.14.0"
version = "0.15.0"
authors = ["The Chromium OS Authors"]
build = "build.rs"

View file

@ -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;
}

View file

@ -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)
}
}
}

View file

@ -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;
}