]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.12/0005-KVM-VMX-Save-restore-rflags.vm-correctly-in-real-mod.patch
Fixes for 4.19
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.12 / 0005-KVM-VMX-Save-restore-rflags.vm-correctly-in-real-mod.patch
1 From 8a618f6f19f9bc88e8b5d75cbfbfedcb416246f3 Mon Sep 17 00:00:00 2001
2 From: Avi Kivity <avi@redhat.com>
3 Date: Thu, 8 Apr 2010 18:19:35 +0300
4 Subject: KVM: VMX: Save/restore rflags.vm correctly in real mode
5
6 From: Avi Kivity <avi@redhat.com>
7
8 (Cherry-picked from commit 78ac8b47c566dd6177a3b9b291b756ccb70670b7)
9
10 Currently we set eflags.vm unconditionally when entering real mode emulation
11 through virtual-8086 mode, and clear it unconditionally when we enter protected
12 mode. The means that the following sequence
13
14 KVM_SET_REGS (rflags.vm=1)
15 KVM_SET_SREGS (cr0.pe=1)
16
17 Ends up with rflags.vm clear due to KVM_SET_SREGS triggering enter_pmode().
18
19 Fix by shadowing rflags.vm (and rflags.iopl) correctly while in real mode:
20 reads and writes to those bits access a shadow register instead of the actual
21 register.
22
23 Signed-off-by: Avi Kivity <avi@redhat.com>
24 Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
25 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
26
27 ---
28 arch/x86/kvm/vmx.c | 24 +++++++++++++++---------
29 1 file changed, 15 insertions(+), 9 deletions(-)
30
31 --- a/arch/x86/kvm/vmx.c
32 +++ b/arch/x86/kvm/vmx.c
33 @@ -61,6 +61,8 @@ module_param_named(unrestricted_guest,
34 static int __read_mostly emulate_invalid_guest_state = 0;
35 module_param(emulate_invalid_guest_state, bool, S_IRUGO);
36
37 +#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM))
38 +
39 struct vmcs {
40 u32 revision_id;
41 u32 abort;
42 @@ -92,7 +94,7 @@ struct vcpu_vmx {
43 } host_state;
44 struct {
45 int vm86_active;
46 - u8 save_iopl;
47 + ulong save_rflags;
48 struct kvm_save_segment {
49 u16 selector;
50 unsigned long base;
51 @@ -783,18 +785,23 @@ static void vmx_fpu_deactivate(struct kv
52
53 static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
54 {
55 - unsigned long rflags;
56 + unsigned long rflags, save_rflags;
57
58 rflags = vmcs_readl(GUEST_RFLAGS);
59 - if (to_vmx(vcpu)->rmode.vm86_active)
60 - rflags &= ~(unsigned long)(X86_EFLAGS_IOPL | X86_EFLAGS_VM);
61 + if (to_vmx(vcpu)->rmode.vm86_active) {
62 + rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
63 + save_rflags = to_vmx(vcpu)->rmode.save_rflags;
64 + rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
65 + }
66 return rflags;
67 }
68
69 static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
70 {
71 - if (to_vmx(vcpu)->rmode.vm86_active)
72 + if (to_vmx(vcpu)->rmode.vm86_active) {
73 + to_vmx(vcpu)->rmode.save_rflags = rflags;
74 rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
75 + }
76 vmcs_writel(GUEST_RFLAGS, rflags);
77 }
78
79 @@ -1431,8 +1438,8 @@ static void enter_pmode(struct kvm_vcpu
80 vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar);
81
82 flags = vmcs_readl(GUEST_RFLAGS);
83 - flags &= ~(X86_EFLAGS_IOPL | X86_EFLAGS_VM);
84 - flags |= (vmx->rmode.save_iopl << IOPL_SHIFT);
85 + flags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
86 + flags |= vmx->rmode.save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
87 vmcs_writel(GUEST_RFLAGS, flags);
88
89 vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
90 @@ -1501,8 +1508,7 @@ static void enter_rmode(struct kvm_vcpu
91 vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
92
93 flags = vmcs_readl(GUEST_RFLAGS);
94 - vmx->rmode.save_iopl
95 - = (flags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
96 + vmx->rmode.save_rflags = flags;
97
98 flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
99