2021-04-28 20:56:56

by Ricardo Koller

[permalink] [raw]
Subject: [PATCH v2 0/6] KVM: x86: Use kernel x86 cpuid utilities in KVM selftests

The kernel has a set of utilities and definitions to deal with x86 cpu
features. The x86 KVM selftests don't use them, and instead have
evolved to use differing and ad-hoc methods for checking features. The
advantage of the kernel feature definitions is that they use a format
that embeds the info needed to extract them from cpuid (function, index,
and register to use).

Patches 1 and 2 add a script for checking that kernel headers don't
drift from their original copies. Patches 3 and 4 massage the related
cpuid header files in the kernel side, then copy them into tools/ so
they can be included by selftests. The last 2 patches replace the tests
checking for cpu features to use the definitions and utilities
introduced from the kernel.

Tested the arch/x86 patches by building these combinations:
ARCH=i386 allmodconfig
ARCH=i386 allyesconfig
ARCH=x86_64 allyesconfig
ARCH=x86_64 allmodconfig
ARCH=um alldefconfig
ARCH=i386 alldefconfig
and the selftest changes on both x86 and arm64.

Thanks,
Ricardo

v2:
- Add script to check for kernel headers drift in tools
- Sync header that is currently failing the check
- Move header copies under tools/testing/selftests/kvm/include/x86
instead of tools/arch/x86/include
v1: https://lore.kernel.org/kvm/[email protected]

Ricardo Koller (6):
KVM: selftests: Add kernel headers sync check
tools headers x86: Update bitsperlong.h in tools
x86/cpu: Expose CPUID regs, leaf and index definitions to tools
tools headers x86: Copy cpuid helpers from the kernel
KVM: selftests: Introduce utilities for checking x86 features
KVM: selftests: Use kernel x86 cpuid features format

arch/x86/events/intel/pt.c | 1 +
arch/x86/include/asm/cpufeature.h | 23 +-
arch/x86/include/asm/processor.h | 11 -
arch/x86/kernel/cpu/scattered.c | 2 +-
arch/x86/kernel/cpuid.c | 2 +-
tools/arch/x86/include/asm/cpufeatures.h | 3 +
tools/include/uapi/asm-generic/bitsperlong.h | 1 +
tools/testing/selftests/kvm/Makefile | 2 +
tools/testing/selftests/kvm/check-headers.sh | 64 +++++
.../kvm/include/x86_64/asm/cpufeature.h | 257 ++++++++++++++++++
.../selftests/kvm/include/x86_64/cpuid.h | 61 +++++
.../selftests/kvm/include/x86_64/processor.h | 16 --
.../kvm/include/x86_64/reverse_cpuid.h | 185 +++++++++++++
.../selftests/kvm/include/x86_64/svm_util.h | 11 +-
tools/testing/selftests/kvm/lib/x86_64/svm.c | 6 +-
tools/testing/selftests/kvm/lib/x86_64/vmx.c | 5 +-
tools/testing/selftests/kvm/steal_time.c | 5 +-
.../kvm/x86_64/cr4_cpuid_sync_test.c | 23 +-
.../selftests/kvm/x86_64/set_sregs_test.c | 25 +-
.../selftests/kvm/x86_64/vmx_pmu_msrs_test.c | 8 +-
.../kvm/x86_64/vmx_set_nested_state_test.c | 5 +-
.../selftests/kvm/x86_64/xss_msr_test.c | 10 +-
22 files changed, 630 insertions(+), 96 deletions(-)
create mode 100755 tools/testing/selftests/kvm/check-headers.sh
create mode 100644 tools/testing/selftests/kvm/include/x86_64/asm/cpufeature.h
create mode 100644 tools/testing/selftests/kvm/include/x86_64/cpuid.h
create mode 100644 tools/testing/selftests/kvm/include/x86_64/reverse_cpuid.h

--
2.31.1.498.g6c1eba8ee3d-goog


2021-04-28 20:57:23

