aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2010-04-08 11:19:35 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-26 10:48:05 -0400
commit01b0fb7b85b4b8a3027e5cc7663ae8b2193b1104 (patch)
treed3ceb1eb0b57c4a68f280c0d051c9ca05e573be4 /arch
parentec861e75183fa0049917cbfa44d8a17e7ece7b4f (diff)
KVM: VMX: Save/restore rflags.vm correctly in real mode
(Cherry-picked from commit 78ac8b47c566dd6177a3b9b291b756ccb70670b7) Currently we set eflags.vm unconditionally when entering real mode emulation through virtual-8086 mode, and clear it unconditionally when we enter protected mode. The means that the following sequence KVM_SET_REGS (rflags.vm=1) KVM_SET_SREGS (cr0.pe=1) Ends up with rflags.vm clear due to KVM_SET_SREGS triggering enter_pmode(). Fix by shadowing rflags.vm (and rflags.iopl) correctly while in real mode: reads and writes to those bits access a shadow register instead of the actual register. Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/kvm/vmx.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 85904fa41f03..3acbe194e525 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -61,6 +61,8 @@ module_param_named(unrestricted_guest,
61static int __read_mostly emulate_invalid_guest_state = 0; 61static int __read_mostly emulate_invalid_guest_state = 0;
62module_param(emulate_invalid_guest_state, bool, S_IRUGO); 62module_param(emulate_invalid_guest_state, bool, S_IRUGO);
63 63
64#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM))
65
64/* 66/*
65 * These 2 parameters are used to config the controls for Pause-Loop Exiting: 67 * These 2 parameters are used to config the controls for Pause-Loop Exiting:
66 * ple_gap: upper bound on the amount of time between two successive 68 * ple_gap: upper bound on the amount of time between two successive
@@ -115,7 +117,7 @@ struct vcpu_vmx {
115 } host_state; 117 } host_state;
116 struct { 118 struct {
117 int vm86_active; 119 int vm86_active;
118 u8 save_iopl; 120 ulong save_rflags;
119 struct kvm_save_segment { 121 struct kvm_save_segment {
120 u16 selector; 122 u16 selector;
121 unsigned long base; 123 unsigned long base;
@@ -787,18 +789,23 @@ static void vmx_fpu_deactivate(struct kvm_vcpu *vcpu)
787 789
788static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) 790static unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu)
789{ 791{
790 unsigned long rflags; 792 unsigned long rflags, save_rflags;
791 793
792 rflags = vmcs_readl(GUEST_RFLAGS); 794 rflags = vmcs_readl(GUEST_RFLAGS);
793 if (to_vmx(vcpu)->rmode.vm86_active) 795 if (to_vmx(vcpu)->rmode.vm86_active) {
794 rflags &= ~(unsigned long)(X86_EFLAGS_IOPL | X86_EFLAGS_VM); 796 rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
797 save_rflags = to_vmx(vcpu)->rmode.save_rflags;
798 rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
799 }
795 return rflags; 800 return rflags;
796} 801}
797 802
798static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) 803static void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
799{ 804{
800 if (to_vmx(vcpu)->rmode.vm86_active) 805 if (to_vmx(vcpu)->rmode.vm86_active) {
806 to_vmx(vcpu)->rmode.save_rflags = rflags;
801 rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; 807 rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
808 }
802 vmcs_writel(GUEST_RFLAGS, rflags); 809 vmcs_writel(GUEST_RFLAGS, rflags);
803} 810}
804 811
@@ -1431,8 +1438,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
1431 vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar); 1438 vmcs_write32(GUEST_TR_AR_BYTES, vmx->rmode.tr.ar);
1432 1439
1433 flags = vmcs_readl(GUEST_RFLAGS); 1440 flags = vmcs_readl(GUEST_RFLAGS);
1434 flags &= ~(X86_EFLAGS_IOPL | X86_EFLAGS_VM); 1441 flags &= RMODE_GUEST_OWNED_EFLAGS_BITS;
1435 flags |= (vmx->rmode.save_iopl << IOPL_SHIFT); 1442 flags |= vmx->rmode.save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS;
1436 vmcs_writel(GUEST_RFLAGS, flags); 1443 vmcs_writel(GUEST_RFLAGS, flags);
1437 1444
1438 vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | 1445 vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) |
@@ -1501,8 +1508,7 @@ static void enter_rmode(struct kvm_vcpu *vcpu)
1501 vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); 1508 vmcs_write32(GUEST_TR_AR_BYTES, 0x008b);
1502 1509
1503 flags = vmcs_readl(GUEST_RFLAGS); 1510 flags = vmcs_readl(GUEST_RFLAGS);
1504 vmx->rmode.save_iopl 1511 vmx->rmode.save_rflags = flags;
1505 = (flags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
1506 1512
1507 flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; 1513 flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM;
1508 1514