@@ -630,6 +630,42 @@ currently being handled is replied to.
* -KVM_EAGAIN - the selected vCPU can't be introspected yet
* -KVM_EOPNOTSUPP - the command hasn't been received during an introspection event
+13. KVMI_VCPU_GET_CPUID
+-----------------------
+
+:Architectures: x86
+:Versions: >= 1
+:Parameters:
+
+::
+
+ struct kvmi_vcpu_hdr;
+ struct kvmi_vcpu_get_cpuid {
+ __u32 function;
+ __u32 index;
+ };
+
+:Returns:
+
+::
+
+ struct kvmi_error_code;
+ struct kvmi_vcpu_get_cpuid_reply {
+ __u32 eax;
+ __u32 ebx;
+ __u32 ecx;
+ __u32 edx;
+ };
+
+Returns a CPUID leaf (as seen by the guest OS).
+
+:Errors:
+
+* -KVM_EINVAL - the selected vCPU is invalid
+* -KVM_EINVAL - the padding is not zero
+* -KVM_EAGAIN - the selected vCPU can't be introspected yet
+* -KVM_ENOENT - the selected leaf is not present or is invalid
+
Events
======
@@ -45,4 +45,16 @@ struct kvmi_vcpu_get_registers_reply {
struct kvm_msrs msrs;
};
+struct kvmi_vcpu_get_cpuid {
+ __u32 function;
+ __u32 index;
+};
+
+struct kvmi_vcpu_get_cpuid_reply {
+ __u32 eax;
+ __u32 ebx;
+ __u32 ecx;
+ __u32 edx;
+};
+
#endif /* _UAPI_ASM_X86_KVMI_H */
@@ -6,6 +6,7 @@
*
*/
+#include "cpuid.h"
#include "../../../virt/kvm/introspection/kvmi_int.h"
#include "kvmi.h"
@@ -107,7 +108,32 @@ static int handle_vcpu_set_registers(const struct kvmi_vcpu_msg_job *job,
return kvmi_msg_vcpu_reply(job, msg, ec, NULL, 0);
}
+static int handle_vcpu_get_cpuid(const struct kvmi_vcpu_msg_job *job,
+ const struct kvmi_msg_hdr *msg,
+ const void *_req)
+{
+ const struct kvmi_vcpu_get_cpuid *req = _req;
+ struct kvmi_vcpu_get_cpuid_reply rpl;
+ struct kvm_cpuid_entry2 *entry;
+ int ec = 0;
+
+ entry = kvm_find_cpuid_entry(job->vcpu, req->function, req->index);
+ if (!entry) {
+ ec = -KVM_ENOENT;
+ } else {
+ memset(&rpl, 0, sizeof(rpl));
+
+ rpl.eax = entry->eax;
+ rpl.ebx = entry->ebx;
+ rpl.ecx = entry->ecx;
+ rpl.edx = entry->edx;
+ }
+
+ return kvmi_msg_vcpu_reply(job, msg, ec, &rpl, sizeof(rpl));
+}
+
static kvmi_vcpu_msg_job_fct const msg_vcpu[] = {
+ [KVMI_VCPU_GET_CPUID] = handle_vcpu_get_cpuid,
[KVMI_VCPU_GET_INFO] = handle_vcpu_get_info,
[KVMI_VCPU_GET_REGISTERS] = handle_vcpu_get_registers,
[KVMI_VCPU_SET_REGISTERS] = handle_vcpu_set_registers,
@@ -39,6 +39,7 @@ enum {
KVMI_VCPU_CONTROL_EVENTS = KVMI_VCPU_MESSAGE_ID(2),
KVMI_VCPU_GET_REGISTERS = KVMI_VCPU_MESSAGE_ID(3),
KVMI_VCPU_SET_REGISTERS = KVMI_VCPU_MESSAGE_ID(4),
+ KVMI_VCPU_GET_CPUID = KVMI_VCPU_MESSAGE_ID(5),
KVMI_NEXT_VCPU_MESSAGE
};
@@ -948,6 +948,35 @@ static void test_cmd_vcpu_set_registers(struct kvm_vm *vm)
wait_vcpu_worker(vcpu_thread);
}
+static void cmd_vcpu_get_cpuid(struct kvm_vm *vm,
+ __u32 function, __u32 index,
+ struct kvmi_vcpu_get_cpuid_reply *rpl)
+{
+ struct {
+ struct kvmi_msg_hdr hdr;
+ struct kvmi_vcpu_hdr vcpu_hdr;
+ struct kvmi_vcpu_get_cpuid cmd;
+ } req = {};
+
+ req.cmd.function = function;
+ req.cmd.index = index;
+
+ test_vcpu0_command(vm, KVMI_VCPU_GET_CPUID, &req.hdr, sizeof(req),
+ rpl, sizeof(*rpl), 0);
+}
+
+static void test_cmd_vcpu_get_cpuid(struct kvm_vm *vm)
+{
+ struct kvmi_vcpu_get_cpuid_reply rpl = {};
+ __u32 function = 0;
+ __u32 index = 0;
+
+ cmd_vcpu_get_cpuid(vm, function, index, &rpl);
+
+ pr_debug("cpuid(%u, %u) => eax 0x%.8x, ebx 0x%.8x, ecx 0x%.8x, edx 0x%.8x\n",
+ function, index, rpl.eax, rpl.ebx, rpl.ecx, rpl.edx);
+}
+
static void test_introspection(struct kvm_vm *vm)
{
srandom(time(0));
@@ -967,6 +996,7 @@ static void test_introspection(struct kvm_vm *vm)
test_cmd_vcpu_control_events(vm);
test_cmd_vcpu_get_registers(vm);
test_cmd_vcpu_set_registers(vm);
+ test_cmd_vcpu_get_cpuid(vm);
unhook_introspection(vm);
}