* [PATCH] selftest: kvm: x86: test KVM_GET_CPUID2 and guest visible CPUIDs against KVM_GET_SUPPORTED_CPUID
@ 2021-01-29 16:18 Vitaly Kuznetsov
2021-02-02 17:28 ` Paolo Bonzini
0 siblings, 1 reply; 2+ messages in thread
From: Vitaly Kuznetsov @ 2021-01-29 16:18 UTC (permalink / raw)
To: kvm, Paolo Bonzini
Cc: Sean Christopherson, Wanpeng Li, Jim Mattson, Michael Roth
Commit 181f494888d5 ("KVM: x86: fix CPUID entries returned by
KVM_GET_CPUID2 ioctl") revealed that we're not testing KVM_GET_CPUID2
ioctl at all. Add a test for it and also check that from inside the guest
visible CPUIDs are equal to it's output.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
---
tools/testing/selftests/kvm/.gitignore | 5 +
tools/testing/selftests/kvm/Makefile | 1 +
.../selftests/kvm/include/x86_64/processor.h | 14 ++
.../selftests/kvm/lib/x86_64/processor.c | 42 +++++
.../selftests/kvm/x86_64/get_cpuid_test.c | 175 ++++++++++++++++++
5 files changed, 237 insertions(+)
create mode 100644 tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index ce8f4ad39684..3194df487404 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -7,6 +7,7 @@
/x86_64/cr4_cpuid_sync_test
/x86_64/debug_regs
/x86_64/evmcs_test
+/x86_64/get_cpuid_test
/x86_64/kvm_pv_test
/x86_64/hyperv_cpuid
/x86_64/mmio_warning_test
@@ -17,6 +18,7 @@
/x86_64/svm_vmcall_test
/x86_64/sync_regs_test
/x86_64/tsc_msrs_test
+/x86_64/user_msr_test
/x86_64/userspace_msr_exit_test
/x86_64/vmx_apic_access_test
/x86_64/vmx_close_while_nested_test
@@ -24,8 +26,11 @@
/x86_64/vmx_preemption_timer_test
/x86_64/vmx_set_nested_state_test
/x86_64/vmx_tsc_adjust_test
+/x86_64/xen_shinfo_test
+/x86_64/xen_vmcall_test
/x86_64/xss_msr_test
/demand_paging_test
+/clear_dirty_log_test
/dirty_log_test
/dirty_log_perf_test
/kvm_create_max_vcpus
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index fe41c6a0fa67..b4743fd0d37b 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -40,6 +40,7 @@ LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_ha
TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
+TEST_GEN_PROGS_x86_64 += x86_64/get_cpuid_test
TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
index 90cd5984751b..c8ab021a3b6e 100644
--- a/tools/testing/selftests/kvm/include/x86_64/processor.h
+++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
@@ -263,6 +263,19 @@ static inline void outl(uint16_t port, uint32_t value)
__asm__ __volatile__("outl %%eax, %%dx" : : "d"(port), "a"(value));
}
+static inline void cpuid(uint32_t *eax, uint32_t *ebx,
+ uint32_t *ecx, uint32_t *edx)
+{
+ /* ecx is often an input as well as an output. */
+ asm volatile("cpuid"
+ : "=a" (*eax),
+ "=b" (*ebx),
+ "=c" (*ecx),
+ "=d" (*edx)
+ : "0" (*eax), "2" (*ecx)
+ : "memory");
+}
+
#define SET_XMM(__var, __xmm) \
asm volatile("movq %0, %%"#__xmm : : "r"(__var) : #__xmm)
@@ -340,6 +353,7 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid,
struct kvm_msr_list *kvm_get_msr_index_list(void);
struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
+struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid,
struct kvm_cpuid2 *cpuid);
diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c
index 95e1a757c629..7a4dea86fad0 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/processor.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c
@@ -669,6 +669,48 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void)
return cpuid;
}
+/*
+ * VM VCPU CPUID Set
+ *
+ * Input Args:
+ * vm - Virtual Machine
+ * vcpuid - VCPU id
+ *
+ * Output Args: None
+ *
+ * Return: KVM CPUID (KVM_GET_CPUID2)
+ *
+ * Set the VCPU's CPUID.
+ */
+struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid)
+{
+ struct vcpu *vcpu = vcpu_find(vm, vcpuid);
+ struct kvm_cpuid2 *cpuid;
+ int rc, max_ent;
+
+ TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
+
+ cpuid = allocate_kvm_cpuid2();
+ max_ent = cpuid->nent;
+
+ for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) {
+ rc = ioctl(vcpu->fd, KVM_GET_CPUID2, cpuid);
+ if (!rc)
+ break;
+
+ TEST_ASSERT(rc == -1 && errno == E2BIG,
+ "KVM_GET_CPUID2 should either succeed or give E2BIG: %d %d",
+ rc, errno);
+ }
+
+ TEST_ASSERT(rc == 0, "KVM_GET_CPUID2 failed, rc: %i errno: %i",
+ rc, errno);
+
+ return cpuid;
+}
+
+
+
/*
* Locate a cpuid entry.
*
diff --git a/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
new file mode 100644
index 000000000000..9b78e8889638
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
@@ -0,0 +1,175 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2021, Red Hat Inc.
+ *
+ * Generic tests for KVM CPUID set/get ioctls
+ */
+#include <asm/kvm_para.h>
+#include <linux/kvm_para.h>
+#include <stdint.h>
+
+#include "test_util.h"
+#include "kvm_util.h"
+#include "processor.h"
+
+#define VCPU_ID 0
+
+/* CPUIDs known to differ */
+struct {
+ u32 function;
+ u32 index;
+} mangled_cpuids[] = {
+ {.function = 0xd, .index = 0},
+};
+
+static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid)
+{
+ int i;
+ u32 eax, ebx, ecx, edx;
+
+ for (i = 0; i < guest_cpuid->nent; i++) {
+ eax = guest_cpuid->entries[i].function;
+ ecx = guest_cpuid->entries[i].index;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ GUEST_ASSERT(eax == guest_cpuid->entries[i].eax &&
+ ebx == guest_cpuid->entries[i].ebx &&
+ ecx == guest_cpuid->entries[i].ecx &&
+ edx == guest_cpuid->entries[i].edx);
+ }
+
+}
+
+static void test_cpuid_40000000(struct kvm_cpuid2 *guest_cpuid)
+{
+ u32 eax = 0x40000000, ebx, ecx = 0, edx;
+
+ cpuid(&eax, &ebx, &ecx, &edx);
+
+ GUEST_ASSERT(eax == 0x40000001);
+}
+
+static void guest_main(struct kvm_cpuid2 *guest_cpuid)
+{
+ GUEST_SYNC(1);
+
+ test_guest_cpuids(guest_cpuid);
+
+ GUEST_SYNC(2);
+
+ test_cpuid_40000000(guest_cpuid);
+
+ GUEST_DONE();
+}
+
+static bool is_cpuid_mangled(struct kvm_cpuid_entry2 *entrie)
+{
+ int i;
+
+ for (i = 0; i < sizeof(mangled_cpuids); i++) {
+ if (mangled_cpuids[i].function == entrie->function &&
+ mangled_cpuids[i].index == entrie->index)
+ return true;
+ }
+
+ return false;
+}
+
+static void check_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *entrie)
+{
+ int i;
+
+ for (i = 0; i < cpuid->nent; i++) {
+ if (cpuid->entries[i].function == entrie->function &&
+ cpuid->entries[i].index == entrie->index) {
+ if (is_cpuid_mangled(entrie))
+ return;
+
+ TEST_ASSERT(cpuid->entries[i].eax == entrie->eax &&
+ cpuid->entries[i].ebx == entrie->ebx &&
+ cpuid->entries[i].ecx == entrie->ecx &&
+ cpuid->entries[i].edx == entrie->edx,
+ "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x",
+ entrie->function, entrie->index,
+ cpuid->entries[i].eax, cpuid->entries[i].ebx,
+ cpuid->entries[i].ecx, cpuid->entries[i].edx,
+ entrie->eax, entrie->ebx, entrie->ecx, entrie->edx);
+ return;
+ }
+ }
+
+ TEST_ASSERT(false, "CPUID 0x%x.%x not found", entrie->function, entrie->index);
+}
+
+static void compare_cpuids(struct kvm_cpuid2 *cpuid1, struct kvm_cpuid2 *cpuid2)
+{
+ int i;
+
+ for (i = 0; i < cpuid1->nent; i++)
+ check_cpuid(cpuid2, &cpuid1->entries[i]);
+
+ for (i = 0; i < cpuid2->nent; i++)
+ check_cpuid(cpuid1, &cpuid2->entries[i]);
+}
+
+static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage)
+{
+ struct ucall uc;
+
+ _vcpu_run(vm, vcpuid);
+
+ switch (get_ucall(vm, vcpuid, &uc)) {
+ case UCALL_SYNC:
+ TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
+ uc.args[1] == stage + 1,
+ "Stage %d: Unexpected register values vmexit, got %lx",
+ stage + 1, (ulong)uc.args[1]);
+ return;
+ case UCALL_DONE:
+ return;
+ case UCALL_ABORT:
+ TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx", (const char *)uc.args[0],
+ __FILE__, uc.args[1], uc.args[2], uc.args[3]);
+ default:
+ TEST_ASSERT(false, "Unexpected exit: %s",
+ exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason));
+ }
+}
+
+struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid)
+{
+ int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]);
+ vm_vaddr_t gva = vm_vaddr_alloc(vm, size,
+ getpagesize(), 0, 0);
+ struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva);
+
+ memcpy(guest_cpuids, cpuid, size);
+
+ *p_gva = gva;
+ return guest_cpuids;
+}
+
+int main(void)
+{
+ struct kvm_cpuid2 *supp_cpuid, *cpuid2;
+ vm_vaddr_t cpuid_gva;
+ struct kvm_vm *vm;
+ int stage;
+
+ vm = vm_create_default(VCPU_ID, 0, guest_main);
+
+ supp_cpuid = kvm_get_supported_cpuid();
+ cpuid2 = vcpu_get_cpuid(vm, VCPU_ID);
+
+ compare_cpuids(supp_cpuid, cpuid2);
+
+ vcpu_alloc_cpuid(vm, &cpuid_gva, cpuid2);
+
+ vcpu_args_set(vm, VCPU_ID, 1, cpuid_gva);
+
+ for (stage = 0; stage < 3; stage++)
+ run_vcpu(vm, VCPU_ID, stage);
+
+ kvm_vm_free(vm);
+}
--
2.29.2
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] selftest: kvm: x86: test KVM_GET_CPUID2 and guest visible CPUIDs against KVM_GET_SUPPORTED_CPUID
2021-01-29 16:18 [PATCH] selftest: kvm: x86: test KVM_GET_CPUID2 and guest visible CPUIDs against KVM_GET_SUPPORTED_CPUID Vitaly Kuznetsov
@ 2021-02-02 17:28 ` Paolo Bonzini
0 siblings, 0 replies; 2+ messages in thread
From: Paolo Bonzini @ 2021-02-02 17:28 UTC (permalink / raw)
To: Vitaly Kuznetsov, kvm
Cc: Sean Christopherson, Wanpeng Li, Jim Mattson, Michael Roth
On 29/01/21 17:18, Vitaly Kuznetsov wrote:
> Commit 181f494888d5 ("KVM: x86: fix CPUID entries returned by
> KVM_GET_CPUID2 ioctl") revealed that we're not testing KVM_GET_CPUID2
> ioctl at all. Add a test for it and also check that from inside the guest
> visible CPUIDs are equal to it's output.
>
> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> ---
> tools/testing/selftests/kvm/.gitignore | 5 +
> tools/testing/selftests/kvm/Makefile | 1 +
> .../selftests/kvm/include/x86_64/processor.h | 14 ++
> .../selftests/kvm/lib/x86_64/processor.c | 42 +++++
> .../selftests/kvm/x86_64/get_cpuid_test.c | 175 ++++++++++++++++++
> 5 files changed, 237 insertions(+)
> create mode 100644 tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
>
> diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
> index ce8f4ad39684..3194df487404 100644
> --- a/tools/testing/selftests/kvm/.gitignore
> +++ b/tools/testing/selftests/kvm/.gitignore
> @@ -7,6 +7,7 @@
> /x86_64/cr4_cpuid_sync_test
> /x86_64/debug_regs
> /x86_64/evmcs_test
> +/x86_64/get_cpuid_test
> /x86_64/kvm_pv_test
> /x86_64/hyperv_cpuid
> /x86_64/mmio_warning_test
> @@ -17,6 +18,7 @@
> /x86_64/svm_vmcall_test
> /x86_64/sync_regs_test
> /x86_64/tsc_msrs_test
> +/x86_64/user_msr_test
> /x86_64/userspace_msr_exit_test
> /x86_64/vmx_apic_access_test
> /x86_64/vmx_close_while_nested_test
> @@ -24,8 +26,11 @@
> /x86_64/vmx_preemption_timer_test
> /x86_64/vmx_set_nested_state_test
> /x86_64/vmx_tsc_adjust_test
> +/x86_64/xen_shinfo_test
> +/x86_64/xen_vmcall_test
> /x86_64/xss_msr_test
> /demand_paging_test
> +/clear_dirty_log_test
> /dirty_log_test
> /dirty_log_perf_test
> /kvm_create_max_vcpus
> diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
> index fe41c6a0fa67..b4743fd0d37b 100644
> --- a/tools/testing/selftests/kvm/Makefile
> +++ b/tools/testing/selftests/kvm/Makefile
> @@ -40,6 +40,7 @@ LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_ha
>
> TEST_GEN_PROGS_x86_64 = x86_64/cr4_cpuid_sync_test
> TEST_GEN_PROGS_x86_64 += x86_64/evmcs_test
> +TEST_GEN_PROGS_x86_64 += x86_64/get_cpuid_test
> TEST_GEN_PROGS_x86_64 += x86_64/hyperv_cpuid
> TEST_GEN_PROGS_x86_64 += x86_64/kvm_pv_test
> TEST_GEN_PROGS_x86_64 += x86_64/mmio_warning_test
> diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
> index 90cd5984751b..c8ab021a3b6e 100644
> --- a/tools/testing/selftests/kvm/include/x86_64/processor.h
> +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
> @@ -263,6 +263,19 @@ static inline void outl(uint16_t port, uint32_t value)
> __asm__ __volatile__("outl %%eax, %%dx" : : "d"(port), "a"(value));
> }
>
> +static inline void cpuid(uint32_t *eax, uint32_t *ebx,
> + uint32_t *ecx, uint32_t *edx)
> +{
> + /* ecx is often an input as well as an output. */
> + asm volatile("cpuid"
> + : "=a" (*eax),
> + "=b" (*ebx),
> + "=c" (*ecx),
> + "=d" (*edx)
> + : "0" (*eax), "2" (*ecx)
> + : "memory");
> +}
> +
> #define SET_XMM(__var, __xmm) \
> asm volatile("movq %0, %%"#__xmm : : "r"(__var) : #__xmm)
>
> @@ -340,6 +353,7 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid,
> struct kvm_msr_list *kvm_get_msr_index_list(void);
>
> struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
> +struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid);
> void vcpu_set_cpuid(struct kvm_vm *vm, uint32_t vcpuid,
> struct kvm_cpuid2 *cpuid);
>
> diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/testing/selftests/kvm/lib/x86_64/processor.c
> index 95e1a757c629..7a4dea86fad0 100644
> --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c
> +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c
> @@ -669,6 +669,48 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void)
> return cpuid;
> }
>
> +/*
> + * VM VCPU CPUID Set
> + *
> + * Input Args:
> + * vm - Virtual Machine
> + * vcpuid - VCPU id
> + *
> + * Output Args: None
> + *
> + * Return: KVM CPUID (KVM_GET_CPUID2)
> + *
> + * Set the VCPU's CPUID.
> + */
> +struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vm *vm, uint32_t vcpuid)
> +{
> + struct vcpu *vcpu = vcpu_find(vm, vcpuid);
> + struct kvm_cpuid2 *cpuid;
> + int rc, max_ent;
> +
> + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid);
> +
> + cpuid = allocate_kvm_cpuid2();
> + max_ent = cpuid->nent;
> +
> + for (cpuid->nent = 1; cpuid->nent <= max_ent; cpuid->nent++) {
> + rc = ioctl(vcpu->fd, KVM_GET_CPUID2, cpuid);
> + if (!rc)
> + break;
> +
> + TEST_ASSERT(rc == -1 && errno == E2BIG,
> + "KVM_GET_CPUID2 should either succeed or give E2BIG: %d %d",
> + rc, errno);
> + }
> +
> + TEST_ASSERT(rc == 0, "KVM_GET_CPUID2 failed, rc: %i errno: %i",
> + rc, errno);
> +
> + return cpuid;
> +}
> +
> +
> +
> /*
> * Locate a cpuid entry.
> *
> diff --git a/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
> new file mode 100644
> index 000000000000..9b78e8889638
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/x86_64/get_cpuid_test.c
> @@ -0,0 +1,175 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2021, Red Hat Inc.
> + *
> + * Generic tests for KVM CPUID set/get ioctls
> + */
> +#include <asm/kvm_para.h>
> +#include <linux/kvm_para.h>
> +#include <stdint.h>
> +
> +#include "test_util.h"
> +#include "kvm_util.h"
> +#include "processor.h"
> +
> +#define VCPU_ID 0
> +
> +/* CPUIDs known to differ */
> +struct {
> + u32 function;
> + u32 index;
> +} mangled_cpuids[] = {
> + {.function = 0xd, .index = 0},
> +};
> +
> +static void test_guest_cpuids(struct kvm_cpuid2 *guest_cpuid)
> +{
> + int i;
> + u32 eax, ebx, ecx, edx;
> +
> + for (i = 0; i < guest_cpuid->nent; i++) {
> + eax = guest_cpuid->entries[i].function;
> + ecx = guest_cpuid->entries[i].index;
> +
> + cpuid(&eax, &ebx, &ecx, &edx);
> +
> + GUEST_ASSERT(eax == guest_cpuid->entries[i].eax &&
> + ebx == guest_cpuid->entries[i].ebx &&
> + ecx == guest_cpuid->entries[i].ecx &&
> + edx == guest_cpuid->entries[i].edx);
> + }
> +
> +}
> +
> +static void test_cpuid_40000000(struct kvm_cpuid2 *guest_cpuid)
> +{
> + u32 eax = 0x40000000, ebx, ecx = 0, edx;
> +
> + cpuid(&eax, &ebx, &ecx, &edx);
> +
> + GUEST_ASSERT(eax == 0x40000001);
> +}
> +
> +static void guest_main(struct kvm_cpuid2 *guest_cpuid)
> +{
> + GUEST_SYNC(1);
> +
> + test_guest_cpuids(guest_cpuid);
> +
> + GUEST_SYNC(2);
> +
> + test_cpuid_40000000(guest_cpuid);
> +
> + GUEST_DONE();
> +}
> +
> +static bool is_cpuid_mangled(struct kvm_cpuid_entry2 *entrie)
> +{
> + int i;
> +
> + for (i = 0; i < sizeof(mangled_cpuids); i++) {
> + if (mangled_cpuids[i].function == entrie->function &&
> + mangled_cpuids[i].index == entrie->index)
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static void check_cpuid(struct kvm_cpuid2 *cpuid, struct kvm_cpuid_entry2 *entrie)
> +{
> + int i;
> +
> + for (i = 0; i < cpuid->nent; i++) {
> + if (cpuid->entries[i].function == entrie->function &&
> + cpuid->entries[i].index == entrie->index) {
> + if (is_cpuid_mangled(entrie))
> + return;
> +
> + TEST_ASSERT(cpuid->entries[i].eax == entrie->eax &&
> + cpuid->entries[i].ebx == entrie->ebx &&
> + cpuid->entries[i].ecx == entrie->ecx &&
> + cpuid->entries[i].edx == entrie->edx,
> + "CPUID 0x%x.%x differ: 0x%x:0x%x:0x%x:0x%x vs 0x%x:0x%x:0x%x:0x%x",
> + entrie->function, entrie->index,
> + cpuid->entries[i].eax, cpuid->entries[i].ebx,
> + cpuid->entries[i].ecx, cpuid->entries[i].edx,
> + entrie->eax, entrie->ebx, entrie->ecx, entrie->edx);
> + return;
> + }
> + }
> +
> + TEST_ASSERT(false, "CPUID 0x%x.%x not found", entrie->function, entrie->index);
> +}
> +
> +static void compare_cpuids(struct kvm_cpuid2 *cpuid1, struct kvm_cpuid2 *cpuid2)
> +{
> + int i;
> +
> + for (i = 0; i < cpuid1->nent; i++)
> + check_cpuid(cpuid2, &cpuid1->entries[i]);
> +
> + for (i = 0; i < cpuid2->nent; i++)
> + check_cpuid(cpuid1, &cpuid2->entries[i]);
> +}
> +
> +static void run_vcpu(struct kvm_vm *vm, uint32_t vcpuid, int stage)
> +{
> + struct ucall uc;
> +
> + _vcpu_run(vm, vcpuid);
> +
> + switch (get_ucall(vm, vcpuid, &uc)) {
> + case UCALL_SYNC:
> + TEST_ASSERT(!strcmp((const char *)uc.args[0], "hello") &&
> + uc.args[1] == stage + 1,
> + "Stage %d: Unexpected register values vmexit, got %lx",
> + stage + 1, (ulong)uc.args[1]);
> + return;
> + case UCALL_DONE:
> + return;
> + case UCALL_ABORT:
> + TEST_ASSERT(false, "%s at %s:%ld\n\tvalues: %#lx, %#lx", (const char *)uc.args[0],
> + __FILE__, uc.args[1], uc.args[2], uc.args[3]);
> + default:
> + TEST_ASSERT(false, "Unexpected exit: %s",
> + exit_reason_str(vcpu_state(vm, vcpuid)->exit_reason));
> + }
> +}
> +
> +struct kvm_cpuid2 *vcpu_alloc_cpuid(struct kvm_vm *vm, vm_vaddr_t *p_gva, struct kvm_cpuid2 *cpuid)
> +{
> + int size = sizeof(*cpuid) + cpuid->nent * sizeof(cpuid->entries[0]);
> + vm_vaddr_t gva = vm_vaddr_alloc(vm, size,
> + getpagesize(), 0, 0);
> + struct kvm_cpuid2 *guest_cpuids = addr_gva2hva(vm, gva);
> +
> + memcpy(guest_cpuids, cpuid, size);
> +
> + *p_gva = gva;
> + return guest_cpuids;
> +}
> +
> +int main(void)
> +{
> + struct kvm_cpuid2 *supp_cpuid, *cpuid2;
> + vm_vaddr_t cpuid_gva;
> + struct kvm_vm *vm;
> + int stage;
> +
> + vm = vm_create_default(VCPU_ID, 0, guest_main);
> +
> + supp_cpuid = kvm_get_supported_cpuid();
> + cpuid2 = vcpu_get_cpuid(vm, VCPU_ID);
> +
> + compare_cpuids(supp_cpuid, cpuid2);
> +
> + vcpu_alloc_cpuid(vm, &cpuid_gva, cpuid2);
> +
> + vcpu_args_set(vm, VCPU_ID, 1, cpuid_gva);
> +
> + for (stage = 0; stage < 3; stage++)
> + run_vcpu(vm, VCPU_ID, stage);
> +
> + kvm_vm_free(vm);
> +}
>
Queued, thanks.
Paolo
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-02-02 17:32 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-29 16:18 [PATCH] selftest: kvm: x86: test KVM_GET_CPUID2 and guest visible CPUIDs against KVM_GET_SUPPORTED_CPUID Vitaly Kuznetsov
2021-02-02 17:28 ` Paolo Bonzini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).