KVM: selftests: Add framework to query KVM CPUID bits

Add X86_FEATURE_* magic in the style of KVM-Unit-Tests' implementation,
where the CPUID function, index, output register, and output bit position
are embedded in the macro value.  Add kvm_cpu_has() to query KVM's
supported CPUID and use it set_sregs_test, which is the most prolific
user of manual feature querying.

Opportunstically rename calc_cr4_feature_bits() to
calc_supported_cr4_feature_bits() to better capture how the CR4 bits are
chosen.

Link: https://lore.kernel.org/all/20210422005626.564163-1-ricarkol@google.com
Suggested-by: Paolo Bonzini <pbonzini@redhat.com>
Suggested-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20220614200707.3315957-4-seanjc@google.com
This commit is contained in:
Sean Christopherson 2022-06-14 20:06:28 +00:00
Родитель 683edfd42b
Коммит 61d76b8a69
3 изменённых файлов: 128 добавлений и 28 удалений

Просмотреть файл

@ -45,23 +45,96 @@
#define X86_CR4_SMAP (1ul << 21) #define X86_CR4_SMAP (1ul << 21)
#define X86_CR4_PKE (1ul << 22) #define X86_CR4_PKE (1ul << 22)
/* Note, these are ordered alphabetically to match kvm_cpuid_entry2. Eww. */
enum cpuid_output_regs {
KVM_CPUID_EAX,
KVM_CPUID_EBX,
KVM_CPUID_ECX,
KVM_CPUID_EDX
};
/*
* Pack the information into a 64-bit value so that each X86_FEATURE_XXX can be
* passed by value with no overhead.
*/
struct kvm_x86_cpu_feature {
u32 function;
u16 index;
u8 reg;
u8 bit;
};
#define KVM_X86_CPU_FEATURE(fn, idx, gpr, __bit) \
({ \
struct kvm_x86_cpu_feature feature = { \
.function = fn, \
.index = idx, \
.reg = KVM_CPUID_##gpr, \
.bit = __bit, \
}; \
\
feature; \
})
/*
* Basic Leafs, a.k.a. Intel defined
*/
#define X86_FEATURE_MWAIT KVM_X86_CPU_FEATURE(0x1, 0, ECX, 3)
#define X86_FEATURE_VMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 5)
#define X86_FEATURE_SMX KVM_X86_CPU_FEATURE(0x1, 0, ECX, 6)
#define X86_FEATURE_PCID KVM_X86_CPU_FEATURE(0x1, 0, ECX, 17)
#define X86_FEATURE_MOVBE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 22)
#define X86_FEATURE_TSC_DEADLINE_TIMER KVM_X86_CPU_FEATURE(0x1, 0, ECX, 24)
#define X86_FEATURE_XSAVE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 26)
#define X86_FEATURE_OSXSAVE KVM_X86_CPU_FEATURE(0x1, 0, ECX, 27)
#define X86_FEATURE_RDRAND KVM_X86_CPU_FEATURE(0x1, 0, ECX, 30)
#define X86_FEATURE_MCE KVM_X86_CPU_FEATURE(0x1, 0, EDX, 7)
#define X86_FEATURE_APIC KVM_X86_CPU_FEATURE(0x1, 0, EDX, 9)
#define X86_FEATURE_CLFLUSH KVM_X86_CPU_FEATURE(0x1, 0, EDX, 19)
#define X86_FEATURE_XMM KVM_X86_CPU_FEATURE(0x1, 0, EDX, 25)
#define X86_FEATURE_XMM2 KVM_X86_CPU_FEATURE(0x1, 0, EDX, 26)
#define X86_FEATURE_FSGSBASE KVM_X86_CPU_FEATURE(0x7, 0, EBX, 0)
#define X86_FEATURE_TSC_ADJUST KVM_X86_CPU_FEATURE(0x7, 0, EBX, 1)
#define X86_FEATURE_HLE KVM_X86_CPU_FEATURE(0x7, 0, EBX, 4)
#define X86_FEATURE_SMEP KVM_X86_CPU_FEATURE(0x7, 0, EBX, 7)
#define X86_FEATURE_INVPCID KVM_X86_CPU_FEATURE(0x7, 0, EBX, 10)
#define X86_FEATURE_RTM KVM_X86_CPU_FEATURE(0x7, 0, EBX, 11)
#define X86_FEATURE_SMAP KVM_X86_CPU_FEATURE(0x7, 0, EBX, 20)
#define X86_FEATURE_PCOMMIT KVM_X86_CPU_FEATURE(0x7, 0, EBX, 22)
#define X86_FEATURE_CLFLUSHOPT KVM_X86_CPU_FEATURE(0x7, 0, EBX, 23)
#define X86_FEATURE_CLWB KVM_X86_CPU_FEATURE(0x7, 0, EBX, 24)
#define X86_FEATURE_UMIP KVM_X86_CPU_FEATURE(0x7, 0, ECX, 2)
#define X86_FEATURE_PKU KVM_X86_CPU_FEATURE(0x7, 0, ECX, 3)
#define X86_FEATURE_LA57 KVM_X86_CPU_FEATURE(0x7, 0, ECX, 16)
#define X86_FEATURE_RDPID KVM_X86_CPU_FEATURE(0x7, 0, ECX, 22)
#define X86_FEATURE_SHSTK KVM_X86_CPU_FEATURE(0x7, 0, ECX, 7)
#define X86_FEATURE_IBT KVM_X86_CPU_FEATURE(0x7, 0, EDX, 20)
#define X86_FEATURE_SPEC_CTRL KVM_X86_CPU_FEATURE(0x7, 0, EDX, 26)
#define X86_FEATURE_ARCH_CAPABILITIES KVM_X86_CPU_FEATURE(0x7, 0, EDX, 29)
#define X86_FEATURE_PKS KVM_X86_CPU_FEATURE(0x7, 0, ECX, 31)
/*
* Extended Leafs, a.k.a. AMD defined
*/
#define X86_FEATURE_SVM KVM_X86_CPU_FEATURE(0x80000001, 0, ECX, 2)
#define X86_FEATURE_NX KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 20)
#define X86_FEATURE_GBPAGES KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 26)
#define X86_FEATURE_RDTSCP KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 27)
#define X86_FEATURE_LM KVM_X86_CPU_FEATURE(0x80000001, 0, EDX, 29)
#define X86_FEATURE_RDPRU KVM_X86_CPU_FEATURE(0x80000008, 0, EBX, 4)
#define X86_FEATURE_AMD_IBPB KVM_X86_CPU_FEATURE(0x80000008, 0, EBX, 12)
#define X86_FEATURE_NPT KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 0)
#define X86_FEATURE_LBRV KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 1)
#define X86_FEATURE_NRIPS KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 3)
#define X86_FEATURE_TSCRATEMSR KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 4)
#define X86_FEATURE_PAUSEFILTER KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 10)
#define X86_FEATURE_PFTHRESHOLD KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 12)
#define X86_FEATURE_VGIF KVM_X86_CPU_FEATURE(0x8000000A, 0, EDX, 16)
/* CPUID.1.ECX */ /* CPUID.1.ECX */
#define CPUID_VMX (1ul << 5) #define CPUID_VMX (1ul << 5)
#define CPUID_SMX (1ul << 6)
#define CPUID_PCID (1ul << 17)
#define CPUID_XSAVE (1ul << 26) #define CPUID_XSAVE (1ul << 26)
#define CPUID_OSXSAVE (1ul << 27) #define CPUID_OSXSAVE (1ul << 27)
/* 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)
/* CPUID.0x8000_0001.EDX */ /* CPUID.0x8000_0001.EDX */
#define CPUID_GBPAGES (1ul << 26) #define CPUID_GBPAGES (1ul << 26)
@ -490,6 +563,15 @@ static inline void vcpu_xcrs_set(struct kvm_vcpu *vcpu, struct kvm_xcrs *xcrs)
} }
struct kvm_cpuid2 *kvm_get_supported_cpuid(void); struct kvm_cpuid2 *kvm_get_supported_cpuid(void);
bool kvm_cpuid_has(const struct kvm_cpuid2 *cpuid,
struct kvm_x86_cpu_feature feature);
static inline bool kvm_cpu_has(struct kvm_x86_cpu_feature feature)
{
return kvm_cpuid_has(kvm_get_supported_cpuid(), feature);
}
struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu); struct kvm_cpuid2 *vcpu_get_cpuid(struct kvm_vcpu *vcpu);
static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu, static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu,

