aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2012-08-01 09:48:03 -0400
committerMarcelo Tosatti <mtosatti@redhat.com>2012-08-01 19:23:57 -0400
commitaa67f6096c19bcdb1951ef88be3cf3d2118809dc (patch)
tree61a806e065b9db4eabfd85753333e580d8b0a465 /arch/x86/kvm/vmx.c
parent4b6486659a7defef82ea51b276024b3aa357fefc (diff)
KVM: VMX: Fix ds/es corruption on i386 with preemption
Commit b2da15ac26a0c ("KVM: VMX: Optimize %ds, %es reload") broke i386 in the following scenario: vcpu_load ... vmx_save_host_state vmx_vcpu_run (ds.rpl, es.rpl cleared by hardware) interrupt push ds, es # pushes bad ds, es schedule vmx_vcpu_put vmx_load_host_state reload ds, es (with __USER_DS) pop ds, es # of other thread's stack iret # other thread runs interrupt push ds, es schedule # back in vcpu thread pop ds, es # now with rpl=0 iret ... vcpu_put resume_userspace iret # clears ds, es due to mismatched rpl (instead of resume_userspace, we might return with SYSEXIT and then take an exception; when the exception IRETs we end up with cleared ds, es) Fix by avoiding the optimization on i386 and reloading ds, es on the lightweight exit path. Reported-by: Chris Clayron <chris2553@googlemail.com> Signed-off-by: Avi Kivity <avi@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c20
1 files changed, 13 insertions, 7 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index c39b60707e02..c00f03de1b79 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1488,13 +1488,6 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
1488 loadsegment(ds, vmx->host_state.ds_sel); 1488 loadsegment(ds, vmx->host_state.ds_sel);
1489 loadsegment(es, vmx->host_state.es_sel); 1489 loadsegment(es, vmx->host_state.es_sel);
1490 } 1490 }
1491#else
1492 /*
1493 * The sysexit path does not restore ds/es, so we must set them to
1494 * a reasonable value ourselves.
1495 */
1496 loadsegment(ds, __USER_DS);
1497 loadsegment(es, __USER_DS);
1498#endif 1491#endif
1499 reload_tss(); 1492 reload_tss();
1500#ifdef CONFIG_X86_64 1493#ifdef CONFIG_X86_64
@@ -6370,6 +6363,19 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
6370#endif 6363#endif
6371 ); 6364 );
6372 6365
6366#ifndef CONFIG_X86_64
6367 /*
6368 * The sysexit path does not restore ds/es, so we must set them to
6369 * a reasonable value ourselves.
6370 *
6371 * We can't defer this to vmx_load_host_state() since that function
6372 * may be executed in interrupt context, which saves and restore segments
6373 * around it, nullifying its effect.
6374 */
6375 loadsegment(ds, __USER_DS);
6376 loadsegment(es, __USER_DS);
6377#endif
6378
6373 vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP) 6379 vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP)
6374 | (1 << VCPU_EXREG_RFLAGS) 6380 | (1 << VCPU_EXREG_RFLAGS)
6375 | (1 << VCPU_EXREG_CPL) 6381 | (1 << VCPU_EXREG_CPL)