Commit 2259c17f authored by Jim Mattson's avatar Jim Mattson Committed by Paolo Bonzini
Browse files

kvm: x86: Sink cpuid update into vendor-specific set_cr4 functions



On emulated VM-entry and VM-exit, update the CPUID bits that reflect
CR4.OSXSAVE and CR4.PKE.

This fixes a bug where the CPUID bits could continue to reflect L2 CR4
values after emulated VM-exit to L1. It also fixes a related bug where
the CPUID bits could continue to reflect L1 CR4 values after emulated
VM-entry to L2. The latter bug is mainly relevant to SVM, wherein
CPUID is not a required intercept. However, it could also be relevant
to VMX, because the code to conditionally update these CPUID bits
assumes that the guest CPUID and the guest CR4 are always in sync.

Fixes: 8eb3f87d ("KVM: nVMX: fix guest CR4 loading when emulating L2 to L1 exit")
Fixes: 2acf923e ("KVM: VMX: Enable XSAVE/XRSTOR for guest")
Fixes: b9baba86 ("KVM, pkeys: expose CPUID/CR4 to guest")
Reported-by: default avatarAbhiroop Dabral <adabral@paloaltonetworks.com>
Signed-off-by: default avatarJim Mattson <jmattson@google.com>
Reviewed-by: default avatarRicardo Koller <ricarkol@google.com>
Reviewed-by: default avatarPeter Shier <pshier@google.com>
Cc: Haozhong Zhang <haozhong.zhang@intel.com>
Cc: Dexuan Cui <dexuan.cui@intel.com>
Cc: Huaitong Han <huaitong.han@intel.com>
Message-Id: <20201029170648.483210-1-jmattson@google.com>
parent 8aa426e8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -146,6 +146,7 @@ void kvm_update_cpuid_runtime(struct kvm_vcpu *vcpu)
					   MSR_IA32_MISC_ENABLE_MWAIT);
	}
}
EXPORT_SYMBOL_GPL(kvm_update_cpuid_runtime);

static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
{
+3 −0
Original line number Diff line number Diff line
@@ -1701,6 +1701,9 @@ void svm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
	cr4 |= host_cr4_mce;
	to_svm(vcpu)->vmcb->save.cr4 = cr4;
	vmcb_mark_dirty(to_svm(vcpu)->vmcb, VMCB_CR);

	if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE))
		kvm_update_cpuid_runtime(vcpu);
}

static void svm_set_segment(struct kvm_vcpu *vcpu,
+4 −0
Original line number Diff line number Diff line
@@ -3113,6 +3113,7 @@ static bool vmx_is_valid_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)

void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
{
	unsigned long old_cr4 = vcpu->arch.cr4;
	struct vcpu_vmx *vmx = to_vmx(vcpu);
	/*
	 * Pass through host's Machine Check Enable value to hw_cr4, which
@@ -3169,6 +3170,9 @@ void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)

	vmcs_writel(CR4_READ_SHADOW, cr4);
	vmcs_writel(GUEST_CR4, hw_cr4);

	if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE))
		kvm_update_cpuid_runtime(vcpu);
}

void vmx_get_segment(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg)
+0 −8
Original line number Diff line number Diff line
@@ -1012,9 +1012,6 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))
		kvm_mmu_reset_context(vcpu);

	if ((cr4 ^ old_cr4) & (X86_CR4_OSXSAVE | X86_CR4_PKE))
		kvm_update_cpuid_runtime(vcpu);

	return 0;
}
EXPORT_SYMBOL_GPL(kvm_set_cr4);
@@ -9576,7 +9573,6 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
{
	struct msr_data apic_base_msr;
	int mmu_reset_needed = 0;
	int cpuid_update_needed = 0;
	int pending_vec, max_bits, idx;
	struct desc_ptr dt;
	int ret = -EINVAL;
@@ -9611,11 +9607,7 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
	vcpu->arch.cr0 = sregs->cr0;

	mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
	cpuid_update_needed |= ((kvm_read_cr4(vcpu) ^ sregs->cr4) &
				(X86_CR4_OSXSAVE | X86_CR4_PKE));
	kvm_x86_ops.set_cr4(vcpu, sregs->cr4);
	if (cpuid_update_needed)
		kvm_update_cpuid_runtime(vcpu);

	idx = srcu_read_lock(&vcpu->kvm->srcu);
	if (is_pae_paging(vcpu)) {