kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Optimize ds/es reload
@ 2012-05-13 16:53 Avi Kivity
  2012-05-13 16:53 ` [PATCH 1/2] KVM: VMX: Fix %ds/%es clobber Avi Kivity
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Avi Kivity @ 2012-05-13 16:53 UTC (permalink / raw)
  To: Marcelo Tosatti, kvm

The lightweight exit path needlessly reloads %ds and %es (and clobbers the
user supplied values as well, a minor ABI bug).  This patchset fixes the bug
and moves the reload to the heavyweight exit path (potentially skipping it
completely on x86_64), reducing the vmexit cost by about 70 cycles.

Avi Kivity (2):
  KVM: VMX: Fix %ds/%es clobber
  KVM: VMX: Optimize %ds, %es reload

 arch/x86/kvm/vmx.c |   32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

-- 
1.7.10.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/2] KVM: VMX: Fix %ds/%es clobber
  2012-05-13 16:53 [PATCH 0/2] Optimize ds/es reload Avi Kivity
@ 2012-05-13 16:53 ` Avi Kivity
  2012-05-13 16:53 ` [PATCH 2/2] KVM: VMX: Optimize %ds, %es reload Avi Kivity
  2012-05-16 19:04 ` [PATCH 0/2] Optimize ds/es reload Marcelo Tosatti
  2 siblings, 0 replies; 4+ messages in thread
From: Avi Kivity @ 2012-05-13 16:53 UTC (permalink / raw)
  To: Marcelo Tosatti, kvm

The vmx exit code unconditionally restores %ds and %es to __USER_DS.  This
can override the user's values, since %ds and %es are not saved and restored
in x86_64 syscalls.  In practice, this isn't dangerous since nobody uses
segment registers in long mode, least of all programs that use KVM.

Signed-off-by: Avi Kivity <avi@redhat.com>
---
 arch/x86/kvm/vmx.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 61ebdb6..16edeea 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -6102,7 +6102,10 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	u16 _ds, _es;
 
+	savesegment(ds, _ds);
+	savesegment(es, _es);
 	if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) {
 		struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 		if (vmcs12->idt_vectoring_info_field &
@@ -6263,7 +6266,8 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 		}
 	}
 
-	asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS));
+	loadsegment(ds, _ds);
+	loadsegment(es, _es);
 	vmx->loaded_vmcs->launched = 1;
 
 	vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
