diff options
-rw-r--r-- | Cargo.lock | 10 | ||||
-rw-r--r-- | crosvm_plugin/Cargo.toml | 2 | ||||
-rw-r--r-- | crosvm_plugin/crosvm.h | 6 | ||||
-rw-r--r-- | crosvm_plugin/src/lib.rs | 36 | ||||
-rw-r--r-- | kvm_sys/src/x86/bindings.rs | 3 | ||||
-rw-r--r-- | plugin_proto/Cargo.toml | 2 | ||||
-rw-r--r-- | plugin_proto/protos/plugin.proto | 18 | ||||
-rw-r--r-- | src/plugin/vcpu.rs | 25 | ||||
-rw-r--r-- | tests/plugins.rs | 125 |
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); +} |