Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Isaku Yamahata and committed by
Paolo Bonzini
da407fe4 6c441e4d

+47
+47
arch/x86/kvm/vmx/tdx.c
··· 859 859 return EXIT_REASON_VMCALL; 860 860 861 861 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; 862 868 default: 863 869 break; 864 870 } ··· 999 993 tdx->guest_entered = true; 1000 994 1001 995 vcpu->arch.regs_avail &= TDX_REGS_AVAIL_SET; 996 + 997 + if (unlikely(tdx->vp_enter_ret == EXIT_REASON_EPT_MISCONFIG)) 998 + return EXIT_FASTPATH_NONE; 1002 999 1003 1000 if (unlikely((tdx->vp_enter_ret & TDX_SW_ERROR) == TDX_SW_ERROR)) 1004 1001 return EXIT_FASTPATH_NONE; ··· 1709 1700 trace_kvm_apicv_accept_irq(vcpu->vcpu_id, delivery_mode, trig_mode, vector); 1710 1701 } 1711 1702 1703 + static int tdx_handle_ept_violation(struct kvm_vcpu *vcpu) 1704 + { 1705 + unsigned long exit_qual; 1706 + gpa_t gpa = to_tdx(vcpu)->exit_gpa; 1707 + 1708 + if (vt_is_tdx_private_gpa(vcpu->kvm, gpa)) { 1709 + /* 1710 + * Always treat SEPT violations as write faults. Ignore the 1711 + * EXIT_QUALIFICATION reported by TDX-SEAM for SEPT violations. 1712 + * TD private pages are always RWX in the SEPT tables, 1713 + * i.e. they're always mapped writable. Just as importantly, 1714 + * treating SEPT violations as write faults is necessary to 1715 + * avoid COW allocations, which will cause TDAUGPAGE failures 1716 + * due to aliasing a single HPA to multiple GPAs. 1717 + */ 1718 + exit_qual = EPT_VIOLATION_ACC_WRITE; 1719 + } else { 1720 + exit_qual = vmx_get_exit_qual(vcpu); 1721 + /* 1722 + * EPT violation due to instruction fetch should never be 1723 + * triggered from shared memory in TDX guest. If such EPT 1724 + * violation occurs, treat it as broken hardware. 1725 + */ 1726 + if (KVM_BUG_ON(exit_qual & EPT_VIOLATION_ACC_INSTR, vcpu->kvm)) 1727 + return -EIO; 1728 + } 1729 + 1730 + trace_kvm_page_fault(vcpu, gpa, exit_qual); 1731 + return __vmx_handle_ept_violation(vcpu, gpa, exit_qual); 1732 + } 1733 + 1712 1734 int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath) 1713 1735 { 1714 1736 struct vcpu_tdx *tdx = to_tdx(vcpu); ··· 1748 1708 1749 1709 if (fastpath != EXIT_FASTPATH_NONE) 1750 1710 return 1; 1711 + 1712 + if (unlikely(vp_enter_ret == EXIT_REASON_EPT_MISCONFIG)) { 1713 + KVM_BUG_ON(1, vcpu->kvm); 1714 + return -EIO; 1715 + } 1751 1716 1752 1717 /* 1753 1718 * Handle TDX SW errors, including TDX_SEAMCALL_UD, TDX_SEAMCALL_GP and ··· 1803 1758 return tdx_emulate_io(vcpu); 1804 1759 case EXIT_REASON_EPT_MISCONFIG: 1805 1760 return tdx_emulate_mmio(vcpu); 1761 + case EXIT_REASON_EPT_VIOLATION: 1762 + return tdx_handle_ept_violation(vcpu); 1806 1763 case EXIT_REASON_OTHER_SMI: 1807 1764 /* 1808 1765 * Unlike VMX, SMI in SEAM non-root mode (i.e. when