Commit 61d76b8a authored by Sean Christopherson's avatar Sean Christopherson
Browse files

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: default avatarPaolo Bonzini <pbonzini@redhat.com>
Suggested-by: default avatarJim Mattson <jmattson@google.com>
Signed-off-by: default avatarSean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20220614200707.3315957-4-seanjc@google.com
parent 683edfd4
Loading
Loading
Loading
Loading
+94 −12
Original line number Diff line number Diff line
@@ -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,
+22 −0
Original line number Diff line number Diff line
@@ -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 {
+12 −16
Original line number Diff line number Diff line
@@ -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);