| From: Wei Huang <wei@redhat.com> |
| Date: Tue, 1 May 2018 09:49:54 -0500 |
| Subject: KVM: x86: Update cpuid properly when CR4.OSXAVE or CR4.PKE is changed |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| commit c4d2188206bafa177ea58e9a25b952baa0bf7712 upstream. |
| |
| The CPUID bits of OSXSAVE (function=0x1) and OSPKE (func=0x7, leaf=0x0) |
| allows user apps to detect if OS has set CR4.OSXSAVE or CR4.PKE. KVM is |
| supposed to update these CPUID bits when CR4 is updated. Current KVM |
| code doesn't handle some special cases when updates come from emulator. |
| Here is one example: |
| |
| Step 1: guest boots |
| Step 2: guest OS enables XSAVE ==> CR4.OSXSAVE=1 and CPUID.OSXSAVE=1 |
| Step 3: guest hot reboot ==> QEMU reset CR4 to 0, but CPUID.OSXAVE==1 |
| Step 4: guest os checks CPUID.OSXAVE, detects 1, then executes xgetbv |
| |
| Step 4 above will cause an #UD and guest crash because guest OS hasn't |
| turned on OSXAVE yet. This patch solves the problem by comparing the the |
| old_cr4 with cr4. If the related bits have been changed, |
| kvm_update_cpuid() needs to be called. |
| |
| Signed-off-by: Wei Huang <wei@redhat.com> |
| Reviewed-by: Bandan Das <bsd@redhat.com> |
| Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> |
| [bwh: Backported to 3.16: PKE is not supported] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| arch/x86/kvm/x86.c | 5 ++++- |
| 1 file changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -6668,6 +6668,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct |
| { |
| 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; |
| |
| @@ -6702,8 +6703,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct |
| 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); |
| kvm_x86_ops->set_cr4(vcpu, sregs->cr4); |
| - if (sregs->cr4 & X86_CR4_OSXSAVE) |
| + if (cpuid_update_needed) |
| kvm_update_cpuid(vcpu); |
| |
| idx = srcu_read_lock(&vcpu->kvm->srcu); |