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.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);
+}