by Ricardo Koller

[permalink] [raw]
Subject: [PATCH v2 6/6] KVM: selftests: Use kernel x86 cpuid features format

Change all tests checking for x86 cpuid features to use the same cpuid
feature definitions as the kernel (from cpufeatures.h). Also change the
tests to use the utilities introduced in cpuid.h.

Signed-off-by: Ricardo Koller <[email protected]>
---
.../selftests/kvm/include/x86_64/processor.h | 16 ------------
.../selftests/kvm/include/x86_64/svm_util.h | 11 ++------
tools/testing/selftests/kvm/lib/x86_64/svm.c | 6 ++---
tools/testing/selftests/kvm/lib/x86_64/vmx.c | 5 ++--
tools/testing/selftests/kvm/steal_time.c | 5 ++--
.../kvm/x86_64/cr4_cpuid_sync_test.c | 23 +++++------------
.../selftests/kvm/x86_64/set_sregs_test.c | 25 ++++++++-----------
.../selftests/kvm/x86_64/vmx_pmu_msrs_test.c | 8 +++---
.../kvm/x86_64/vmx_set_nested_state_test.c | 5 ++--
.../selftests/kvm/x86_64/xss_msr_test.c | 10 +++-----
10 files changed, 36 insertions(+), 78 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
index 0b30b4e15c38..022e00b04fff 100644
--- a/tools/testing/selftests/kvm/include/x86_64/processor.h
+++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
@@ -37,22 +37,6 @@
#define X86_CR4_SMAP (1ul << 21)
#define X86_CR4_PKE (1ul << 22)

-/* CPUID.1.ECX */
-#define CPUID_VMX (1ul << 5)
-#define CPUID_SMX (1ul << 6)
-#define CPUID_PCID (1ul << 17)
-#define CPUID_XSAVE (1ul << 26)
-
-/* CPUID.7.EBX */
-#define CPUID_FSGSBASE (1ul << 0)
-#define CPUID_SMEP (1ul << 7)
-#define CPUID_SMAP (1ul << 20)
-
-/* CPUID.7.ECX */
-#define CPUID_UMIP (1ul << 2)
-#define CPUID_PKU (1ul << 3)
-#define CPUID_LA57 (1ul << 16)
-
#define UNEXPECTED_VECTOR_PORT 0xfff0u

/* General Registers in 64-Bit Mode */
diff --git a/tools/testing/selftests/kvm/include/x86_64/svm_util.h b/tools/testing/selftests/kvm/include/x86_64/svm_util.h
index b7531c83b8ae..adba82ff4c9b 100644
--- a/tools/testing/selftests/kvm/include/x86_64/svm_util.h
+++ b/tools/testing/selftests/kvm/include/x86_64/svm_util.h
@@ -12,9 +12,7 @@
#include <stdint.h>
#include "svm.h"
#include "processor.h"
-
-#define CPUID_SVM_BIT 2
-#define CPUID_SVM BIT_ULL(CPUID_SVM_BIT)
+#include "cpuid.h"

#define SVM_EXIT_VMMCALL 0x081

@@ -38,12 +36,7 @@ void nested_svm_check_supported(void);

static inline bool cpu_has_svm(void)
{
- u32 eax = 0x80000001, ecx;
-
- asm("cpuid" :
- "=a" (eax), "=c" (ecx) : "0" (eax) : "ebx", "edx");
-
- return ecx & CPUID_SVM;
+ return this_cpu_has(X86_FEATURE_SVM);
}

#endif /* SELFTEST_KVM_SVM_UTILS_H */
diff --git a/tools/testing/selftests/kvm/lib/x86_64/svm.c b/tools/testing/selftests/kvm/lib/x86_64/svm.c
index 827fe6028dd4..c68245233cf9 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/svm.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/svm.c
@@ -12,6 +12,7 @@
#include "../kvm_util_internal.h"
#include "processor.h"
#include "svm_util.h"
+#include "cpuid.h"

