diff options
author | Dmitry Torokhov <dtor@chromium.org> | 2018-02-26 15:17:53 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-02-28 21:30:20 -0800 |
commit | 9786573e07992d43bfd5304ca7490a35aca2c61f (patch) | |
tree | f1082dcd1d1121ccdaf850251384825e1baab6f3 | |
parent | d1c761354f5d2583763704c8f9a8a7dd61d1dbb7 (diff) | |
download | crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.tar crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.tar.gz crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.tar.bz2 crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.tar.lz crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.tar.xz crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.tar.zst crosvm-9786573e07992d43bfd5304ca7490a35aca2c61f.zip |
allow plugin to query KVM for supported/emulated CPUIDs
This plumbs calls to KVM_GET_SUPPORTED_CPUID and KVM_GET_EMULATED_CPUID to be available to plugins. TEST=cargo test --features plugin; cargo test -p kvm BUG=chromium:800626 Change-Id: I98879599b5f970c6c2720772658689a505d8abe1 Signed-off-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/938674 Reviewed-by: Zach Reizner <zachr@chromium.org>
-rw-r--r-- | Cargo.lock | 10 | ||||
-rw-r--r-- | crosvm_plugin/Cargo.toml | 2 | ||||
-rw-r--r-- | crosvm_plugin/crosvm.h | 17 | ||||
-rw-r--r-- | crosvm_plugin/src/lib.rs | 86 | ||||
-rw-r--r-- | plugin_proto/Cargo.toml | 2 | ||||
-rw-r--r-- | plugin_proto/protos/plugin.proto | 38 | ||||
-rw-r--r-- | src/plugin/mod.rs | 4 | ||||
-rw-r--r-- | src/plugin/process.rs | 30 | ||||
-rw-r--r-- | tests/plugin_supported_cpuid.c | 67 | ||||
-rw-r--r-- | tests/plugins.rs | 5 |
10 files changed, 233 insertions, 28 deletions
diff --git a/Cargo.lock b/Cargo.lock index fa6f505..fda25e9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -18,7 +18,7 @@ name = "crosvm" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crosvm_plugin 0.10.0", + "crosvm_plugin 0.11.0", "data_model 0.1.0", "device_manager 0.1.0", "devices 0.1.0", @@ -29,7 +29,7 @@ dependencies = [ "kvm_sys 0.1.0", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "net_util 0.1.0", - "plugin_proto 0.10.0", + "plugin_proto 0.11.0", "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "qcow 0.1.0", "qcow_utils 0.1.0", @@ -42,12 +42,12 @@ dependencies = [ [[package]] name = "crosvm_plugin" -version = "0.10.0" +version = "0.11.0" dependencies = [ "kvm 0.1.0", "kvm_sys 0.1.0", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin_proto 0.10.0", + "plugin_proto 0.11.0", "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "sys_util 0.1.0", ] @@ -173,7 +173,7 @@ dependencies = [ [[package]] name = "plugin_proto" -version = "0.10.0" +version = "0.11.0" dependencies = [ "gcc 0.3.54 (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 4020f3a..d34753a 100644 --- a/crosvm_plugin/Cargo.toml +++ b/crosvm_plugin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "crosvm_plugin" -version = "0.10.0" +version = "0.11.0" authors = ["The Chromium OS Authors"] [lib] diff --git a/crosvm_plugin/crosvm.h b/crosvm_plugin/crosvm.h index 454ba34..0dc2a60 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 10 +#define CROSVM_API_MINOR 11 #define CROSVM_API_PATCH 0 enum crosvm_address_space { @@ -115,6 +115,21 @@ int crosvm_check_extension(struct crosvm*, uint32_t __extension, bool *__has_extension); /* + * Queries x86 cpuid features which are supported by the hardware and + * kvm. + */ +int crosvm_get_supported_cpuid(struct crosvm*, uint32_t __entry_count, + struct kvm_cpuid_entry2 *__cpuid_entries, + uint32_t *__out_count); + +/* + * Queries x86 cpuid features which are emulated by kvm. + */ +int crosvm_get_emulated_cpuid(struct crosvm*, uint32_t __entry_count, + struct kvm_cpuid_entry2 *__cpuid_entries, + uint32_t *__out_count); + +/* * Registers a range in the given address space that, when accessed, will block * and wait for a crosvm_vcpu_resume call. * diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs index 250692a..a794d40 100644 --- a/crosvm_plugin/src/lib.rs +++ b/crosvm_plugin/src/lib.rs @@ -35,7 +35,7 @@ use std::slice; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; -use libc::{ENOTCONN, EINVAL, EPROTO, ENOENT}; +use libc::{E2BIG, ENOTCONN, EINVAL, EPROTO, ENOENT}; use protobuf::{Message, ProtobufEnum, RepeatedField, parse_from_bytes}; @@ -242,6 +242,54 @@ impl crosvm { Ok(response.get_check_extension().has_extension) } + fn get_supported_cpuid(&mut self, cpuid_entries: &mut [kvm_cpuid_entry2]) + -> result::Result<usize, c_int> { + let mut r = MainRequest::new(); + r.mut_get_supported_cpuid(); + + let (response, _) = self.main_transaction(&r, &[])?; + if !response.has_get_supported_cpuid() { + return Err(-EPROTO); + } + + let supported_cpuids: &MainResponse_CpuidResponse = response.get_get_supported_cpuid(); + if supported_cpuids.get_entries().len() > cpuid_entries.len() { + return Err(-E2BIG); + } + + for (proto_entry, kvm_entry) in + supported_cpuids.get_entries().iter() + .zip(cpuid_entries.iter_mut()) { + *kvm_entry = cpuid_proto_to_kvm(proto_entry); + } + + Ok(supported_cpuids.get_entries().len()) + } + + fn get_emulated_cpuid(&mut self, cpuid_entries: &mut [kvm_cpuid_entry2]) + -> result::Result<usize, c_int> { + let mut r = MainRequest::new(); + r.mut_get_emulated_cpuid(); + + let (response, _) = self.main_transaction(&r, &[])?; + if !response.has_get_emulated_cpuid() { + return Err(-EPROTO); + } + + let emulated_cpuids: &MainResponse_CpuidResponse = response.get_get_emulated_cpuid(); + if emulated_cpuids.get_entries().len() > cpuid_entries.len() { + return Err(-E2BIG); + } + + for (proto_entry, kvm_entry) in + emulated_cpuids.get_entries().iter() + .zip(cpuid_entries.iter_mut()) { + *kvm_entry = cpuid_proto_to_kvm(proto_entry); + } + + Ok(emulated_cpuids.get_entries().len()) + } + fn reserve_range(&mut self, space: u32, start: u64, length: u64) -> result::Result<(), c_int> { let mut r = MainRequest::new(); { @@ -826,6 +874,42 @@ pub unsafe extern "C" fn crosvm_check_extension(self_: *mut crosvm, } #[no_mangle] +pub unsafe extern "C" +fn crosvm_get_supported_cpuid(this: *mut crosvm, + entry_count: u32, + cpuid_entries: *mut kvm_cpuid_entry2, + out_count: *mut u32) + -> c_int { + let this = &mut *this; + let cpuid_entries = from_raw_parts_mut(cpuid_entries, entry_count as usize); + match this.get_supported_cpuid(cpuid_entries) { + Ok(num) => { + *out_count = num as u32; + 0 + }, + Err(e) => e, + } +} + +#[no_mangle] +pub unsafe extern "C" +fn crosvm_get_emulated_cpuid(this: *mut crosvm, + entry_count: u32, + cpuid_entries: *mut kvm_cpuid_entry2, + out_count: *mut u32) + -> c_int { + let this = &mut *this; + let cpuid_entries = from_raw_parts_mut(cpuid_entries, entry_count as usize); + match this.get_emulated_cpuid(cpuid_entries) { + Ok(num) => { + *out_count = num as u32; + 0 + }, + Err(e) => e, + } +} + +#[no_mangle] pub unsafe extern "C" fn crosvm_reserve_range(self_: *mut crosvm, space: u32, start: u64, diff --git a/plugin_proto/Cargo.toml b/plugin_proto/Cargo.toml index bb43452..9ddf1a4 100644 --- a/plugin_proto/Cargo.toml +++ b/plugin_proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "plugin_proto" -version = "0.10.0" +version = "0.11.0" authors = ["The Chromium OS Authors"] build = "build.rs" diff --git a/plugin_proto/protos/plugin.proto b/plugin_proto/protos/plugin.proto index 194b315..0e6f883 100644 --- a/plugin_proto/protos/plugin.proto +++ b/plugin_proto/protos/plugin.proto @@ -72,6 +72,9 @@ message MainRequest { uint32 extension = 1; } + message CpuidRequest { + } + message ReserveRange { AddressSpace space = 1; uint64 start = 2; @@ -131,13 +134,15 @@ message MainRequest { NewConnection new_connection = 3; GetShutdownEventfd get_shutdown_eventfd = 4; CheckExtension check_extension = 5; - ReserveRange reserve_range = 6; - SetIrq set_irq = 7; - SetIrqRouting set_irq_routing = 8; - SetIdentityMapAddr set_identity_map_addr = 9; - PauseVcpus pause_vcpus = 10; - GetVcpus get_vcpus = 11; - Start start = 12; + CpuidRequest get_supported_cpuid = 6; + CpuidRequest get_emulated_cpuid = 7; + ReserveRange reserve_range = 8; + SetIrq set_irq = 9; + SetIrqRouting set_irq_routing = 10; + SetIdentityMapAddr set_identity_map_addr = 11; + PauseVcpus pause_vcpus = 12; + GetVcpus get_vcpus = 13; + Start start = 14; // Method for a Memory type object for retrieving the dirty bitmap. Only valid if the memory // object was created with dirty_log set. MemoryDirtyLog dirty_log = 101; @@ -156,6 +161,9 @@ message MainResponse { message CheckExtension { bool has_extension = 1; } + message CpuidResponse { + repeated CpuidEntry entries = 1; + } message ReserveRange {} message SetIrq {} message SetIrqRouting {} @@ -179,13 +187,15 @@ message MainResponse { NewConnection new_connection = 4; GetShutdownEventfd get_shutdown_eventfd = 5; CheckExtension check_extension = 6; - ReserveRange reserve_range = 7; - SetIrq set_irq = 8; - SetIrqRouting set_irq_routing = 9; - SetIdentityMapAddr set_identity_map_addr = 10; - PauseVcpus pause_vcpus = 11; - GetVcpus get_vcpus = 12; - Start start = 13; + CpuidResponse get_supported_cpuid = 7; + CpuidResponse get_emulated_cpuid = 8; + ReserveRange reserve_range = 9; + SetIrq set_irq = 10; + SetIrqRouting set_irq_routing = 11; + SetIdentityMapAddr set_identity_map_addr = 12; + PauseVcpus pause_vcpus = 13; + GetVcpus get_vcpus = 14; + Start start = 15; MemoryDirtyLog dirty_log = 101; } } diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index 44cba39..4d164a4 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -405,7 +405,7 @@ pub fn run_config(cfg: Config) -> Result<()> { let kvm = Kvm::new().map_err(Error::CreateKvm)?; let mut vm = Vm::new(&kvm, mem).map_err(Error::CreateVm)?; vm.create_irq_chip().map_err(Error::CreateIrqChip)?; - let mut plugin = Process::new(vcpu_count, &mut vm, plugin_path, &plugin_args, jail)?; + let mut plugin = Process::new(vcpu_count, &kvm, &mut vm, plugin_path, &plugin_args, jail)?; let mut res = Ok(()); // If Some, we will exit after enough time is passed to shutdown cleanly. @@ -530,7 +530,7 @@ pub fn run_config(cfg: Config) -> Result<()> { } t if t >= PLUGIN_BASE && t < PLUGIN_BASE + (plugin.sockets().len() as u32) => { let socket_index = (t - PLUGIN_BASE) as usize; - match plugin.handle_socket(socket_index, &mut vm, &vcpu_handles) { + match plugin.handle_socket(socket_index, &kvm, &mut vm, &vcpu_handles) { Ok(_) => {} // A HUP is an expected event for a socket, so don't bother warning about // it. diff --git a/src/plugin/process.rs b/src/plugin/process.rs index aa4a907..89c201c 100644 --- a/src/plugin/process.rs +++ b/src/plugin/process.rs @@ -73,6 +73,7 @@ impl Process { /// Due to an API limitation in libminijail necessitating that this function set an environment /// variable, this function is not thread-safe. pub fn new(cpu_count: u32, + kvm: &Kvm, vm: &mut Vm, cmd: &Path, args: &[&str], @@ -125,13 +126,13 @@ impl Process { response_buffer: Vec::new(), }; - plugin.run_until_started(vm)?; + plugin.run_until_started(kvm, vm)?; Ok(plugin) } - fn run_until_started(&mut self, vm: &mut Vm) -> Result<()> { + fn run_until_started(&mut self, kvm: &Kvm, vm: &mut Vm) -> Result<()> { let mut sockets_to_drop = Vec::new(); let mut poller = Poller::new(1); while !self.started { @@ -150,7 +151,7 @@ impl Process { }; for &token in tokens { - match self.handle_socket(token as usize, vm, &[]) { + match self.handle_socket(token as usize, kvm, vm, &[]) { Ok(_) => {} Err(Error::PluginSocketHup) => sockets_to_drop.push(token as usize), r => return r, @@ -388,6 +389,7 @@ impl Process { /// interrupt a VCPU thread currently running in the VM if the socket request it. pub fn handle_socket(&mut self, index: usize, + kvm: &Kvm, vm: &mut Vm, vcpu_handles: &[JoinHandle<()>]) -> Result<()> { @@ -533,6 +535,28 @@ impl Process { } _ => Err(SysError::new(-ENOENT)), } + } else if request.has_get_supported_cpuid() { + let cpuid_response = &mut response.mut_get_supported_cpuid().entries; + match kvm.get_supported_cpuid() { + Ok(mut cpuid) => { + for entry in cpuid.mut_entries_slice() { + cpuid_response.push(cpuid_kvm_to_proto(entry)); + } + Ok(()) + } + Err(e) => Err(e) + } + } else if request.has_get_emulated_cpuid() { + let cpuid_response = &mut response.mut_get_emulated_cpuid().entries; + match kvm.get_emulated_cpuid() { + Ok(mut cpuid) => { + for entry in cpuid.mut_entries_slice() { + cpuid_response.push(cpuid_kvm_to_proto(entry)); + } + Ok(()) + } + Err(e) => Err(e) + } } else { Err(SysError::new(-ENOTTY)) }; diff --git a/tests/plugin_supported_cpuid.c b/tests/plugin_supported_cpuid.c new file mode 100644 index 0000000..0acb134 --- /dev/null +++ b/tests/plugin_supported_cpuid.c @@ -0,0 +1,67 @@ +/* + * Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "crosvm.h" + +int main(int argc, char** argv) { + struct crosvm *crosvm; + int ret = crosvm_connect(&crosvm); + if (ret) { + fprintf(stderr, "failed to connect to crosvm: %d\n", ret); + return 1; + } + + struct kvm_cpuid_entry2 cpuids[100]; + int n_entries; + ret = crosvm_get_supported_cpuid(crosvm, 1, cpuids, &n_entries); + if (ret >= 0) { + fprintf(stderr, + "expected crosvm_get_supported_cpuids to fail with E2BIG\n"); + return 1; + } + + ret = crosvm_get_supported_cpuid(crosvm, 100, cpuids, &n_entries); + if (ret < 0) { + fprintf(stderr, + "unexpected failure of crosvm_get_supported_cpuids: %d\n", ret); + return 1; + } + + if (n_entries <= 1) { + fprintf(stderr, + "unexpected number of supported cpuid entries: %d\n", + n_entries); + return 1; + } + + ret = crosvm_get_emulated_cpuid(crosvm, 1, cpuids, &n_entries); + if (ret >= 0) { + fprintf(stderr, + "expected crosvm_get_emulated_cpuids to fail with E2BIG\n"); + return 1; + } + + ret = crosvm_get_emulated_cpuid(crosvm, 100, cpuids, &n_entries); + if (ret < 0) { + fprintf(stderr, + "unexpected failure of crosvm_get_emulated_cpuid: %d\n", ret); + return 1; + } + + if (n_entries < 1) { + fprintf(stderr, + "unexpected number of emulated cpuid entries: %d\n", n_entries); + return 1; + } + + return 0; +} diff --git a/tests/plugins.rs b/tests/plugins.rs index 1a99a43..d036e97 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -231,6 +231,11 @@ fn test_extensions() { } #[test] +fn test_supported_cpuid() { + test_plugin(include_str!("plugin_supported_cpuid.c")); +} + +#[test] fn test_vcpu_pause() { test_plugin(include_str!("plugin_vcpu_pause.c")); } |