Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d6321d49 authored by Radim Krčmář's avatar Radim Krčmář Committed by Paolo Bonzini
Browse files

KVM: x86: generalize guest_cpuid_has_ helpers



This patch turns guest_cpuid_has_XYZ(cpuid) into guest_cpuid_has(cpuid,
X86_FEATURE_XYZ), which gets rid of many very similar helpers.

When seeing a X86_FEATURE_*, we can know which cpuid it belongs to, but
this information isn't in common code, so we recreate it for KVM.

Add some BUILD_BUG_ONs to make sure that it runs nicely.

Signed-off-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
Reviewed-by: default avatarDavid Hildenbrand <david@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent c6bd1801
Loading
Loading
Loading
Loading
+57 −113
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@

#include "x86.h"
#include <asm/cpu.h>
#include <asm/processor.h>

int kvm_update_cpuid(struct kvm_vcpu *vcpu);
bool kvm_mpx_supported(void);
@@ -29,95 +30,78 @@ static inline int cpuid_maxphyaddr(struct kvm_vcpu *vcpu)
	return vcpu->arch.maxphyaddr;
}

static inline bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;
struct cpuid_reg {
	u32 function;
	u32 index;
	int reg;
};

	if (!static_cpu_has(X86_FEATURE_XSAVE))
		return false;

	best = kvm_find_cpuid_entry(vcpu, 1, 0);
	return best && (best->ecx & bit(X86_FEATURE_XSAVE));
}
static const struct cpuid_reg reverse_cpuid[] = {
	[CPUID_1_EDX]         = {         1, 0, CPUID_EDX},
	[CPUID_8000_0001_EDX] = {0x80000001, 0, CPUID_EDX},
	[CPUID_8086_0001_EDX] = {0x80860001, 0, CPUID_EDX},
	[CPUID_1_ECX]         = {         1, 0, CPUID_ECX},
	[CPUID_C000_0001_EDX] = {0xc0000001, 0, CPUID_EDX},
	[CPUID_8000_0001_ECX] = {0xc0000001, 0, CPUID_ECX},
	[CPUID_7_0_EBX]       = {         7, 0, CPUID_EBX},
	[CPUID_D_1_EAX]       = {       0xd, 1, CPUID_EAX},
	[CPUID_F_0_EDX]       = {       0xf, 0, CPUID_EDX},
	[CPUID_F_1_EDX]       = {       0xf, 1, CPUID_EDX},
	[CPUID_8000_0008_EBX] = {0x80000008, 0, CPUID_EBX},
	[CPUID_6_EAX]         = {         6, 0, CPUID_EAX},
	[CPUID_8000_000A_EDX] = {0x8000000a, 0, CPUID_EDX},
	[CPUID_7_ECX]         = {         7, 0, CPUID_ECX},
	[CPUID_8000_0007_EBX] = {0x80000007, 0, CPUID_EBX},
};

static inline bool guest_cpuid_has_mtrr(struct kvm_vcpu *vcpu)
static __always_inline struct cpuid_reg x86_feature_cpuid(unsigned x86_feature)
{
	struct kvm_cpuid_entry2 *best;
	unsigned x86_leaf = x86_feature / 32;

	best = kvm_find_cpuid_entry(vcpu, 1, 0);
	return best && (best->edx & bit(X86_FEATURE_MTRR));
}
	BUILD_BUG_ON(!__builtin_constant_p(x86_leaf));
	BUILD_BUG_ON(x86_leaf >= ARRAY_SIZE(reverse_cpuid));
	BUILD_BUG_ON(reverse_cpuid[x86_leaf].function == 0);

static inline bool guest_cpuid_has_tsc_adjust(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ebx & bit(X86_FEATURE_TSC_ADJUST));
	return reverse_cpuid[x86_leaf];
}

static inline bool guest_cpuid_has_smep(struct kvm_vcpu *vcpu)
static __always_inline int *guest_cpuid_get_register(struct kvm_vcpu *vcpu, unsigned x86_feature)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ebx & bit(X86_FEATURE_SMEP));
}
	struct kvm_cpuid_entry2 *entry;
	const struct cpuid_reg cpuid = x86_feature_cpuid(x86_feature);