struct gpr64_regs guest_regs;
u64 rflags;
@@ -150,10 +151,7 @@ void run_guest(struct vmcb *vmcb, uint64_t vmcb_gpa)

bool nested_svm_supported(void)
{
- struct kvm_cpuid_entry2 *entry =
- kvm_get_supported_cpuid_entry(0x80000001);
-
- return entry->ecx & CPUID_SVM;
+ return kvm_cpuid_has(X86_FEATURE_SVM);
}

void nested_svm_check_supported(void)
diff --git a/tools/testing/selftests/kvm/lib/x86_64/vmx.c b/tools/testing/selftests/kvm/lib/x86_64/vmx.c
index 2448b30e8efa..be26dcd260a4 100644
--- a/tools/testing/selftests/kvm/lib/x86_64/vmx.c
+++ b/tools/testing/selftests/kvm/lib/x86_64/vmx.c
@@ -10,6 +10,7 @@
#include "../kvm_util_internal.h"
#include "processor.h"
#include "vmx.h"
+#include "cpuid.h"

#define PAGE_SHIFT_4K 12

@@ -381,9 +382,7 @@ void prepare_vmcs(struct vmx_pages *vmx, void *guest_rip, void *guest_rsp)

bool nested_vmx_supported(void)
{
- struct kvm_cpuid_entry2 *entry = kvm_get_supported_cpuid_entry(1);
-
- return entry->ecx & CPUID_VMX;
+ return kvm_cpuid_has(X86_FEATURE_VMX);
}

void nested_vmx_check_supported(void)
diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c
index fcc840088c91..04d86601de92 100644
--- a/tools/testing/selftests/kvm/steal_time.c
+++ b/tools/testing/selftests/kvm/steal_time.c
@@ -27,6 +27,8 @@ static uint64_t guest_stolen_time[NR_VCPUS];

#if defined(__x86_64__)

+#include "cpuid.h"
+
/* steal_time must have 64-byte alignment */
#define STEAL_TIME_SIZE ((sizeof(struct kvm_steal_time) + 63) & ~63)

