]>
Commit | Line | Data |
---|---|---|
eab49e0f GKH |
1 | From c4d2188206bafa177ea58e9a25b952baa0bf7712 Mon Sep 17 00:00:00 2001 |
2 | From: Wei Huang <wei@redhat.com> | |
3 | Date: Tue, 1 May 2018 09:49:54 -0500 | |
4 | Subject: KVM: x86: Update cpuid properly when CR4.OSXAVE or CR4.PKE is changed | |
5 | MIME-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ||
9 | From: Wei Huang <wei@redhat.com> | |
10 | ||
11 | commit c4d2188206bafa177ea58e9a25b952baa0bf7712 upstream. | |
12 | ||
13 | The CPUID bits of OSXSAVE (function=0x1) and OSPKE (func=0x7, leaf=0x0) | |
14 | allows user apps to detect if OS has set CR4.OSXSAVE or CR4.PKE. KVM is | |
15 | supposed to update these CPUID bits when CR4 is updated. Current KVM | |
16 | code doesn't handle some special cases when updates come from emulator. | |
17 | Here is one example: | |
18 | ||
19 | Step 1: guest boots | |
20 | Step 2: guest OS enables XSAVE ==> CR4.OSXSAVE=1 and CPUID.OSXSAVE=1 | |
21 | Step 3: guest hot reboot ==> QEMU reset CR4 to 0, but CPUID.OSXAVE==1 | |
22 | Step 4: guest os checks CPUID.OSXAVE, detects 1, then executes xgetbv | |
23 | ||
24 | Step 4 above will cause an #UD and guest crash because guest OS hasn't | |
25 | turned on OSXAVE yet. This patch solves the problem by comparing the the | |
26 | old_cr4 with cr4. If the related bits have been changed, | |
27 | kvm_update_cpuid() needs to be called. | |
28 | ||
29 | Signed-off-by: Wei Huang <wei@redhat.com> | |
30 | Reviewed-by: Bandan Das <bsd@redhat.com> | |
31 | Cc: stable@vger.kernel.org | |
32 | Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> | |
33 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
34 | ||
35 | --- | |
36 | arch/x86/kvm/x86.c | 5 ++++- | |
37 | 1 file changed, 4 insertions(+), 1 deletion(-) | |
38 | ||
39 | --- a/arch/x86/kvm/x86.c | |
40 | +++ b/arch/x86/kvm/x86.c | |
41 | @@ -7258,6 +7258,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct | |
42 | { | |
43 | struct msr_data apic_base_msr; | |
44 | int mmu_reset_needed = 0; | |
45 | + int cpuid_update_needed = 0; | |
46 | int pending_vec, max_bits, idx; | |
47 | struct desc_ptr dt; | |
48 | ||
49 | @@ -7289,8 +7290,10 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct | |
50 | vcpu->arch.cr0 = sregs->cr0; | |
51 | ||
52 | mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4; | |
53 | + cpuid_update_needed |= ((kvm_read_cr4(vcpu) ^ sregs->cr4) & | |
54 | + (X86_CR4_OSXSAVE | X86_CR4_PKE)); | |
55 | kvm_x86_ops->set_cr4(vcpu, sregs->cr4); | |
56 | - if (sregs->cr4 & (X86_CR4_OSXSAVE | X86_CR4_PKE)) | |
57 | + if (cpuid_update_needed) | |
58 | kvm_update_cpuid(vcpu); | |
59 | ||
60 | idx = srcu_read_lock(&vcpu->kvm->srcu); |