On 07/05/19 18:06, Sean Christopherson wrote: > When switching between vmcs01 and vmcs02, KVM isn't actually switching > between guest and host. If guest state is already loaded (the likely, > if not guaranteed, case), keep the guest state loaded and manually swap > the loaded_cpu_state pointer after propagating saved host state to the > new vmcs0{1,2}. > > Avoiding the switch between guest and host reduces the latency of > switching between vmcs01 and vmcs02 by several hundred cycles, and > reduces the roundtrip time of a nested VM by upwards of 1000 cycles. > > Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> > --- > arch/x86/kvm/vmx/nested.c | 18 +++++++++++++- > arch/x86/kvm/vmx/vmx.c | 52 ++++++++++++++++++++++----------------- > arch/x86/kvm/vmx/vmx.h | 3 ++- > 3 files changed, 48 insertions(+), 25 deletions(-) > > diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c > index a30d53823b2e..4651d3462df4 100644 > --- a/arch/x86/kvm/vmx/nested.c > +++ b/arch/x86/kvm/vmx/nested.c > @@ -241,15 +241,31 @@ static void free_nested(struct kvm_vcpu *vcpu) > static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) > { > struct vcpu_vmx *vmx = to_vmx(vcpu); > + struct vmcs_host_state *src; > + struct loaded_vmcs *prev; > int cpu; > > if (vmx->loaded_vmcs == vmcs) > return; > > cpu = get_cpu(); > - vmx_vcpu_put(vcpu); > + prev = vmx->loaded_cpu_state; > vmx->loaded_vmcs = vmcs; > vmx_vcpu_load(vcpu, cpu); > + > + if (likely(prev)) { > + src = &prev->host_state; > + > + vmx_set_host_fs_gs(&vmcs->host_state, src->fs_sel, src->gs_sel, > + src->fs_base, src->gs_base); > + > + vmcs->host_state.ldt_sel = src->ldt_sel; > +#ifdef CONFIG_X86_64 > + vmcs->host_state.ds_sel = src->ds_sel; > + vmcs->host_state.es_sel = src->es_sel; > +#endif > + vmx->loaded_cpu_state = vmcs; > + } > put_cpu(); I'd like to extract this into a separate function: diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 438fae1fef2a..83e436f201bf 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -248,34 +248,40 @@ static void free_nested(struct kvm_vcpu *vcpu) free_loaded_vmcs(&vmx->nested.vmcs02); } +static void vmx_sync_vmcs_host_state(struct vcpu_vmx *vmx) +{ + struct loaded_vmcs *prev = vmx->loaded_cpu_state; + struct loaded_vmcs *cur; + struct vmcs_host_state *dest, *src; + + if (unlikely(!prev)) + return; + + cur = &vmx->loaded_vmcs; + src = &prev->host_state; + dest = &cur->host_state; + + vmx_set_host_fs_gs(dest, src->fs_sel, src->gs_sel, src->fs_base, src->gs_base); + dest->ldt_sel = src->ldt_sel; +#ifdef CONFIG_X86_64 + dest->ds_sel = src->ds_sel; + dest->es_sel = src->es_sel; +#endif + vmx->loaded_cpu_state = cur; +} + static void vmx_switch_vmcs(struct kvm_vcpu *vcpu, struct loaded_vmcs *vmcs) { struct vcpu_vmx *vmx = to_vmx(vcpu); - struct vmcs_host_state *src; - struct loaded_vmcs *prev; int cpu; if (vmx->loaded_vmcs == vmcs) return; cpu = get_cpu(); - prev = vmx->loaded_cpu_state; vmx->loaded_vmcs = vmcs; vmx_vcpu_load(vcpu, cpu); - - if (likely(prev)) { - src = &prev->host_state; - - vmx_set_host_fs_gs(&vmcs->host_state, src->fs_sel, src->gs_sel, - src->fs_base, src->gs_base); - - vmcs->host_state.ldt_sel = src->ldt_sel; -#ifdef CONFIG_X86_64 - vmcs->host_state.ds_sel = src->ds_sel; - vmcs->host_state.es_sel = src->es_sel; -#endif - vmx->loaded_cpu_state = vmcs; - } + vmx_sync_vmcs_host_state(vmx); put_cpu(); vm_entry_controls_reset_shadow(vmx); Paolo