@@ -64,8 +66,7 @@ static void steal_time_init(struct kvm_vm *vm)
{
int i;

- if (!(kvm_get_supported_cpuid_entry(KVM_CPUID_FEATURES)->eax &
- KVM_FEATURE_STEAL_TIME)) {
+ if (!kvm_pv_has(KVM_FEATURE_STEAL_TIME)) {
print_skip("steal-time not supported");
exit(KSFT_SKIP);
}
diff --git a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c
index f40fd097cb35..97e97b258983 100644
--- a/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c
+++ b/tools/testing/selftests/kvm/x86_64/cr4_cpuid_sync_test.c
@@ -18,26 +18,17 @@

#include "kvm_util.h"
#include "processor.h"
+#include "cpuid.h"

-#define X86_FEATURE_XSAVE (1<<26)
-#define X86_FEATURE_OSXSAVE (1<<27)
#define VCPU_ID 1

static inline bool cr4_cpuid_is_sync(void)
{
- int func, subfunc;
- uint32_t eax, ebx, ecx, edx;
- uint64_t cr4;
-
- func = 0x1;
- subfunc = 0x0;
- __asm__ __volatile__("cpuid"
- : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
- : "a"(func), "c"(subfunc));
-
- cr4 = get_cr4();
+ uint64_t cr4 = get_cr4();
+ bool cpuid_has_osxsave = this_cpu_has(X86_FEATURE_OSXSAVE);
+ bool cr4_has_osxsave = cr4 & X86_CR4_OSXSAVE;

- return (!!(ecx & X86_FEATURE_OSXSAVE)) == (!!(cr4 & X86_CR4_OSXSAVE));
+ return cpuid_has_osxsave == cr4_has_osxsave;
}

static void guest_code(void)
@@ -66,12 +57,10 @@ int main(int argc, char *argv[])
struct kvm_run *run;
struct kvm_vm *vm;
struct kvm_sregs sregs;
- struct kvm_cpuid_entry2 *entry;
struct ucall uc;
int rc;

- entry = kvm_get_supported_cpuid_entry(1);
- if (!(entry->ecx & X86_FEATURE_XSAVE)) {
+ if (!kvm_cpuid_has(X86_FEATURE_XSAVE)) {
print_skip("XSAVE feature not supported");
return 0;
}
diff --git a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c
index 318be0bf77ab..e3247f33d765 100644
--- a/tools/testing/selftests/kvm/x86_64/set_sregs_test.c
+++ b/tools/testing/selftests/kvm/x86_64/set_sregs_test.c
@@ -21,6 +21,7 @@

#include "kvm_util.h"
#include "processor.h"
+#include "cpuid.h"

#define VCPU_ID 5

@@ -47,34 +48,30 @@ static void test_cr4_feature_bit(struct kvm_vm *vm, struct kvm_sregs *orig,

static uint64_t calc_cr4_feature_bits(struct kvm_vm *vm)
{
- struct kvm_cpuid_entry2 *cpuid_1, *cpuid_7;
uint64_t cr4;

- cpuid_1 = kvm_get_supported_cpuid_entry(1);
- cpuid_7 = kvm_get_supported_cpuid_entry(7);
-
cr4 = X86_CR4_VME | X86_CR4_PVI | X86_CR4_TSD | X86_CR4_DE |
X86_CR4_PSE | X86_CR4_PAE | X86_CR4_MCE | X86_CR4_PGE |
X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT;
- if (cpuid_7->ecx & CPUID_UMIP)
+ if (kvm_cpuid_has(X86_FEATURE_UMIP))
cr4 |= X86_CR4_UMIP;
- if (cpuid_7->ecx & CPUID_LA57)
+ if (kvm_cpuid_has(X86_FEATURE_LA57))
cr4 |= X86_CR4_LA57;
- if (cpuid_1->ecx & CPUID_VMX)
+ if (kvm_cpuid_has(X86_FEATURE_VMX))
cr4 |= X86_CR4_VMXE;
- if (cpuid_1->ecx & CPUID_SMX)
+ if (kvm_cpuid_has(X86_FEATURE_SMX))
cr4 |= X86_CR4_SMXE;
- if (cpuid_7->ebx & CPUID_FSGSBASE)
+ if (kvm_cpuid_has(X86_FEATURE_FSGSBASE))
cr4 |= X86_CR4_FSGSBASE;
- if (cpuid_1->ecx & CPUID_PCID)
+ if (kvm_cpuid_has(X86_FEATURE_PCID))
cr4 |= X86_CR4_PCIDE;
- if (cpuid_1->ecx & CPUID_XSAVE)
+ if (kvm_cpuid_has(X86_FEATURE_XSAVE))
cr4 |= X86_CR4_OSXSAVE;
- if (cpuid_7->ebx & CPUID_SMEP)
+ if (kvm_cpuid_has(X86_FEATURE_SMEP))
cr4 |= X86_CR4_SMEP;
- if (cpuid_7->ebx & CPUID_SMAP)
+ if (kvm_cpuid_has(X86_FEATURE_SMAP))
cr4 |= X86_CR4_SMAP;
- if (cpuid_7->ecx & CPUID_PKU)
+ if (kvm_cpuid_has(X86_FEATURE_PKU))
cr4 |= X86_CR4_PKE;

return cr4;
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c
index 23051d84b907..3755451f4877 100644
--- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c
+++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_msrs_test.c
@@ -17,10 +17,10 @@

#include "kvm_util.h"
#include "vmx.h"
+#include "cpuid.h"

#define VCPU_ID 0

-#define X86_FEATURE_PDCM (1<<15)
#define PMU_CAP_FW_WRITES (1ULL << 13)
#define PMU_CAP_LBR_FMT 0x3f

@@ -76,7 +76,7 @@ int main(int argc, char *argv[])
if (kvm_get_cpuid_max_basic() >= 0xa) {
entry_1_0 = kvm_get_supported_cpuid_index(1, 0);
entry_a_0 = kvm_get_supported_cpuid_index(0xa, 0);
- pdcm_supported = entry_1_0 && !!(entry_1_0->ecx & X86_FEATURE_PDCM);
+ pdcm_supported = kvm_cpuid_has(X86_FEATURE_PDCM);
eax.full = entry_a_0->eax;
}
if (!pdcm_supported) {
@@ -111,13 +111,13 @@ int main(int argc, char *argv[])
TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");

/* testcase 4, set capabilities when we don't have PDCM bit */
- entry_1_0->ecx &= ~X86_FEATURE_PDCM;
+ entry_1_0->ecx &= ~feature_bit(PDCM);
vcpu_set_cpuid(vm, VCPU_ID, cpuid);
ret = _vcpu_set_msr(vm, 0, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
TEST_ASSERT(ret == 0, "Bad PERF_CAPABILITIES didn't fail.");

/* testcase 5, set capabilities when we don't have PMU version bits */
- entry_1_0->ecx |= X86_FEATURE_PDCM;
+ entry_1_0->ecx |= feature_bit(PDCM);
eax.split.version_id = 0;
entry_1_0->ecx = eax.full;
vcpu_set_cpuid(vm, VCPU_ID, cpuid);
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
index 5827b9bae468..bea74c9ef0f7 100644
--- a/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
+++ b/tools/testing/selftests/kvm/x86_64/vmx_set_nested_state_test.c
@@ -11,6 +11,7 @@
#include "kvm_util.h"
#include "processor.h"
#include "vmx.h"
+#include "cpuid.h"

#include <errno.h>
#include <linux/kvm.h>
@@ -255,9 +256,9 @@ void disable_vmx(struct kvm_vm *vm)
break;
TEST_ASSERT(i != cpuid->nent, "CPUID function 1 not found");

- cpuid->entries[i].ecx &= ~CPUID_VMX;
+ cpuid->entries[i].ecx &= ~feature_bit(VMX);
vcpu_set_cpuid(vm, VCPU_ID, cpuid);
- cpuid->entries[i].ecx |= CPUID_VMX;
+ cpuid->entries[i].ecx |= feature_bit(VMX);
}

int main(int argc, char *argv[])
diff --git a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c
index 3529376747c2..962dbb63cffe 100644
--- a/tools/testing/selftests/kvm/x86_64/xss_msr_test.c
+++ b/tools/testing/selftests/kvm/x86_64/xss_msr_test.c
@@ -11,12 +11,11 @@
#include "test_util.h"
#include "kvm_util.h"
#include "vmx.h"
+#include "cpuid.h"

#define VCPU_ID 1
#define MSR_BITS 64

-#define X86_FEATURE_XSAVES (1<<3)
-
bool is_supported_msr(u32 msr_index)
{
struct kvm_msr_list *list;
@@ -37,7 +36,6 @@ bool is_supported_msr(u32 msr_index)

int main(int argc, char *argv[])
{
- struct kvm_cpuid_entry2 *entry;
bool xss_supported = false;
struct kvm_vm *vm;
uint64_t xss_val;
@@ -46,10 +44,8 @@ int main(int argc, char *argv[])
/* Create VM */
vm = vm_create_default(VCPU_ID, 0, 0);

- if (kvm_get_cpuid_max_basic() >= 0xd) {
- entry = kvm_get_supported_cpuid_index(0xd, 1);
- xss_supported = entry && !!(entry->eax & X86_FEATURE_XSAVES);
- }
+ if (kvm_get_cpuid_max_basic() >= 0xd)
+ xss_supported = kvm_cpuid_has(X86_FEATURE_XSAVES);
if (!xss_supported) {
print_skip("IA32_XSS is not supported by the vCPU");
exit(KSFT_SKIP);
--
2.31.1.498.g6c1eba8ee3d-goog