diff options
author | Sean Christopherson <sean.j.christopherson@intel.com> | 2019-05-07 08:36:28 -0700 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2019-06-18 11:46:47 +0200 |
commit | e2174295b41d8c9115ab246a630d4630724a2cd5 (patch) | |
tree | 3da02ceb03368594324e6ff8c638502e718af5a7 /arch/x86/kvm/vmx/nested.c | |
parent | 3731905ef28fc1a9240d1532b2a9efbaea205dc0 (diff) | |
download | lwn-e2174295b41d8c9115ab246a630d4630724a2cd5.tar.gz lwn-e2174295b41d8c9115ab246a630d4630724a2cd5.zip |
KVM: nVMX: Add helpers to identify shadowed VMCS fields
So that future optimizations related to shadowed fields don't need to
define their own switch statement.
Add a BUILD_BUG_ON() to ensure at least one of the types (RW vs RO) is
defined when including vmcs_shadow_fields.h (guess who keeps mistyping
SHADOW_FIELD_RO as SHADOW_FIELD_R0).
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx/nested.c')
-rw-r--r-- | arch/x86/kvm/vmx/nested.c | 71 |
1 files changed, 40 insertions, 31 deletions
diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index fc2b8f4cf45f..0d9a239b9df9 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -4420,6 +4420,29 @@ static int handle_vmread(struct kvm_vcpu *vcpu) return nested_vmx_succeed(vcpu); } +static bool is_shadow_field_rw(unsigned long field) +{ + switch (field) { +#define SHADOW_FIELD_RW(x, y) case x: +#include "vmcs_shadow_fields.h" + return true; + default: + break; + } + return false; +} + +static bool is_shadow_field_ro(unsigned long field) +{ + switch (field) { +#define SHADOW_FIELD_RO(x, y) case x: +#include "vmcs_shadow_fields.h" + return true; + default: + break; + } + return false; +} static int handle_vmwrite(struct kvm_vcpu *vcpu) { @@ -4503,41 +4526,27 @@ static int handle_vmwrite(struct kvm_vcpu *vcpu) vmcs12_write_any(vmcs12, field, offset, field_value); /* - * Do not track vmcs12 dirty-state if in guest-mode - * as we actually dirty shadow vmcs12 instead of vmcs12. + * Do not track vmcs12 dirty-state if in guest-mode as we actually + * dirty shadow vmcs12 instead of vmcs12. Fields that can be updated + * by L1 without a vmexit are always updated in the vmcs02, i.e. don't + * "dirty" vmcs12, all others go down the prepare_vmcs02() slow path. */ - if (!is_guest_mode(vcpu)) { - switch (field) { -#define SHADOW_FIELD_RW(x, y) case x: -#include "vmcs_shadow_fields.h" - /* - * The fields that can be updated by L1 without a vmexit are - * always updated in the vmcs02, the others go down the slow - * path of prepare_vmcs02. - */ - break; - -#define SHADOW_FIELD_RO(x, y) case x: -#include "vmcs_shadow_fields.h" - /* - * L1 can read these fields without exiting, ensure the - * shadow VMCS is up-to-date. - */ - if (enable_shadow_vmcs) { - preempt_disable(); - vmcs_load(vmx->vmcs01.shadow_vmcs); + if (!is_guest_mode(vcpu) && !is_shadow_field_rw(field)) { + /* + * L1 can read these fields without exiting, ensure the + * shadow VMCS is up-to-date. + */ + if (enable_shadow_vmcs && is_shadow_field_ro(field)) { + preempt_disable(); + vmcs_load(vmx->vmcs01.shadow_vmcs); - __vmcs_writel(field, field_value); + __vmcs_writel(field, field_value); - vmcs_clear(vmx->vmcs01.shadow_vmcs); - vmcs_load(vmx->loaded_vmcs->vmcs); - preempt_enable(); - } - /* fall through */ - default: - vmx->nested.dirty_vmcs12 = true; - break; + vmcs_clear(vmx->vmcs01.shadow_vmcs); + vmcs_load(vmx->loaded_vmcs->vmcs); + preempt_enable(); } + vmx->nested.dirty_vmcs12 = true; } return nested_vmx_succeed(vcpu); |