summary refs log tree commit diff
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2018-02-06 20:50:07 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-02-12 22:42:38 -0800
commit7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63 (patch)
treeb0cd9cf9353234b3d0bc2529e445b52ce28a8768
parentce8961d1fcba5724553ba21288fbec752b0c00bf (diff)
downloadcrosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.tar
crosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.tar.gz
crosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.tar.bz2
crosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.tar.lz
crosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.tar.xz
crosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.tar.zst
crosvm-7ca9f771e7f406ff95b5b554bbefacbc8f8d6e63.zip
add plugin support for configuring CPUID
The guest expects to be able to read the CPUID, so the plugin process
needs to specify what the CPUID for each VCPU will have.

TEST=cargo test --features plugin; ./build_test
BUG=chromium:800626

Change-Id: I9258540ab2501126c3d8cadbd09b7fc01d19f7a9
Reviewed-on: https://chromium-review.googlesource.com/906006
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
-rw-r--r--Cargo.lock10
-rw-r--r--crosvm_plugin/Cargo.toml2
-rw-r--r--crosvm_plugin/crosvm.h6
-rw-r--r--crosvm_plugin/src/lib.rs36
-rw-r--r--kvm_sys/src/x86/bindings.rs3
-rw-r--r--plugin_proto/Cargo.toml2
-rw-r--r--plugin_proto/protos/plugin.proto18
-rw-r--r--src/plugin/vcpu.rs25
-rw-r--r--tests/plugins.rs125
9 files changed, 216 insertions, 11 deletions
diff --git a/Cargo.lock b/Cargo.lock
index c810954..b2bc83b 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.8.0",
+ "crosvm_plugin 0.9.0",
  "data_model 0.1.0",
  "devices 0.1.0",
  "io_jail 0.1.0",
@@ -28,7 +28,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.8.0",
+ "plugin_proto 0.9.0",
  "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "qcow 0.1.0",
  "qcow_utils 0.1.0",
@@ -41,12 +41,12 @@ dependencies = [
 
 [[package]]
 name = "crosvm_plugin"
-version = "0.8.0"
+version = "0.9.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.8.0",
+ "plugin_proto 0.9.0",
  "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "sys_util 0.1.0",
 ]
