[PATCH v3 4/4] KVM: TDX: Enable Bus Lock VM exit
From: Xiaoyao Li
Date: Wed Aug 12 2026 - 04:14:36 EST
Enable Bus Lock VM exit functionality for TDX guests.
Bus Lock VM exit is an existing feature supported by KVM. Userspace can
enable Bus Lock VM exit through KVM_BUS_LOCK_DETECTION_EXIT when it's
reported as supported. However, KVM reports the support of this CAP
just based on the hardware capability but doesn't differentiate between
VMX and TDX. This leads to the issue that userspace can enable this cap
for TDX guests without getting an error, but the feature is not actually
enabled because KVM doesn't call the TDX module API to program the
relevant TD VMCS fields.
Enable Bus Lock VM exit for TDX guests by programming the
BUS_LOCK_DETECTION control in the TD VMCS and by adding the exit handler.
Clear the bus_lock_detected bit to avoid being counted multiple times if
it needs to return early for wait_for_sept_zap case in tdx_vcpu_run().
Since the wait_for_sept_zap case is expected to be rare, just do the
clearing of bus_lock_detected unconditionally.
Note, there is no enumeration bit for this feature by TDX module because
all TDX modules support it, and allow to set the TD VMCS as long as the
hardware supports the feature.
Fixes: 161d34609f9b ("KVM: TDX: Make TDX VM type supported")
Cc: stable@xxxxxxxxxxxxxxx
Originally-by: Chenyi Qiang <chenyi.qiang@xxxxxxxxx>
Signed-off-by: Xiaoyao Li <xiaoyao.li@xxxxxxxxx>
---
Changes in v3:
- Refine the changelog. (Rick)
Changes in v2:
- Don't overwrite the negative return value to 0. (Sashiko)
- Clear the bus_lock_detected bit when it returns early for
wait_for_sept_zap case.
- Add a note to clarify the feature is always supported by the TDX
module, to make Sashiko happy.
---
arch/x86/kvm/vmx/tdx.c | 28 ++++++++++++++++++++++++++--
arch/x86/kvm/vmx/vmx.c | 2 +-
arch/x86/kvm/vmx/vmx.h | 1 +
3 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 598b85d772e3..e7047657ef78 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1082,8 +1082,10 @@ fastpath_t tdx_vcpu_run(struct kvm_vcpu *vcpu, u64 run_flags)
* allowing vCPU entry to avoid contention with tdh_vp_enter() and
* TDCALLs.
*/
- if (unlikely(READ_ONCE(to_kvm_tdx(vcpu->kvm)->wait_for_sept_zap)))
+ if (unlikely(READ_ONCE(to_kvm_tdx(vcpu->kvm)->wait_for_sept_zap))) {
+ vt->exit_reason.bus_lock_detected = 0;
return EXIT_FASTPATH_EXIT_HANDLED;
+ }
trace_kvm_entry(vcpu, run_flags & KVM_RUN_FORCE_IMMEDIATE_EXIT);
@@ -2039,7 +2041,7 @@ int tdx_complete_emulated_msr(struct kvm_vcpu *vcpu, int err)
}
-int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
+static int __tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
{
struct vcpu_tdx *tdx = to_tdx(vcpu);
u64 vp_enter_ret = tdx->vp_enter_ret;
@@ -2140,6 +2142,8 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
case EXIT_REASON_NOTIFY:
/* NMI blocking state is handled by TDX module */
return __vmx_handle_notify(vcpu, vmx_get_exit_qual(vcpu));
+ case EXIT_REASON_BUS_LOCK:
+ return handle_bus_lock_vmexit(vcpu);
default:
break;
}
@@ -2149,6 +2153,22 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
return 0;
}
+int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
+{
+ int ret = __tdx_handle_exit(vcpu, fastpath);
+
+ /* Exit to user space when bus lock was detected */
+ if (vmx_get_exit_reason(vcpu).bus_lock_detected) {
+ if (ret > 0) {
+ vcpu->run->exit_reason = KVM_EXIT_X86_BUS_LOCK;
+ ret = 0;
+ }
+
+ vcpu->run->flags |= KVM_RUN_X86_BUS_LOCK;
+ }
+ return ret;
+}
+
void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code)
{
@@ -3175,6 +3195,10 @@ static int tdx_vcpu_init(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *cmd)
vcpu->kvm->arch.notify_window);
}
+ if (vcpu->kvm->arch.bus_lock_detection_enabled)
+ td_vmcs_setbit32(tdx, SECONDARY_VM_EXEC_CONTROL,
+ SECONDARY_EXEC_BUS_LOCK_DETECTION);
+
tdx->state = VCPU_TD_STATE_INITIALIZED;
return 0;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index e53cc96002c7..c429db9b9205 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6265,7 +6265,7 @@ static int handle_encls(struct kvm_vcpu *vcpu)
}
#endif /* CONFIG_X86_SGX_KVM */
-static int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu)
+int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu)
{
/*
* Hardware may or may not set the BUS_LOCK_DETECTED flag on BUS_LOCK
diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h
index dc8517f15bc4..8faf04c09721 100644
--- a/arch/x86/kvm/vmx/vmx.h
+++ b/arch/x86/kvm/vmx/vmx.h
@@ -379,6 +379,7 @@ bool __vmx_vcpu_run(struct vcpu_vmx *vmx, unsigned int flags);
void vmx_ept_load_pdptrs(struct kvm_vcpu *vcpu);
void vmx_set_intercept_for_msr(struct kvm_vcpu *vcpu, u32 msr, int type, bool set);
+int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu);
static inline void vmx_disable_intercept_for_msr(struct kvm_vcpu *vcpu,
u32 msr, int type)
--
2.43.0