KVM: nVMX: invvpid handling improvements
authorJan Dakinevich <jan.dakinevich@gmail.com>
Fri, 28 Oct 2016 04:00:30 +0000 (07:00 +0300)
committerRadim Krčmář <rkrcmar@redhat.com>
Tue, 22 Nov 2016 16:26:42 +0000 (17:26 +0100)
 - Expose all invalidation types to the L1

 - Reject invvpid instruction, if L1 passed zero vpid value to single
   context invalidations

Signed-off-by: Jan Dakinevich <jan.dakinevich@gmail.com>
Tested-by: Ladi Prosek <lprosek@redhat.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/vmx.c

index f81a8e4..0e86219 100644 (file)
@@ -132,6 +132,12 @@ module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO);
 
 #define VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE 5
 
+#define VMX_VPID_EXTENT_SUPPORTED_MASK         \
+       (VMX_VPID_EXTENT_INDIVIDUAL_ADDR_BIT |  \
+       VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |    \
+       VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT |    \
+       VMX_VPID_EXTENT_SINGLE_NON_GLOBAL_BIT)
+
 /*
  * These 2 parameters are used to config the controls for Pause-Loop Exiting:
  * ple_gap:    upper bound on the amount of time between two successive
@@ -2834,8 +2840,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
         */
        if (enable_vpid)
                vmx->nested.nested_vmx_vpid_caps = VMX_VPID_INVVPID_BIT |
-                               VMX_VPID_EXTENT_SINGLE_CONTEXT_BIT |
-                               VMX_VPID_EXTENT_GLOBAL_CONTEXT_BIT;
+                       VMX_VPID_EXTENT_SUPPORTED_MASK;
        else
                vmx->nested.nested_vmx_vpid_caps = 0;
 
@@ -7597,7 +7602,8 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
        vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
        type = kvm_register_readl(vcpu, (vmx_instruction_info >> 28) & 0xf);
 
-       types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
+       types = (vmx->nested.nested_vmx_vpid_caps &
+                       VMX_VPID_EXTENT_SUPPORTED_MASK) >> 8;
 
        if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
@@ -7619,21 +7625,27 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
        }
 
        switch (type) {
+       case VMX_VPID_EXTENT_INDIVIDUAL_ADDR:
        case VMX_VPID_EXTENT_SINGLE_CONTEXT:
-               /*
-                * Old versions of KVM use the single-context version so we
-                * have to support it; just treat it the same as all-context.
-                */
+       case VMX_VPID_EXTENT_SINGLE_NON_GLOBAL:
+               if (!vpid) {
+                       nested_vmx_failValid(vcpu,
+                               VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
+                       skip_emulated_instruction(vcpu);
+                       return 1;
+               }
+               break;
        case VMX_VPID_EXTENT_ALL_CONTEXT:
-               __vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
-               nested_vmx_succeed(vcpu);
                break;
        default:
-               /* Trap individual address invalidation invvpid calls */
-               BUG_ON(1);
-               break;
+               WARN_ON_ONCE(1);
+               skip_emulated_instruction(vcpu);
+               return 1;
        }
 
+       __vmx_flush_tlb(vcpu, vmx->nested.vpid02);
+       nested_vmx_succeed(vcpu);
+
        skip_emulated_instruction(vcpu);
        return 1;
 }