@@ -160,7 +160,7 @@ dependencies = [
 
 [[package]]
 name = "plugin_proto"
-version = "0.8.0"
+version = "0.9.0"
 dependencies = [
  "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
  "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/crosvm_plugin/Cargo.toml b/crosvm_plugin/Cargo.toml
index b650f3a..f6aeb24 100644
--- a/crosvm_plugin/Cargo.toml
+++ b/crosvm_plugin/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "crosvm_plugin"
-version = "0.8.0"
+version = "0.9.0"
 authors = ["The Chromium OS Authors"]
 
 [lib]
diff --git a/crosvm_plugin/crosvm.h b/crosvm_plugin/crosvm.h
index d6eafb6..1bdcec6 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 8
+#define CROSVM_API_MINOR 9
 #define CROSVM_API_PATCH 0
 
 enum crosvm_address_space {
@@ -430,6 +430,10 @@ int crosvm_vcpu_get_msrs(struct crosvm_vcpu*, uint32_t __msr_count,
 int crosvm_vcpu_set_msrs(struct crosvm_vcpu*, uint32_t __msr_count,
                          const struct kvm_msr_entry *__msr_entries);
 
+/* Sets the responses to the cpuid instructions executed on this vcpu, */
+int crosvm_vcpu_set_cpuid(struct crosvm_vcpu*, uint32_t __cpuid_count,
+                          const struct kvm_cpuid_entry2 *__cpuid_entries);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs
index e383a1b..102d129 100644
--- a/crosvm_plugin/src/lib.rs
+++ b/crosvm_plugin/src/lib.rs
@@ -43,7 +43,8 @@ use sys_util::Scm;
 
 use kvm::dirty_log_bitmap_size;
 
-use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_msr_entry};
+use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_msr_entry, kvm_cpuid_entry2,
+              KVM_CPUID_FLAG_SIGNIFCANT_INDEX};
 
 use plugin_proto::*;
 
@@ -736,6 +737,26 @@ impl crosvm_vcpu {
         self.vcpu_transaction(&r)?;
         Ok(())
     }
+
+    fn set_cpuid(&mut self, cpuid_entries: &[kvm_cpuid_entry2]) -> result::Result<(), c_int> {
+        let mut r = VcpuRequest::new();
+        {
+            let set_cpuid_entries: &mut RepeatedField<CpuidEntry> = r.mut_set_cpuid().mut_entries();
+            for cpuid_entry in cpuid_entries.iter() {
+                let mut entry = CpuidEntry::new();
+                entry.function = cpuid_entry.function;
+                entry.has_index = cpuid_entry.flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX != 0;
+                entry.index = cpuid_entry.index;
+                entry.eax = cpuid_entry.eax;
+                entry.ebx = cpuid_entry.ebx;
+                entry.ecx = cpuid_entry.ecx;
+                entry.edx = cpuid_entry.edx;
+                set_cpuid_entries.push(entry);
+            }
+        }
+        self.vcpu_transaction(&r)?;
+        Ok(())
+    }
 }
 
 #[no_mangle]
@@ -1005,3 +1026,16 @@ pub unsafe extern "C" fn crosvm_vcpu_set_msrs(this: *mut crosvm_vcpu,
         Err(e) => e,
     }
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn crosvm_vcpu_set_cpuid(this: *mut crosvm_vcpu,
+                                               cpuid_count: u32,
+                                               cpuid_entries: *const kvm_cpuid_entry2)
+                                               -> c_int {
+    let this = &mut *this;
+    let cpuid_entries = from_raw_parts(cpuid_entries, cpuid_count as usize);
+    match this.set_cpuid(cpuid_entries) {
+        Ok(_) => 0,
+        Err(e) => e,
+    }
+}
diff --git a/kvm_sys/src/x86/bindings.rs b/kvm_sys/src/x86/bindings.rs
index fa21578..a0b5985 100644
--- a/kvm_sys/src/x86/bindings.rs
+++ b/kvm_sys/src/x86/bindings.rs
@@ -164,6 +164,9 @@ pub const KVM_IRQCHIP_IOAPIC: ::std::os::raw::c_uint = 2;
 pub const KVM_NR_IRQCHIPS: ::std::os::raw::c_uint = 3;
 pub const KVM_RUN_X86_SMM: ::std::os::raw::c_uint = 1;
 pub const KVM_APIC_REG_SIZE: ::std::os::raw::c_uint = 1024;
+pub const KVM_CPUID_FLAG_SIGNIFCANT_INDEX: ::std::os::raw::c_uint = 1;
+pub const KVM_CPUID_FLAG_STATEFUL_FUNC: ::std::os::raw::c_uint = 2;
+pub const KVM_CPUID_FLAG_STATE_READ_NEXT: ::std::os::raw::c_uint = 4;
 pub const KVM_GUESTDBG_USE_SW_BP: ::std::os::raw::c_uint = 65536;
 pub const KVM_GUESTDBG_USE_HW_BP: ::std::os::raw::c_uint = 131072;
 pub const KVM_GUESTDBG_INJECT_DB: ::std::os::raw::c_uint = 262144;
diff --git a/plugin_proto/Cargo.toml b/plugin_proto/Cargo.toml
index d8f1509..0e5ead4 100644
--- a/plugin_proto/Cargo.toml
+++ b/plugin_proto/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "plugin_proto"
-version = "0.8.0"
+version = "0.9.0"
 authors = ["The Chromium OS Authors"]
 build = "build.rs"
 
diff --git a/plugin_proto/protos/plugin.proto b/plugin_proto/protos/plugin.proto
index 8bcdcc9..22f7be6 100644
--- a/plugin_proto/protos/plugin.proto
+++ b/plugin_proto/protos/plugin.proto
@@ -14,6 +14,16 @@ enum AddressSpace {
     MMIO = 1;
  }
 
+message CpuidEntry  {
+    uint32 function = 1;
+    bool has_index = 3;
+    uint32 index = 4;
+    uint32 eax = 5;
+    uint32 ebx = 6;
+    uint32 ecx = 7;
+    uint32 edx = 8;
+}
+
 // A request made to the crosvm main process that affects the global aspects of the VM.
 message MainRequest {
     // Every message under the Create namespace will instantiate an object with the given ID. The
@@ -224,6 +234,10 @@ message VcpuRequest {
         repeated MsrEntry entries = 1;
     }
 
+    message SetCpuid {
+        repeated CpuidEntry entries = 1;
+    }
+
     // The type of the message is determined by which of these oneof fields is present in the
     // protobuf.
     oneof message {
@@ -233,6 +247,7 @@ message VcpuRequest {
         SetState set_state = 4;
         GetMsrs get_msrs = 5;
         SetMsrs set_msrs = 6;
+        SetCpuid set_cpuid = 7;
     }
 }
 
@@ -285,6 +300,8 @@ message VcpuResponse  {
 
     message SetMsrs {}
 
+    message SetCpuid {}
+
     // This is zero on success, and a negative integer on failure.
     sint32 errno = 1;
     // The field present here is always the same as the one present in the corresponding
@@ -296,5 +313,6 @@ message VcpuResponse  {
         SetState set_state = 5;
         GetMsrs get_msrs = 6;
         SetMsrs set_msrs = 7;
+        SetCpuid set_cpuid = 8;
     }
 }
diff --git a/src/plugin/vcpu.rs b/src/plugin/vcpu.rs
index fcd6543..ea830bf 100644
--- a/src/plugin/vcpu.rs
+++ b/src/plugin/vcpu.rs
@@ -16,8 +16,9 @@ use protobuf;
 use protobuf::Message;
 
 use data_model::DataInit;
-use kvm::Vcpu;
-use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_msrs, kvm_msr_entry};
+use kvm::{Vcpu, CpuId};
+use kvm_sys::{kvm_regs, kvm_sregs, kvm_fpu, kvm_debugregs, kvm_msrs, kvm_msr_entry,
+              KVM_CPUID_FLAG_SIGNIFCANT_INDEX};
 use plugin_proto::*;
 
 use super::*;
@@ -448,6 +449,26 @@ impl PluginVcpu {
             }
             kvm_msrs.nmsrs = request_entries.len() as u32;
             vcpu.set_msrs(&kvm_msrs)
+        } else if request.has_set_cpuid() {
+            response.mut_set_cpuid();
+            let request_entries = &request.get_set_cpuid().entries;
+            let mut cpuid = CpuId::new(request_entries.len());
+            {
+                let cpuid_entries = cpuid.mut_entries_slice();
+                for (request_entry, cpuid_entry) in
+                    request_entries.iter().zip(cpuid_entries.iter_mut()) {
+                    cpuid_entry.function = request_entry.function;
+                    if request_entry.has_index {
+                        cpuid_entry.index = request_entry.index;
+                        cpuid_entry.flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                    }
+                    cpuid_entry.eax = request_entry.eax;
+                    cpuid_entry.ebx = request_entry.ebx;
+                    cpuid_entry.ecx = request_entry.ecx;
+                    cpuid_entry.edx = request_entry.edx;
+                }
+            }
+            vcpu.set_cpuid2(&cpuid)
         } else {
             Err(SysError::new(-ENOTTY))
         };
