[PATCH v4 07/11] KVM: VMX: Handle NMI Source report in VM exit

Jacob Pan posted 11 patches 1 year, 5 months ago
[PATCH v4 07/11] KVM: VMX: Handle NMI Source report in VM exit
Posted by Jacob Pan 1 year, 5 months ago
From: Zeng Guang <guang.zeng@intel.com>

If the "NMI exiting" VM-execution control is 1, the value of the 16-bit NMI
source vector is saved in the exit-qualification field in the VMCS when VM
exits occur on CPUs that support NMI source.

KVM that is aware of NMI-source reporting will push the bitmask of NMI source
vectors as the exceptoin event data field on the stack for then entry of FRED
exception. Subsequently, the host NMI exception handler is invoked which
will process NMI source information in the event data. This operation is
independent of vCPU FRED enabling status.

Signed-off-by: Zeng Guang <guang.zeng@intel.com>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
---
 arch/x86/kvm/vmx/vmx.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 4e7b36081b76..6719c598fa5f 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7331,10 +7331,15 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
 	if ((u16)vmx->exit_reason.basic == EXIT_REASON_EXCEPTION_NMI &&
 	    is_nmi(vmx_get_intr_info(vcpu))) {
 		kvm_before_interrupt(vcpu, KVM_HANDLING_NMI);
-		if (cpu_feature_enabled(X86_FEATURE_FRED))
-			fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR, 0);
-		else
+		if (cpu_feature_enabled(X86_FEATURE_FRED)) {
+			unsigned long edata = 0;
+
+			if (cpu_feature_enabled(X86_FEATURE_NMI_SOURCE))
+				edata = vmx_get_exit_qual(vcpu);
+			fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR, edata);
+		} else {
 			vmx_do_nmi_irqoff();
+		}
 		kvm_after_interrupt(vcpu);
 	}
 
-- 
2.25.1
Re: [PATCH v4 07/11] KVM: VMX: Handle NMI Source report in VM exit
Posted by Sean Christopherson 1 year, 3 months ago
On Tue, Jul 09, 2024, Jacob Pan wrote:
> From: Zeng Guang <guang.zeng@intel.com>
> 
> If the "NMI exiting" VM-execution control is 1, the value of the 16-bit NMI
> source vector is saved in the exit-qualification field in the VMCS when VM
> exits occur on CPUs that support NMI source.
> 
> KVM that is aware of NMI-source reporting will push the bitmask of NMI source
> vectors as the exceptoin event data field on the stack for then entry of FRED
> exception. Subsequently, the host NMI exception handler is invoked which
> will process NMI source information in the event data. This operation is
> independent of vCPU FRED enabling status.
> 
> Signed-off-by: Zeng Guang <guang.zeng@intel.com>
> Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
> ---
>  arch/x86/kvm/vmx/vmx.c | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index 4e7b36081b76..6719c598fa5f 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -7331,10 +7331,15 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
>  	if ((u16)vmx->exit_reason.basic == EXIT_REASON_EXCEPTION_NMI &&
>  	    is_nmi(vmx_get_intr_info(vcpu))) {
>  		kvm_before_interrupt(vcpu, KVM_HANDLING_NMI);
> -		if (cpu_feature_enabled(X86_FEATURE_FRED))
> -			fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR, 0);
> -		else
> +		if (cpu_feature_enabled(X86_FEATURE_FRED)) {
> +			unsigned long edata = 0;
> +
> +			if (cpu_feature_enabled(X86_FEATURE_NMI_SOURCE))
> +				edata = vmx_get_exit_qual(vcpu);
> +			fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR, edata);

Eh, I would just east the extra VMREAD if KVM happens to run on a CPU that supports
FRED but not NMI source reporting.  Per spec 7.0, the EXIT_QUALIFICATION is 0 if
NMI source isn't supported, i.e. it's guaranteed to not cause functional problems.

I assume there won't be many (any?) CPUs with FRED but not NMI_SOURCE (and if there
are, why!?!?!).  On the other hand, gating this on NMI_SOURCE means KVM will need
another update if some other event data is ever added for NMIs.  And readers don't
have to hunt through the FRED spec with a fine-toothed comb to suss out that
EXIT_QUALIFICATION == event data, but that KVM is getting cute and only reading
it when it can be non-zero (as far as KVM knows).

As a bonus, the code is less ugly:

		if (cpu_feature_enabled(X86_FEATURE_FRED))
			fred_entry_from_kvm(EVENT_TYPE_NMI, NMI_VECTOR,
					    vmx_get_exit_qual(vcpu));
		else
			vmx_do_nmi_irqoff();

> +		} else {
>  			vmx_do_nmi_irqoff();
> +		}
>  		kvm_after_interrupt(vcpu);
>  	}
>  
> -- 
> 2.25.1
>