summaryrefslogtreecommitdiff
path: root/arch/x86/kvm
diff options
context:
space:
mode:
authorSean Christopherson <sean.j.christopherson@intel.com>2018-07-23 22:32:50 +0300
committerPaolo Bonzini <pbonzini@redhat.com>2018-08-06 18:59:17 +0300
commit5e079c7ece1060491ef4a45414823162cce91b3d (patch)
tree31374e01961924f1ff4d32535f4677812623b975 /arch/x86/kvm
parent8f21a0bbf36f58334695ae6e46c0cf906a217154 (diff)
downloadlinux-5e079c7ece1060491ef4a45414823162cce91b3d.tar.xz
KVM: vmx: skip VMWRITE of HOST_{FS,GS}_BASE when possible
The host's FS.base and GS.base rarely change, e.g. ~0.1% of host/guest swaps on my system. Cache the last value written to the VMCS and skip the VMWRITE to the associated VMCS fields when loading host state if the value hasn't changed since the last VMWRITE. Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm')
-rw-r--r--arch/x86/kvm/vmx.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 4937e11f971a..b23ecc04ca51 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -226,6 +226,8 @@ struct vmcs {
struct vmcs_host_state {
unsigned long cr3; /* May not match real cr3 */
unsigned long cr4; /* May not match real cr4 */
+ unsigned long gs_base;
+ unsigned long fs_base;
u16 fs_sel, gs_sel, ldt_sel;
#ifdef CONFIG_X86_64
@@ -2731,9 +2733,14 @@ static void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
vmcs_write16(HOST_GS_SELECTOR, 0);
host_state->gs_sel = gs_sel;
}
-
- vmcs_writel(HOST_FS_BASE, fs_base);
- vmcs_writel(HOST_GS_BASE, gs_base);
+ if (unlikely(fs_base != host_state->fs_base)) {
+ vmcs_writel(HOST_FS_BASE, fs_base);
+ host_state->fs_base = fs_base;
+ }
+ if (unlikely(gs_base != host_state->gs_base)) {
+ vmcs_writel(HOST_GS_BASE, gs_base);
+ host_state->gs_base = gs_base;
+ }
for (i = 0; i < vmx->save_nmsrs; ++i)
kvm_set_shared_msr(vmx->guest_msrs[i].index,