diff --git a/tests/plugins.rs b/tests/plugins.rs
index 357ad9a..54c4b7d 100644
--- a/tests/plugins.rs
+++ b/tests/plugins.rs
@@ -374,3 +374,128 @@ fn test_msrs() {
     };
     test_mini_plugin(&mini_plugin);
 }
+
+#[test]
+fn test_cpuid() {
+    let mini_plugin = MiniPlugin {
+        assembly_src: "org 0x1000
+             bits 16
+             push eax
+             push ecx
+             cpuid
+             mov [0x0], eax
+             mov [0x4], ebx
+             mov [0x8], ecx
+             mov [0xc], edx
+             pop ecx
+             pop eax
+             add ecx, 1
+             cpuid
+             mov [0x10], eax
+             mov [0x14], ebx
+             mov [0x18], ecx
+             mov [0x1c], edx
+             mov byte [es:0], 1",
+        src: r#"
+            #define ENTRY1_INDEX 0
+            #define ENTRY1_EAX 0x40414243
+            #define ENTRY1_EBX 0x50515253
+            #define ENTRY1_ECX 0x60616263
+            #define ENTRY1_EDX 0x71727374
+            #define ENTRY2_INDEX 1
+            #define ENTRY2_EAX 0xAABBCCDD
+            #define ENTRY2_EBX 0xEEFF0011
+            #define ENTRY2_ECX 0x22334455
+            #define ENTRY2_EDX 0x66778899
+            #define KILL_ADDRESS 0x3000
+
+            int g_kill_evt;
+            struct kvm_msr_entry g_msr2;
+
+            int setup_vm(struct crosvm *crosvm, void *mem) {
+                g_kill_evt = crosvm_get_shutdown_eventfd(crosvm);
+                crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_MMIO, KILL_ADDRESS, 1);
+                return 0;
+            }
+
+            int handle_vpcu_init(struct crosvm_vcpu *vcpu, struct kvm_regs *regs,
+                                 struct kvm_sregs *sregs)
+            {
+                regs->rax = ENTRY1_INDEX;
+                regs->rcx = 0;
+                regs->rsp = 0x1000;
+                sregs->es.base = KILL_ADDRESS;
+
+                struct kvm_cpuid_entry2 entries[2];
+                entries[0].function = 0;
+                entries[0].index = ENTRY1_INDEX;
+                entries[0].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                entries[0].eax = ENTRY1_EAX;
+                entries[0].ebx = ENTRY1_EBX;
+                entries[0].ecx = ENTRY1_ECX;
+                entries[0].edx = ENTRY1_EDX;
+                entries[1].function = 0;
+                entries[1].index = ENTRY2_INDEX;
+                entries[1].flags = KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
+                entries[1].eax = ENTRY2_EAX;
+                entries[1].ebx = ENTRY2_EBX;
+                entries[1].ecx = ENTRY2_ECX;
+                entries[1].edx = ENTRY2_EDX;
+                return crosvm_vcpu_set_cpuid(vcpu, 2, entries);
+            }
+
+            int handle_vpcu_evt(struct crosvm_vcpu *vcpu, struct crosvm_vcpu_event evt) {
+                if (evt.kind == CROSVM_VCPU_EVENT_KIND_IO_ACCESS &&
+                        evt.io_access.address_space == CROSVM_ADDRESS_SPACE_MMIO &&
+                        evt.io_access.address == KILL_ADDRESS &&
+                        evt.io_access.is_write &&
+                        evt.io_access.length == 1 &&
+                        evt.io_access.data[0] == 1)
+                {
+                    uint64_t dummy = 1;
+                    write(g_kill_evt, &dummy, sizeof(dummy));
+                    return 1;
+                }
+                return 0;
+            }
+
+            int check_result(struct crosvm *vcpu, void *memory) {
+                uint32_t *mem = (uint32_t*)memory;
+                if (mem[0] != ENTRY1_EAX) {
+                    fprintf(stderr, "entry 1 eax has unexpected value: 0x%x\n", mem[0]);
+                    return 1;
+                }
+                if (mem[1] != ENTRY1_EBX) {
+                    fprintf(stderr, "entry 1 ebx has unexpected value: 0x%x\n", mem[1]);
+                    return 1;
+                }
+                if (mem[2] != ENTRY1_ECX) {
+                    fprintf(stderr, "entry 1 ecx has unexpected value: 0x%x\n", mem[2]);
+                    return 1;
+                }
+                if (mem[3] != ENTRY1_EDX) {
+                    fprintf(stderr, "entry 1 edx has unexpected value: 0x%x\n", mem[3]);
+                    return 1;
+                }
+                if (mem[4] != ENTRY2_EAX) {
+                    fprintf(stderr, "entry 2 eax has unexpected value: 0x%x\n", mem[4]);
+                    return 1;
+                }
+                if (mem[5] != ENTRY2_EBX) {
+                    fprintf(stderr, "entry 2 ebx has unexpected value: 0x%x\n", mem[5]);
+                    return 1;
+                }
+                if (mem[6] != ENTRY2_ECX) {
+                    fprintf(stderr, "entry 2 ecx has unexpected value: 0x%x\n", mem[6]);
+                    return 1;
+                }
+                if (mem[7] != ENTRY2_EDX) {
+                    fprintf(stderr, "entry 2 edx has unexpected value: 0x%x\n", mem[7]);
+                    return 1;
+                }
+                return 0;
+            }"#,
+        ..Default::default()
+    };
+    test_mini_plugin(&mini_plugin);
+}