-- 
1.7.10.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] KVM: VMX: Optimize %ds, %es reload
  2012-05-13 16:53 [PATCH 0/2] Optimize ds/es reload Avi Kivity
  2012-05-13 16:53 ` [PATCH 1/2] KVM: VMX: Fix %ds/%es clobber Avi Kivity
@ 2012-05-13 16:53 ` Avi Kivity
  2012-05-16 19:04 ` [PATCH 0/2] Optimize ds/es reload Marcelo Tosatti
  2 siblings, 0 replies; 4+ messages in thread
From: Avi Kivity @ 2012-05-13 16:53 UTC (permalink / raw)
  To: Marcelo Tosatti, kvm

On x86_64, we can defer %ds and %es reload to the heavyweight context switch,
since nothing in the lightweight paths uses the host %ds or %es (they are
ignored by the processor).  Furthermore we can avoid the load if the segments
are null, by letting the hardware load the null segments for us.  This is the
expected case.

On i386, we could avoid the reload entirely, since the entry.S paths take care
of reload, except for the SYSEXIT path which leaves %ds and %es set to __USER_DS.
So we set them to the same values as well.

Saves about 70 cycles out of 1600 (around 4%; noisy measurements).

Signed-off-by: Avi Kivity <avi@redhat.com>
---
 arch/x86/kvm/vmx.c |   36 +++++++++++++++++++++++++++++++-----
 1 file changed, 31 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 16edeea..4c7d4cc 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -393,6 +393,9 @@ struct vcpu_vmx {
 	struct {
 		int           loaded;
 		u16           fs_sel, gs_sel, ldt_sel;
+#ifdef CONFIG_X86_64
+		u16           ds_sel, es_sel;
+#endif
 		int           gs_ldt_reload_needed;
 		int           fs_reload_needed;
 	} host_state;
@@ -1418,6 +1421,11 @@ static void vmx_save_host_state(struct kvm_vcpu *vcpu)
 	}
 
 #ifdef CONFIG_X86_64
+	savesegment(ds, vmx->host_state.ds_sel);
+	savesegment(es, vmx->host_state.es_sel);
+#endif
+
+#ifdef CONFIG_X86_64
 	vmcs_writel(HOST_FS_BASE, read_msr(MSR_FS_BASE));
 	vmcs_writel(HOST_GS_BASE, read_msr(MSR_GS_BASE));
 #else
@@ -1457,6 +1465,19 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
 	}
 	if (vmx->host_state.fs_reload_needed)
 		loadsegment(fs, vmx->host_state.fs_sel);
+#ifdef CONFIG_X86_64
+	if (unlikely(vmx->host_state.ds_sel | vmx->host_state.es_sel)) {
+		loadsegment(ds, vmx->host_state.ds_sel);
+		loadsegment(es, vmx->host_state.es_sel);
+	}
+#else
+	/*
+	 * The sysexit path does not restore ds/es, so we must set them to
+	 * a reasonable value ourselves.
+	 */
+	loadsegment(ds, __USER_DS);
+	loadsegment(es, __USER_DS);
+#endif
 	reload_tss();
 #ifdef CONFIG_X86_64
 	wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base);
@@ -3640,8 +3661,18 @@ static void vmx_set_constant_host_state(void)
 	vmcs_writel(HOST_CR3, read_cr3());  /* 22.2.3  FIXME: shadow tables */
 
 	vmcs_write16(HOST_CS_SELECTOR, __KERNEL_CS);  /* 22.2.4 */
+#ifdef CONFIG_X86_64
+	/*
+	 * Load null selectors, so we can avoid reloading them in
+	 * __vmx_load_host_state(), in case userspace uses the null selectors
+	 * too (the expected case).
+	 */
+	vmcs_write16(HOST_DS_SELECTOR, 0);
+	vmcs_write16(HOST_ES_SELECTOR, 0);
+#else
 	vmcs_write16(HOST_DS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
 	vmcs_write16(HOST_ES_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
+#endif
 	vmcs_write16(HOST_SS_SELECTOR, __KERNEL_DS);  /* 22.2.4 */
 	vmcs_write16(HOST_TR_SELECTOR, GDT_ENTRY_TSS*8);  /* 22.2.4 */
 
@@ -6102,10 +6133,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
-	u16 _ds, _es;
 
-	savesegment(ds, _ds);
-	savesegment(es, _es);
 	if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) {
 		struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
 		if (vmcs12->idt_vectoring_info_field &
@@ -6266,8 +6294,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 		}
 	}
 
-	loadsegment(ds, _ds);
-	loadsegment(es, _es);
 	vmx->loaded_vmcs->launched = 1;
 
 	vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
-- 
1.7.10.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 0/2] Optimize ds/es reload
  2012-05-13 16:53 [PATCH 0/2] Optimize ds/es reload Avi Kivity
  2012-05-13 16:53 ` [PATCH 1/2] KVM: VMX: Fix %ds/%es clobber Avi Kivity
  2012-05-13 16:53 ` [PATCH 2/2] KVM: VMX: Optimize %ds, %es reload Avi Kivity
@ 2012-05-16 19:04 ` Marcelo Tosatti
  2 siblings, 0 replies; 4+ messages in thread
From: Marcelo Tosatti @ 2012-05-16 19:04 UTC (permalink / raw)
  To: Avi Kivity; +Cc: kvm

On Sun, May 13, 2012 at 07:53:22PM +0300, Avi Kivity wrote:
> The lightweight exit path needlessly reloads %ds and %es (and clobbers the
> user supplied values as well, a minor ABI bug).  This patchset fixes the bug
> and moves the reload to the heavyweight exit path (potentially skipping it
> completely on x86_64), reducing the vmexit cost by about 70 cycles.
> 
> Avi Kivity (2):
>   KVM: VMX: Fix %ds/%es clobber
>   KVM: VMX: Optimize %ds, %es reload
> 
>  arch/x86/kvm/vmx.c |   32 +++++++++++++++++++++++++++++++-
>  1 file changed, 31 insertions(+), 1 deletion(-)

Applied, thanks.


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2012-05-16 19:08 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-13 16:53 [PATCH 0/2] Optimize ds/es reload Avi Kivity
2012-05-13 16:53 ` [PATCH 1/2] KVM: VMX: Fix %ds/%es clobber Avi Kivity
2012-05-13 16:53 ` [PATCH 2/2] KVM: VMX: Optimize %ds, %es reload Avi Kivity
2012-05-16 19:04 ` [PATCH 0/2] Optimize ds/es reload Marcelo Tosatti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).