Skip to content

Commit f30cb64

Browse files
yamahatabonzini
authored andcommitted
KVM: TDX: Handle EXCEPTION_NMI and EXTERNAL_INTERRUPT
Handle EXCEPTION_NMI and EXTERNAL_INTERRUPT exits for TDX. NMI Handling: Just like the VMX case, NMI remains blocked after exiting from TDX guest for NMI-induced exits [*]. Handle NMI-induced exits for TDX guests in the same way as they are handled for VMX guests, i.e., handle NMI in tdx_vcpu_enter_exit() by calling the vmx_handle_nmi() helper. Interrupt and Exception Handling: Similar to the VMX case, external interrupts and exceptions (machine check is the only exception type KVM handles for TDX guests) are handled in the .handle_exit_irqoff() callback. For other exceptions, because TDX guest state is protected, exceptions in TDX guests can't be intercepted. TDX VMM isn't supposed to handle these exceptions. If unexpected exception occurs, exit to userspace with KVM_EXIT_EXCEPTION. For external interrupt, increase the statistics, same as the VMX case. [*]: Some old TDX modules have a bug which makes NMI unblocked after exiting from TDX guest for NMI-induced exits. This could potentially lead to nested NMIs: a new NMI arrives when KVM is manually calling the host NMI handler. This is an architectural violation, but it doesn't have real harm until FRED is enabled together with TDX (for non-FRED, the host NMI handler can handle nested NMIs). Given this is rare to happen and has no real harm, ignore this for the initial TDX support. Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> Co-developed-by: Binbin Wu <binbin.wu@linux.intel.com> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-ID: <20250222014757.897978-16-binbin.wu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 7e548b0 commit f30cb64

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

arch/x86/kvm/vmx/tdx.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,8 @@ static noinstr void tdx_vcpu_enter_exit(struct kvm_vcpu *vcpu)
882882
tdx->exit_gpa = tdx->vp_enter_args.r8;
883883
vt->exit_intr_info = tdx->vp_enter_args.r9;
884884

885+
vmx_handle_nmi(vcpu);
886+
885887
guest_state_exit_irqoff();
886888
}
887889

@@ -1028,6 +1030,25 @@ void tdx_inject_nmi(struct kvm_vcpu *vcpu)
10281030
vcpu->arch.nmi_pending = 0;
10291031
}
10301032

1033+
static int tdx_handle_exception_nmi(struct kvm_vcpu *vcpu)
1034+
{
1035+
u32 intr_info = vmx_get_intr_info(vcpu);
1036+
1037+
/*
1038+
* Machine checks are handled by handle_exception_irqoff(), or by
1039+
* tdx_handle_exit() with TDX_NON_RECOVERABLE set if a #MC occurs on
1040+
* VM-Entry. NMIs are handled by tdx_vcpu_enter_exit().
1041+
*/
1042+
if (is_nmi(intr_info) || is_machine_check(intr_info))
1043+
return 1;
1044+
1045+
vcpu->run->exit_reason = KVM_EXIT_EXCEPTION;
1046+
vcpu->run->ex.exception = intr_info & INTR_INFO_VECTOR_MASK;
1047+
vcpu->run->ex.error_code = 0;
1048+
1049+
return 0;
1050+
}
1051+
10311052
static int complete_hypercall_exit(struct kvm_vcpu *vcpu)
10321053
{
10331054
tdvmcall_set_return_code(vcpu, vcpu->run->hypercall.ret);
@@ -1724,6 +1745,11 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
17241745
vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
17251746
vcpu->mmio_needed = 0;
17261747
return 0;
1748+
case EXIT_REASON_EXCEPTION_NMI:
1749+
return tdx_handle_exception_nmi(vcpu);
1750+
case EXIT_REASON_EXTERNAL_INTERRUPT:
1751+
++vcpu->stat.irq_exits;
1752+
return 1;
17271753
case EXIT_REASON_TDCALL:
17281754
return handle_tdvmcall(vcpu);
17291755
case EXIT_REASON_VMCALL:

arch/x86/kvm/vmx/vmx.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6961,9 +6961,7 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu,
69616961

69626962
void vmx_handle_exit_irqoff(struct kvm_vcpu *vcpu)
69636963
{
6964-
struct vcpu_vmx *vmx = to_vmx(vcpu);
6965-
6966-
if (vmx->vt.emulation_required)
6964+
if (to_vt(vcpu)->emulation_required)
69676965
return;
69686966

69696967
if (vmx_get_exit_reason(vcpu).basic == EXIT_REASON_EXTERNAL_INTERRUPT)

0 commit comments

Comments
 (0)