static inline bool guest_cpuid_has_smap(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;
	entry = kvm_find_cpuid_entry(vcpu, cpuid.function, cpuid.index);
	if (!entry)
		return NULL;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ebx & bit(X86_FEATURE_SMAP));
	switch (cpuid.reg) {
	case CPUID_EAX:
		return &entry->eax;
	case CPUID_EBX:
		return &entry->ebx;
	case CPUID_ECX:
		return &entry->ecx;
	case CPUID_EDX:
		return &entry->edx;
	default:
		BUILD_BUG();
		return NULL;
	}

static inline bool guest_cpuid_has_fsgsbase(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ebx & bit(X86_FEATURE_FSGSBASE));
}

static inline bool guest_cpuid_has_pku(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ecx & bit(X86_FEATURE_PKU));
}

static inline bool guest_cpuid_has_longmode(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
	return best && (best->edx & bit(X86_FEATURE_LM));
}

static inline bool guest_cpuid_has_osvw(struct kvm_vcpu *vcpu)
static __always_inline bool guest_cpuid_has(struct kvm_vcpu *vcpu, unsigned x86_feature)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
	return best && (best->ecx & bit(X86_FEATURE_OSVW));
}
	int *reg;

static inline bool guest_cpuid_has_pcid(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 1, 0);
	return best && (best->ecx & bit(X86_FEATURE_PCID));
}
	if (x86_feature == X86_FEATURE_XSAVE &&
			!static_cpu_has(X86_FEATURE_XSAVE))
		return false;

static inline bool guest_cpuid_has_x2apic(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;
	reg = guest_cpuid_get_register(vcpu, x86_feature);
	if (!reg)
		return false;

	best = kvm_find_cpuid_entry(vcpu, 1, 0);
	return best && (best->ecx & bit(X86_FEATURE_X2APIC));
	return *reg & bit(x86_feature);
}

static inline bool guest_cpuid_is_amd(struct kvm_vcpu *vcpu)
@@ -128,46 +112,6 @@ static inline bool guest_cpuid_is_amd(struct kvm_vcpu *vcpu)
	return best && best->ebx == X86EMUL_CPUID_VENDOR_AuthenticAMD_ebx;
}

static inline bool guest_cpuid_has_gbpages(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
	return best && (best->edx & bit(X86_FEATURE_GBPAGES));
}

static inline bool guest_cpuid_has_rtm(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ebx & bit(X86_FEATURE_RTM));
}

static inline bool guest_cpuid_has_mpx(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 7, 0);
	return best && (best->ebx & bit(X86_FEATURE_MPX));
}

static inline bool guest_cpuid_has_rdtscp(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
	return best && (best->edx & bit(X86_FEATURE_RDTSCP));
}

static inline bool guest_cpuid_has_nrips(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;

	best = kvm_find_cpuid_entry(vcpu, 0x8000000a, 0);
	return best && (best->edx & bit(X86_FEATURE_NRIPS));
}

static inline int guest_cpuid_family(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best;
+4 −3
Original line number Diff line number Diff line
@@ -4052,7 +4052,8 @@ static void reset_rsvds_bits_mask(struct kvm_vcpu *vcpu,
{
	__reset_rsvds_bits_mask(vcpu, &context->guest_rsvd_check,
				cpuid_maxphyaddr(vcpu), context->root_level,
				context->nx, guest_cpuid_has_gbpages(vcpu),
				context->nx,
				guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES),
				is_pse(vcpu), guest_cpuid_is_amd(vcpu));
}

@@ -4114,8 +4115,8 @@ reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context)
	__reset_rsvds_bits_mask(vcpu, &context->shadow_zero_check,
				boot_cpu_data.x86_phys_bits,
				context->shadow_root_level, uses_nx,
				guest_cpuid_has_gbpages(vcpu), is_pse(vcpu),
				true);
				guest_cpuid_has(vcpu, X86_FEATURE_GBPAGES),
				is_pse(vcpu), true);
}
EXPORT_SYMBOL_GPL(reset_shadow_zero_bits_mask);

+1 −1
Original line number Diff line number Diff line
@@ -130,7 +130,7 @@ static u8 mtrr_disabled_type(struct kvm_vcpu *vcpu)
	 * enable MTRRs and it is obviously undesirable to run the
	 * guest entirely with UC memory and we use WB.
	 */
	if (guest_cpuid_has_mtrr(vcpu))
	if (guest_cpuid_has(vcpu, X86_FEATURE_MTRR))
		return MTRR_TYPE_UNCACHABLE;
	else
		return MTRR_TYPE_WRBACK;
