]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
KVM: nVMX: Enforce NMI controls on vmentry of L2 guests
authorKrish Sadhukhan <krish.sadhukhan@oracle.com>
Wed, 21 Feb 2018 02:24:39 +0000 (21:24 -0500)
committerRadim Krčmář <rkrcmar@redhat.com>
Thu, 8 Mar 2018 15:54:03 +0000 (16:54 +0100)
According to Intel SDM 26.2.1.1, the following rules should be enforced
on vmentry:

 *  If the "NMI exiting" VM-execution control is 0, "Virtual NMIs"
    VM-execution control must be 0.
 *  If the “virtual NMIs” VM-execution control is 0, the “NMI-window
    exiting” VM-execution control must be 0.

This patch enforces these rules when entering an L2 guest.

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Reviewed-by: Liran Alon <liran.alon@oracle.com>
Reviewed-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
arch/x86/kvm/vmx.c

index 66a77b15e38aba6df4aacf012cbda089f6e79adf..5726cee43f4f4ed03b6cb1ad8499f5d0742dadae 100644 (file)
@@ -1340,6 +1340,16 @@ static inline bool nested_cpu_has_preemption_timer(struct vmcs12 *vmcs12)
                PIN_BASED_VMX_PREEMPTION_TIMER;
 }
 
+static inline bool nested_cpu_has_nmi_exiting(struct vmcs12 *vmcs12)
+{
+       return vmcs12->pin_based_vm_exec_control & PIN_BASED_NMI_EXITING;
+}
+
+static inline bool nested_cpu_has_virtual_nmis(struct vmcs12 *vmcs12)
+{
+       return vmcs12->pin_based_vm_exec_control & PIN_BASED_VIRTUAL_NMIS;
+}
+
 static inline int nested_cpu_has_ept(struct vmcs12 *vmcs12)
 {
        return nested_cpu_has2(vmcs12, SECONDARY_EXEC_ENABLE_EPT);
@@ -5896,8 +5906,7 @@ static bool nested_exit_intr_ack_set(struct kvm_vcpu *vcpu)
 
 static bool nested_exit_on_nmi(struct kvm_vcpu *vcpu)
 {
-       return get_vmcs12(vcpu)->pin_based_vm_exec_control &
-               PIN_BASED_NMI_EXITING;
+       return nested_cpu_has_nmi_exiting(get_vmcs12(vcpu));
 }
 
 static void enable_irq_window(struct kvm_vcpu *vcpu)
@@ -10979,6 +10988,19 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
        return 0;
 }
 
+static int nested_vmx_check_nmi_controls(struct vmcs12 *vmcs12)
+{
+       if (!nested_cpu_has_nmi_exiting(vmcs12) &&
+           nested_cpu_has_virtual_nmis(vmcs12))
+               return -EINVAL;
+
+       if (!nested_cpu_has_virtual_nmis(vmcs12) &&
+           nested_cpu_has(vmcs12, CPU_BASED_VIRTUAL_NMI_PENDING))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -11023,6 +11045,9 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                                vmx->nested.msrs.entry_ctls_high))
                return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
 
+       if (nested_vmx_check_nmi_controls(vmcs12))
+               return VMXERR_ENTRY_INVALID_CONTROL_FIELD;
+
        if (nested_cpu_has_vmfunc(vmcs12)) {
                if (vmcs12->vm_function_control &
                    ~vmx->nested.msrs.vmfunc_controls)