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:
Родитель
683edfd42b
Коммит
61d76b8a69
|
@ -45,23 +45,96 @@
|
|||
#define X86_CR4_SMAP (1ul << 21)
|
||||
#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 */
|
||||
#define CPUID_VMX (1ul << 5)
|
||||
#define CPUID_SMX (1ul << 6)
|
||||
#define CPUID_PCID (1ul << 17)
|
||||
#define CPUID_XSAVE (1ul << 26)
|
||||
#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 */
|
||||
#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);
|
||||
|
||||
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);
|
||||
|
||||
static inline int __vcpu_set_cpuid(struct kvm_vcpu *vcpu,
|
||||
|
|
|
@ -734,6 +734,28 @@ struct kvm_cpuid2 *kvm_get_supported_cpuid(void)
|
|||
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)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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_cpu_has(X86_FEATURE_UMIP))
|
||||
cr4 |= X86_CR4_UMIP;
|
||||
if (cpuid_7->ecx & CPUID_LA57)
|
||||
if (kvm_cpu_has(X86_FEATURE_LA57))
|
||||
cr4 |= X86_CR4_LA57;
|
||||
if (cpuid_1->ecx & CPUID_VMX)
|
||||
if (kvm_cpu_has(X86_FEATURE_VMX))
|
||||
cr4 |= X86_CR4_VMXE;
|
||||
if (cpuid_1->ecx & CPUID_SMX)
|
||||
if (kvm_cpu_has(X86_FEATURE_SMX))
|
||||
cr4 |= X86_CR4_SMXE;
|
||||
if (cpuid_7->ebx & CPUID_FSGSBASE)
|
||||
if (kvm_cpu_has(X86_FEATURE_FSGSBASE))
|
||||
cr4 |= X86_CR4_FSGSBASE;
|
||||
if (cpuid_1->ecx & CPUID_PCID)
|
||||
if (kvm_cpu_has(X86_FEATURE_PCID))
|
||||
cr4 |= X86_CR4_PCIDE;
|
||||
if (cpuid_1->ecx & CPUID_XSAVE)
|
||||
if (kvm_cpu_has(X86_FEATURE_XSAVE))
|
||||
cr4 |= X86_CR4_OSXSAVE;
|
||||
if (cpuid_7->ebx & CPUID_SMEP)
|
||||
if (kvm_cpu_has(X86_FEATURE_SMEP))
|
||||
cr4 |= X86_CR4_SMEP;
|
||||
if (cpuid_7->ebx & CPUID_SMAP)
|
||||
if (kvm_cpu_has(X86_FEATURE_SMAP))
|
||||
cr4 |= X86_CR4_SMAP;
|
||||
if (cpuid_7->ecx & CPUID_PKU)
|
||||
if (kvm_cpu_has(X86_FEATURE_PKU))
|
||||
cr4 |= X86_CR4_PKE;
|
||||
|
||||
return cr4;
|
||||
|
@ -99,7 +95,7 @@ int main(int argc, char *argv[])
|
|||
|
||||
vcpu_sregs_get(vcpu, &sregs);
|
||||
|
||||
sregs.cr4 |= calc_cr4_feature_bits(vm);
|
||||
sregs.cr4 |= calc_supported_cr4_feature_bits();
|
||||
cr4 = sregs.cr4;
|
||||
|
||||
rc = _vcpu_sregs_set(vcpu, &sregs);
|
||||
|
|
Загрузка…
Ссылка в новой задаче