+1 −1
Original line number Diff line number Diff line
@@ -5078,7 +5078,7 @@ static void svm_cpuid_update(struct kvm_vcpu *vcpu)
	struct kvm_cpuid_entry2 *entry;

	/* Update nrips enabled cache */
	svm->nrips_enabled = !!guest_cpuid_has_nrips(&svm->vcpu);
	svm->nrips_enabled = !!guest_cpuid_has(&svm->vcpu, X86_FEATURE_NRIPS);

	if (!kvm_vcpu_apicv_active(vcpu))
		return;
+12 −14
Original line number Diff line number Diff line
@@ -2611,7 +2611,7 @@ static void setup_msrs(struct vcpu_vmx *vmx)
		if (index >= 0)
			move_msr_up(vmx, index, save_nmsrs++);
		index = __find_msr_index(vmx, MSR_TSC_AUX);
		if (index >= 0 && guest_cpuid_has_rdtscp(&vmx->vcpu))
		if (index >= 0 && guest_cpuid_has(&vmx->vcpu, X86_FEATURE_RDTSCP))
			move_msr_up(vmx, index, save_nmsrs++);
		/*
		 * MSR_STAR is only needed on long mode guests, and only
@@ -2671,12 +2671,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
	}
}

static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
{
	struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0);
	return best && (best->ecx & (1 << (X86_FEATURE_VMX & 31)));
}

/*
 * nested_vmx_allowed() checks whether a guest should be allowed to use VMX
 * instructions and MSRs (i.e., nested VMX). Nested VMX is disabled for
@@ -2685,7 +2679,7 @@ static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
 */
static inline bool nested_vmx_allowed(struct kvm_vcpu *vcpu)
{
	return nested && guest_cpuid_has_vmx(vcpu);
	return nested && guest_cpuid_has(vcpu, X86_FEATURE_VMX);
}

/*
@@ -3281,7 +3275,8 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
		break;
	case MSR_IA32_BNDCFGS:
		if (!kvm_mpx_supported() ||
		    (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu)))
		    (!msr_info->host_initiated &&
		     !guest_cpuid_has(vcpu, X86_FEATURE_MPX)))
			return 1;
		msr_info->data = vmcs_read64(GUEST_BNDCFGS);
		break;
@@ -3305,7 +3300,8 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
		msr_info->data = vcpu->arch.ia32_xss;
		break;
	case MSR_TSC_AUX:
		if (!guest_cpuid_has_rdtscp(vcpu) && !msr_info->host_initiated)
		if (!msr_info->host_initiated &&
		    !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
			return 1;
		/* Otherwise falls through */
	default:
@@ -3364,7 +3360,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
		break;
	case MSR_IA32_BNDCFGS:
		if (!kvm_mpx_supported() ||
		    (!msr_info->host_initiated && !guest_cpuid_has_mpx(vcpu)))
		    (!msr_info->host_initiated &&
		     !guest_cpuid_has(vcpu, X86_FEATURE_MPX)))
			return 1;
		if (is_noncanonical_address(data & PAGE_MASK) ||
		    (data & MSR_IA32_BNDCFGS_RSVD))
@@ -3427,7 +3424,8 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
			clear_atomic_switch_msr(vmx, MSR_IA32_XSS);
		break;
	case MSR_TSC_AUX:
		if (!guest_cpuid_has_rdtscp(vcpu) && !msr_info->host_initiated)
		if (!msr_info->host_initiated &&
		    !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP))
			return 1;
		/* Check reserved bit, higher 32 bits should be zero */
		if ((data >> 32) != 0)
@@ -9622,7 +9620,7 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
	u32 secondary_exec_ctl = vmx_secondary_exec_control(vmx);

	if (vmx_rdtscp_supported()) {
		bool rdtscp_enabled = guest_cpuid_has_rdtscp(vcpu);
		bool rdtscp_enabled = guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP);
		if (!rdtscp_enabled)
			secondary_exec_ctl &= ~SECONDARY_EXEC_RDTSCP;

@@ -9641,7 +9639,7 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
		struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 0x7, 0);
		bool invpcid_enabled =
			best && best->ebx & bit(X86_FEATURE_INVPCID) &&
			guest_cpuid_has_pcid(vcpu);
			guest_cpuid_has(vcpu, X86_FEATURE_PCID);

		if (!invpcid_enabled) {
			secondary_exec_ctl &= ~SECONDARY_EXEC_ENABLE_INVPCID;
Loading