Просмотреть файл

@ -734,6 +734,28 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void)
return cpuid; return cpuid;
} }
bool kvm_cpuid_has(const struct kvm_cpuid2 *cpuid,
struct kvm_x86_cpu_feature feature)
{
const struct kvm_cpuid_entry2 *entry;
int i;
for (i = 0; i < cpuid->nent; i++) {
entry = &cpuid->entries[i];
/*
* The output registers in kvm_cpuid_entry2 are in alphabetical
* order, but kvm_x86_cpu_feature matches that mess, so yay
* pointer shenanigans!
*/
if (entry->function == feature.function &&
entry->index == feature.index)
return (&entry->eax)[feature.reg] & BIT(feature.bit);
}
return false;
}
uint64_t kvm_get_feature_msr(uint64_t msr_index) uint64_t kvm_get_feature_msr(uint64_t msr_index)
{ {
struct { struct {

Просмотреть файл

@ -43,36 +43,32 @@ static void test_cr4_feature_bit(struct kvm_vcpu *vcpu, struct kvm_sregs *orig,
TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs"); TEST_ASSERT(!memcmp(&sregs, orig, sizeof(sregs)), "KVM modified sregs");
} }
static uint64_t calc_cr4_feature_bits(struct kvm_vm *vm) static uint64_t calc_supported_cr4_feature_bits(void)
{ {
struct kvm_cpuid_entry2 *cpuid_1, *cpuid_7;
uint64_t cr4; 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 | 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_PSE | X86_CR4_PAE | X86_CR4_MCE | X86_CR4_PGE |
X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT; X86_CR4_PCE | X86_CR4_OSFXSR | X86_CR4_OSXMMEXCPT;
if (cpuid_7->ecx & CPUID_UMIP) if (kvm_cpu_has(X86_FEATURE_UMIP))
cr4 |= X86_CR4_UMIP; cr4 |= X86_CR4_UMIP;
if (cpuid_7->ecx & CPUID_LA57) if (kvm_cpu_has(X86_FEATURE_LA57))
cr4 |= X86_CR4_LA57; cr4 |= X86_CR4_LA57;
if (cpuid_1->ecx & CPUID_VMX) if (kvm_cpu_has(X86_FEATURE_VMX))
cr4 |= X86_CR4_VMXE; cr4 |= X86_CR4_VMXE;
if (cpuid_1->ecx & CPUID_SMX) if (kvm_cpu_has(X86_FEATURE_SMX))
cr4 |= X86_CR4_SMXE; cr4 |= X86_CR4_SMXE;
if (cpuid_7->ebx & CPUID_FSGSBASE) if (kvm_cpu_has(X86_FEATURE_FSGSBASE))
cr4 |= X86_CR4_FSGSBASE; cr4 |= X86_CR4_FSGSBASE;
if (cpuid_1->ecx & CPUID_PCID) if (kvm_cpu_has(X86_FEATURE_PCID))
cr4 |= X86_CR4_PCIDE; cr4 |= X86_CR4_PCIDE;
if (cpuid_1->ecx & CPUID_XSAVE) if (kvm_cpu_has(X86_FEATURE_XSAVE))
cr4 |= X86_CR4_OSXSAVE; cr4 |= X86_CR4_OSXSAVE;
if (cpuid_7->ebx & CPUID_SMEP) if (kvm_cpu_has(X86_FEATURE_SMEP))
cr4 |= X86_CR4_SMEP; cr4 |= X86_CR4_SMEP;
if (cpuid_7->ebx & CPUID_SMAP) if (kvm_cpu_has(X86_FEATURE_SMAP))
cr4 |= X86_CR4_SMAP; cr4 |= X86_CR4_SMAP;
if (cpuid_7->ecx & CPUID_PKU) if (kvm_cpu_has(X86_FEATURE_PKU))
cr4 |= X86_CR4_PKE; cr4 |= X86_CR4_PKE;
return cr4; return cr4;
@ -99,7 +95,7 @@ int main(int argc, char *argv[])
vcpu_sregs_get(vcpu, &sregs); vcpu_sregs_get(vcpu, &sregs);
sregs.cr4 |= calc_cr4_feature_bits(vm); sregs.cr4 |= calc_supported_cr4_feature_bits();
cr4 = sregs.cr4; cr4 = sregs.cr4;
rc = _vcpu_sregs_set(vcpu, &sregs); rc = _vcpu_sregs_set(vcpu, &sregs);