Skip to content

Commit da407fe

Browse files
yamahatabonzini
authored andcommitted
KVM: TDX: Handle EPT violation/misconfig exit
For TDX, on EPT violation, call common __vmx_handle_ept_violation() to trigger x86 MMU code; on EPT misconfiguration, bug the VM since it shouldn't happen. EPT violation due to instruction fetch should never be triggered from shared memory in TDX guest. If such EPT violation occurs, treat it as broken hardware. EPT misconfiguration shouldn't happen on neither shared nor secure EPT for TDX guests. - TDX module guarantees no EPT misconfiguration on secure EPT. Per TDX module v1.5 spec section 9.4 "Secure EPT Induced TD Exits": "By design, since secure EPT is fully controlled by the TDX module, an EPT misconfiguration on a private GPA indicates a TDX module bug and is handled as a fatal error." - For shared EPT, the MMIO caching optimization, which is the only case where current KVM configures EPT entries to generate EPT misconfiguration, is implemented in a different way for TDX guests. KVM configures EPT entries to non-present value without suppressing #VE bit. It causes #VE in the TDX guest and the guest will call TDG.VP.VMCALL to request MMIO emulation. Suggested-by: Sean Christopherson <seanjc@google.com> Signed-off-by: Isaku Yamahata <isaku.yamahata@intel.com> Co-developed-by: Adrian Hunter <adrian.hunter@intel.com> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com> [binbin: rework changelog] Co-developed-by: Binbin Wu <binbin.wu@linux.intel.com> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com> Message-ID: <20250227012021.1778144-2-binbin.wu@linux.intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 6c441e4 commit da407fe

File tree

1 file changed

+47
-0
lines changed

1 file changed

+47
-0
lines changed

arch/x86/kvm/vmx/tdx.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,12 @@ static __always_inline u32 tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
859859
return EXIT_REASON_VMCALL;
860860

861861
return tdcall_to_vmx_exit_reason(vcpu);
862+
case EXIT_REASON_EPT_MISCONFIG:
863+
/*
864+
* Defer KVM_BUG_ON() until tdx_handle_exit() because this is in
865+
* non-instrumentable code with interrupts disabled.
866+
*/
867+
return -1u;
862868
default:
863869
break;
864870
}
@@ -994,6 +1000,9 @@ fastpath_t tdx_vcpu_run(struct kvm_vcpu *vcpu, bool force_immediate_exit)
9941000

9951001
vcpu->arch.regs_avail &= TDX_REGS_AVAIL_SET;
9961002

1003+
if (unlikely(tdx->vp_enter_ret == EXIT_REASON_EPT_MISCONFIG))
1004+
return EXIT_FASTPATH_NONE;
1005+
9971006
if (unlikely((tdx->vp_enter_ret & TDX_SW_ERROR) == TDX_SW_ERROR))
9981007
return EXIT_FASTPATH_NONE;
9991008

@@ -1700,6 +1709,37 @@ void tdx_deliver_interrupt(struct kvm_lapic *apic, int delivery_mode,
17001709
trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode, trig_mode, vector);
17011710
}
17021711

1712+
static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu)
1713+
{
1714+
unsigned long exit_qual;
1715+
gpa_t gpa = to_tdx(vcpu)->exit_gpa;
1716+
1717+
if (vt_is_tdx_private_gpa(vcpu->kvm, gpa)) {
1718+
/*
1719+
* Always treat SEPT violations as write faults. Ignore the
1720+
* EXIT_QUALIFICATION reported by TDX-SEAM for SEPT violations.
1721+
* TD private pages are always RWX in the SEPT tables,
1722+
* i.e. they're always mapped writable. Just as importantly,
1723+
* treating SEPT violations as write faults is necessary to
1724+
* avoid COW allocations, which will cause TDAUGPAGE failures
1725+
* due to aliasing a single HPA to multiple GPAs.
1726+
*/
1727+
exit_qual = EPT_VIOLATION_ACC_WRITE;
1728+
} else {
1729+
exit_qual = vmx_get_exit_qual(vcpu);
1730+
/*
1731+
* EPT violation due to instruction fetch should never be
1732+
* triggered from shared memory in TDX guest. If such EPT
1733+
* violation occurs, treat it as broken hardware.
1734+
*/
1735+
if (KVM_BUG_ON(exit_qual & EPT_VIOLATION_ACC_INSTR, vcpu->kvm))
1736+
return -EIO;
1737+
}
1738+
1739+
trace_kvm_page_fault(vcpu, gpa, exit_qual);
1740+
return __vmx_handle_ept_violation(vcpu, gpa, exit_qual);
1741+
}
1742+
17031743
int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
17041744
{
17051745
struct vcpu_tdx *tdx = to_tdx(vcpu);
@@ -1709,6 +1749,11 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
17091749
if (fastpath != EXIT_FASTPATH_NONE)
17101750
return 1;
17111751

1752+
if (unlikely(vp_enter_ret == EXIT_REASON_EPT_MISCONFIG)) {
1753+
KVM_BUG_ON(1, vcpu->kvm);
1754+
return -EIO;
1755+
}
1756+
17121757
/*
17131758
* Handle TDX SW errors, including TDX_SEAMCALL_UD, TDX_SEAMCALL_GP and
17141759
* TDX_SEAMCALL_VMFAILINVALID.
@@ -1758,6 +1803,8 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
17581803
return tdx_emulate_io(vcpu);
17591804
case EXIT_REASON_EPT_MISCONFIG:
17601805
return tdx_emulate_mmio(vcpu);
1806+
case EXIT_REASON_EPT_VIOLATION:
1807+
return tdx_handle_ept_violation(vcpu);
17611808
case EXIT_REASON_OTHER_SMI:
17621809
/*
17631810
* Unlike VMX, SMI in SEAM non-root mode (i.e. when

0 commit comments

Comments
 (0)