* [PATCH v2 1/3] KVM: TDX: Enable Notify VM exit
2026-08-10 11:21 [PATCH v2 0/3] KVM: TDX: Enable VM-DoS Prevention Features for TDX Xiaoyao Li
@ 2026-08-10 11:21 ` Xiaoyao Li
2026-08-11 0:37 ` Edgecombe, Rick P
2026-08-10 11:21 ` [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling Xiaoyao Li
2026-08-10 11:22 ` [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit Xiaoyao Li
2 siblings, 1 reply; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-10 11:21 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: Rick Edgecombe, Kiryl Shutsemau, Nikolay Borisov, Xiaoyao Li, kvm,
linux-kernel, linux-coco
Enable Notify VM exit functionality for TDX guests.
Notify VM exit is an existing feature supported by KVM. Userspace can
enable Notify VM exit through KVM_CAP_X86_NOTIFY_VMEXIT 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 Notify VM exit for TDX guests by:
- Invoking TDX module API calls to set NOTIFY_VM_EXITING and Notify
Window in TD VMCS. It's done in tdx_vcpu_init() where other TD VMCS
bits are set. Since TDX vCPU cannot be reset, it only needs to be
configured once when initializing the TDX vCPU.
- Adding corresponding exit handler for TDX Notify VM Exit.
Notify VM exit can happen when executing the IRET instruction. If the
IRET unblocks the NMI blocking state, bit 12 of the exit qualification
is set. In this case, the VMM needs to restore the "blocked by NMI" state
when it decides to re-enter the guest. For TDX, KVM cannot manage the
GUEST_INTERRUPTIBILITY_INFO and it's TDX module's responsibility to
handle it. Extract the common part without NMI blocking handling into a
helper in common.h so that it can be shared between VMX and TDX.
Note, KVM uses "pre-production" terminology for the feature formally called
Notify VM-Exit. All public versions of the SDM refer to the feature as
Instruction Timeout. This will be remedied in the near future, for now,
use KVM's terminology for consistency.
Note, #2, there is no enumeration bit for Notify VM exit by TDX module
because all TDX modules support it, and allow to set the corresponding
TD VMCS fields as long as the hardware supports the feature.
Fixes: 161d34609f9b ("KVM: TDX: Make TDX VM type supported")
Cc: stable@vger.kernel.org
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
Changes in v2:
- Mention the feature name mismatch between KVM and SDM in changelog and
leave the renaming to future, since this patch is targeted for stable
- Extract the common handling into a helper, and put the helper in
common.h instead of refactorin the existing handle_notify() in vmx.h
- Add a note to clarify the feature is always supported by TDX module,
to make Sashiko happy.
---
arch/x86/kvm/vmx/common.h | 19 +++++++++++++++++++
arch/x86/kvm/vmx/tdx.c | 10 ++++++++++
arch/x86/kvm/vmx/vmx.c | 13 +------------
3 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/arch/x86/kvm/vmx/common.h b/arch/x86/kvm/vmx/common.h
index 08005676702c..2cbaa9aba901 100644
--- a/arch/x86/kvm/vmx/common.h
+++ b/arch/x86/kvm/vmx/common.h
@@ -4,6 +4,7 @@
#include <linux/kvm_host.h>
#include <asm/posted_intr.h>
+#include <asm/vmx.h>
#include "mmu.h"
@@ -183,6 +184,24 @@ static inline void __vmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu,
kvm_vcpu_trigger_posted_interrupt(vcpu, POSTED_INTR_VECTOR);
}
+static inline int __vmx_handle_notify(struct kvm_vcpu *vcpu,
+ unsigned long exit_qual)
+{
+ bool context_invalid = exit_qual & NOTIFY_VM_CONTEXT_INVALID;
+
+ ++vcpu->stat.notify_window_exits;
+
+ if (vcpu->kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_USER ||
+ context_invalid) {
+ vcpu->run->exit_reason = KVM_EXIT_NOTIFY;
+ vcpu->run->notify.flags = context_invalid ?
+ KVM_NOTIFY_CONTEXT_INVALID : 0;
+ return 0;
+ }
+
+ return 1;
+}
+
noinstr void vmx_handle_nmi(struct kvm_vcpu *vcpu);
#endif /* __KVM_X86_VMX_COMMON_H */
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index b272c20586a7..7338ac0af693 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -2126,6 +2126,9 @@ int tdx_handle_exit(struct kvm_vcpu *vcpu, fastpath_t fastpath)
* - If it's not an MSMI, no need to do anything here.
*/
return 1;
+ case EXIT_REASON_NOTIFY:
+ /* NMI blocking state is handled by TDX module */
+ return __vmx_handle_notify(vcpu, vmx_get_exit_qual(vcpu));
default:
break;
}
@@ -3154,6 +3157,13 @@ static int tdx_vcpu_init(struct kvm_vcpu *vcpu, struct kvm_tdx_cmd *cmd)
td_vmcs_write64(tdx, POSTED_INTR_DESC_ADDR, __pa(&tdx->vt.pi_desc));
td_vmcs_setbit32(tdx, PIN_BASED_VM_EXEC_CONTROL, PIN_BASED_POSTED_INTR);
+ if (kvm_notify_vmexit_enabled(vcpu->kvm)) {
+ td_vmcs_setbit32(tdx, SECONDARY_VM_EXEC_CONTROL,
+ SECONDARY_EXEC_NOTIFY_VM_EXITING);
+ td_vmcs_write32(tdx, NOTIFY_WINDOW,
+ vcpu->kvm->arch.notify_window);
+ }
+
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 e3bfe6aca1a0..e53cc96002c7 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -6279,9 +6279,6 @@ static int handle_bus_lock_vmexit(struct kvm_vcpu *vcpu)
static int handle_notify(struct kvm_vcpu *vcpu)
{
unsigned long exit_qual = vmx_get_exit_qual(vcpu);
- bool context_invalid = exit_qual & NOTIFY_VM_CONTEXT_INVALID;
-
- ++vcpu->stat.notify_window_exits;
/*
* Notify VM exit happened while executing iret from NMI,
@@ -6291,15 +6288,7 @@ static int handle_notify(struct kvm_vcpu *vcpu)
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO,
GUEST_INTR_STATE_NMI);
- if (vcpu->kvm->arch.notify_vmexit_flags & KVM_X86_NOTIFY_VMEXIT_USER ||
- context_invalid) {
- vcpu->run->exit_reason = KVM_EXIT_NOTIFY;
- vcpu->run->notify.flags = context_invalid ?
- KVM_NOTIFY_CONTEXT_INVALID : 0;
- return 0;
- }
-
- return 1;
+ return __vmx_handle_notify(vcpu, exit_qual);
}
static int vmx_get_msr_imm_reg(struct kvm_vcpu *vcpu)
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 1/3] KVM: TDX: Enable Notify VM exit
2026-08-10 11:21 ` [PATCH v2 1/3] KVM: TDX: Enable Notify VM exit Xiaoyao Li
@ 2026-08-11 0:37 ` Edgecombe, Rick P
0 siblings, 0 replies; 18+ messages in thread
From: Edgecombe, Rick P @ 2026-08-11 0:37 UTC (permalink / raw)
To: Li, Xiaoyao, pbonzini@redhat.com, seanjc@google.com
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, kas@kernel.org,
nik.borisov@suse.com, linux-kernel@vger.kernel.org
On Mon, 2026-08-10 at 19:21 +0800, Xiaoyao Li wrote:
> Enable Notify VM exit functionality for TDX guests.
>
> Notify VM exit is an existing feature supported by KVM. Userspace can
> enable Notify VM exit through KVM_CAP_X86_NOTIFY_VMEXIT 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 Notify VM exit for TDX guests by:
>
> - Invoking TDX module API calls to set NOTIFY_VM_EXITING and Notify
> Window in TD VMCS. It's done in tdx_vcpu_init() where other TD VMCS
> bits are set. Since TDX vCPU cannot be reset, it only needs to be
> configured once when initializing the TDX vCPU.
>
> - Adding corresponding exit handler for TDX Notify VM Exit.
>
> Notify VM exit can happen when executing the IRET instruction. If the
> IRET unblocks the NMI blocking state, bit 12 of the exit qualification
> is set. In this case, the VMM needs to restore the "blocked by NMI" state
> when it decides to re-enter the guest. For TDX, KVM cannot manage the
> GUEST_INTERRUPTIBILITY_INFO and it's TDX module's responsibility to
> handle it. Extract the common part without NMI blocking handling into a
> helper in common.h so that it can be shared between VMX and TDX.
>
> Note, KVM uses "pre-production" terminology for the feature formally called
> Notify VM-Exit. All public versions of the SDM refer to the feature as
> Instruction Timeout. This will be remedied in the near future, for now,
> use KVM's terminology for consistency.
>
> Note, #2, there is no enumeration bit for Notify VM exit by TDX module
> because all TDX modules support it, and allow to set the corresponding
> TD VMCS fields as long as the hardware supports the feature.
>
> Fixes: 161d34609f9b ("KVM: TDX: Make TDX VM type supported")
> Cc: stable@vger.kernel.org
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 11:21 [PATCH v2 0/3] KVM: TDX: Enable VM-DoS Prevention Features for TDX Xiaoyao Li
2026-08-10 11:21 ` [PATCH v2 1/3] KVM: TDX: Enable Notify VM exit Xiaoyao Li
@ 2026-08-10 11:21 ` Xiaoyao Li
2026-08-10 11:39 ` sashiko-bot
` (2 more replies)
2026-08-10 11:22 ` [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit Xiaoyao Li
2 siblings, 3 replies; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-10 11:21 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: Rick Edgecombe, Kiryl Shutsemau, Nikolay Borisov, Xiaoyao Li, kvm,
linux-kernel, linux-coco
Get and check the exit reason from the low 16 bits of vp_enter_ret, and
store the synthesized/transformed exit reason in the "basic" field.
Some bits in the upper 16 bits in the exit reason have their own meanings
and they might be 1. When handling the exit reason, only do handling on
the lower 16 bits and keep the upper 16 bits unchanged. This change
also helps remove the additional check in tdx_failed_vmentry().
Note, due to the synthesized invalid exit reason, -1, is changed to
assigned to the "basic" field, adjust the checking in tdx_get_exit_info()
accordingly.
Fixes: 095b71a03f49 ("KVM: TDX: Add a place holder to handle TDX VM exit")
Fixes: c42856af8f70 ("KVM: TDX: Add a place holder for handler of TDX hypercalls (TDG.VP.VMCALL)")
Cc: stable@vger.kernel.org
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
Changes in v2:
- new patch
---
arch/x86/kvm/vmx/tdx.c | 35 ++++++++++++++++++++++-------------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 7338ac0af693..a89885d550c9 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -921,10 +921,10 @@ static __always_inline u32 tdcall_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
return EXIT_REASON_TDCALL;
}
-static __always_inline u32 tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
+static __always_inline union vmx_exit_reason tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
{
struct vcpu_tdx *tdx = to_tdx(vcpu);
- u32 exit_reason;
+ union vmx_exit_reason exit_reason;
switch (tdx->vp_enter_ret & TDX_SEAMCALL_STATUS_MASK) {
case TDX_SUCCESS:
@@ -934,23 +934,33 @@ static __always_inline u32 tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
case TDX_NON_RECOVERABLE_TD_WRONG_APIC_MODE:
break;
default:
- return -1u;
+ /*
+ * Synthesize an invalid bogus Exit Reason, as the TDX-Module
+ * never attempted to run the vCPU, i.e. the Exit Reason is
+ * undefined, but this is NOT a failed VM-Enter.
+ */
+ return (union vmx_exit_reason) {
+ .basic = -1,
+ };
}
- exit_reason = tdx->vp_enter_ret;
+ exit_reason.full = (u32)tdx->vp_enter_ret;
- switch (exit_reason) {
+ switch (exit_reason.basic) {
case EXIT_REASON_TDCALL:
if (tdvmcall_exit_type(vcpu))
- return EXIT_REASON_VMCALL;
-
- return tdcall_to_vmx_exit_reason(vcpu);
+ exit_reason.basic = EXIT_REASON_VMCALL;
+ else
+ exit_reason.basic = tdcall_to_vmx_exit_reason(vcpu);
+ break;
case EXIT_REASON_EPT_MISCONFIG:
/*
* Defer KVM_BUG_ON() until tdx_handle_exit() because this is in
* non-instrumentable code with interrupts disabled.
*/
- return -1u;
+ return (union vmx_exit_reason) {
+ .basic = -1,
+ };
default:
break;
}
@@ -967,7 +977,7 @@ static noinstr void tdx_vcpu_enter_exit(struct kvm_vcpu *vcpu)
tdx->vp_enter_ret = tdh_vp_enter(&tdx->vp, &tdx->vp_enter_args);
- vt->exit_reason.full = tdx_to_vmx_exit_reason(vcpu);
+ vt->exit_reason = tdx_to_vmx_exit_reason(vcpu);
vt->exit_qualification = tdx->vp_enter_args.rcx;
tdx->ext_exit_qualification = tdx->vp_enter_args.rdx;
@@ -981,8 +991,7 @@ static noinstr void tdx_vcpu_enter_exit(struct kvm_vcpu *vcpu)
static bool tdx_failed_vmentry(struct kvm_vcpu *vcpu)
{
- return vmx_get_exit_reason(vcpu).failed_vmentry &&
- vmx_get_exit_reason(vcpu).full != -1u;
+ return vmx_get_exit_reason(vcpu).failed_vmentry;
}
static fastpath_t tdx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
@@ -2144,7 +2153,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
struct vcpu_tdx *tdx = to_tdx(vcpu);
*reason = tdx->vt.exit_reason.full;
- if (*reason != -1u) {
+ if (tdx->vt.exit_reason.basic != -1) {
*info1 = vmx_get_exit_qual(vcpu);
*info2 = tdx->ext_exit_qualification;
*intr_info = vmx_get_intr_info(vcpu);
--
2.43.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 11:21 ` [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling Xiaoyao Li
@ 2026-08-10 11:39 ` sashiko-bot
2026-08-10 12:02 ` Xiaoyao Li
2026-08-11 0:03 ` Sean Christopherson
2026-08-11 0:38 ` Edgecombe, Rick P
2 siblings, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-08-10 11:39 UTC (permalink / raw)
To: Xiaoyao Li; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The condition `tdx->vt.exit_reason.basic != -1` in `tdx_get_exit_info()` is unconditionally true due to C integer promotion rules, defeating the check for synthesized invalid exit reasons and leaking uninitialized or host state to the `kvm_exit` tracepoint.
--
--- Patch [2]: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling ---
commit d21d0519253cbb288be7d1030cb7a0bb7547067a
Author: Xiaoyao Li <xiaoyao.li@intel.com>
KVM: TDX: Fix the exit reason handling
This patch modifies how KVM handles TDX exit reasons by isolating
the lower 16 bits into the basic field and keeping the upper 16 bits
unchanged. It synthesizes an invalid exit reason (-1) for specific
TDX SEAMCALL statuses and updates tdx_get_exit_info() to check this field.
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 66e9e6ee62dae..2c8844acbd43e 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
[ ... ]
> @@ -2147,7 +2156,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
> struct vcpu_tdx *tdx = to_tdx(vcpu);
>
> *reason = tdx->vt.exit_reason.full;
> - if (*reason != -1u) {
> + if (tdx->vt.exit_reason.basic != -1) {
[Severity: Medium]
Will this check always evaluate to true due to C integer promotion rules?
The basic field in union vmx_exit_reason is a 16-bit unsigned bitfield. When
comparing it to -1, the unsigned 16-bit value is promoted to a signed 32-bit
integer. If the value was set to -1 (65535), the comparison evaluates as
65535 != -1, which is always true.
Could this cause uninitialized or host state (such as tdvpr_pa passed via rcx
to the TDX module) to leak to the kvm_exit tracepoint instead of falling back
and safely zeroing the exit data?
> *info1 = vmx_get_exit_qual(vcpu);
> *info2 = tdx->ext_exit_qualification;
> *intr_info = vmx_get_intr_info(vcpu);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260810112200.2326727-1-xiaoyao.li@intel.com?part=2
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 11:39 ` sashiko-bot
@ 2026-08-10 12:02 ` Xiaoyao Li
2026-08-10 23:57 ` Sean Christopherson
0 siblings, 1 reply; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-10 12:02 UTC (permalink / raw)
To: sashiko-reviews; +Cc: kvm, Sean Christopherson, Paolo Bonzini
On 8/10/2026 7:39 PM, sashiko-bot@kernel.org wrote:
>> @@ -2147,7 +2156,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
>> struct vcpu_tdx *tdx = to_tdx(vcpu);
>>
>> *reason = tdx->vt.exit_reason.full;
>> - if (*reason != -1u) {
>> + if (tdx->vt.exit_reason.basic != -1) {
> [Severity: Medium]
> Will this check always evaluate to true due to C integer promotion rules?
>
> The basic field in union vmx_exit_reason is a 16-bit unsigned bitfield. When
> comparing it to -1, the unsigned 16-bit value is promoted to a signed 32-bit
> integer. If the value was set to -1 (65535), the comparison evaluates as
> 65535 != -1, which is always true.
>
Well, how about something below on top of this patch?
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index a89885d550c9..e3c8c92f6f71 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -59,6 +59,8 @@ module_param_named(tdx, enable_tdx, bool, 0444);
#define TDX_SHARED_BIT_PWL_5 gpa_to_gfn(BIT_ULL(51))
#define TDX_SHARED_BIT_PWL_4 gpa_to_gfn(BIT_ULL(47))
+#define TDX_INVALID_EXIT_REASON U16_MAX
+
static const struct tdx_sys_info *tdx_sysinfo;
void tdh_vp_rd_failed(struct vcpu_tdx *tdx, char *uclass, u32 field,
u64 err)
@@ -940,7 +942,7 @@ static __always_inline union vmx_exit_reason
tdx_to_vmx_exit_reason(struct kvm_v
* undefined, but this is NOT a failed VM-Enter.
*/
return (union vmx_exit_reason) {
- .basic = -1,
+ .basic = TDX_INVALID_EXIT_REASON,
};
}
@@ -959,7 +961,7 @@ static __always_inline union vmx_exit_reason
tdx_to_vmx_exit_reason(struct kvm_v
* non-instrumentable code with interrupts disabled.
*/
return (union vmx_exit_reason) {
- .basic = -1,
+ .basic = TDX_INVALID_EXIT_REASON,
};
default:
break;
@@ -2153,7 +2155,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32
*reason,
struct vcpu_tdx *tdx = to_tdx(vcpu);
*reason = tdx->vt.exit_reason.full;
- if (tdx->vt.exit_reason.basic != -1) {
+ if (tdx->vt.exit_reason.basic != TDX_INVALID_EXIT_REASON) {
*info1 = vmx_get_exit_qual(vcpu);
*info2 = tdx->ext_exit_qualification;
*intr_info = vmx_get_intr_info(vcpu);
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 12:02 ` Xiaoyao Li
@ 2026-08-10 23:57 ` Sean Christopherson
2026-08-11 0:04 ` Sean Christopherson
2026-08-11 0:19 ` Xiaoyao Li
0 siblings, 2 replies; 18+ messages in thread
From: Sean Christopherson @ 2026-08-10 23:57 UTC (permalink / raw)
To: Xiaoyao Li; +Cc: sashiko-reviews, kvm, Paolo Bonzini
On Mon, Aug 10, 2026, Xiaoyao Li wrote:
> On 8/10/2026 7:39 PM, sashiko-bot@kernel.org wrote:
> > > @@ -2147,7 +2156,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
> > > struct vcpu_tdx *tdx = to_tdx(vcpu);
> > > *reason = tdx->vt.exit_reason.full;
> > > - if (*reason != -1u) {
> > > + if (tdx->vt.exit_reason.basic != -1) {
> > [Severity: Medium]
> > Will this check always evaluate to true due to C integer promotion rules?
> >
> > The basic field in union vmx_exit_reason is a 16-bit unsigned bitfield. When
> > comparing it to -1, the unsigned 16-bit value is promoted to a signed 32-bit
> > integer. If the value was set to -1 (65535), the comparison evaluates as
> > 65535 != -1, which is always true.
> >
>
> Well, how about something below on top of this patch?
No, we need to not rely on magic exit_reason.basic values. Can't this be?
if ((tdx->vp_enter_ret & TDX_SW_ERROR) != TDX_SW_ERROR) {
<read values>
} else {
<zero values>
}
We'd need to use the unsafe version if we go with my suggestion[*], but other
than that wrinkle, the above seems like the obviously correct fix (maybe too
obvious)?
[*] https://lore.kernel.org/all/anXxBzO41_5eaaOI@google.com
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 23:57 ` Sean Christopherson
@ 2026-08-11 0:04 ` Sean Christopherson
2026-08-11 0:19 ` Xiaoyao Li
1 sibling, 0 replies; 18+ messages in thread
From: Sean Christopherson @ 2026-08-11 0:04 UTC (permalink / raw)
To: Xiaoyao Li; +Cc: sashiko-reviews, kvm, Paolo Bonzini
On Mon, Aug 10, 2026, Sean Christopherson wrote:
> On Mon, Aug 10, 2026, Xiaoyao Li wrote:
> > On 8/10/2026 7:39 PM, sashiko-bot@kernel.org wrote:
> > > > @@ -2147,7 +2156,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
> > > > struct vcpu_tdx *tdx = to_tdx(vcpu);
> > > > *reason = tdx->vt.exit_reason.full;
> > > > - if (*reason != -1u) {
> > > > + if (tdx->vt.exit_reason.basic != -1) {
> > > [Severity: Medium]
> > > Will this check always evaluate to true due to C integer promotion rules?
> > >
> > > The basic field in union vmx_exit_reason is a 16-bit unsigned bitfield. When
> > > comparing it to -1, the unsigned 16-bit value is promoted to a signed 32-bit
> > > integer. If the value was set to -1 (65535), the comparison evaluates as
> > > 65535 != -1, which is always true.
> > >
> >
> > Well, how about something below on top of this patch?
>
> No, we need to not rely on magic exit_reason.basic values. Can't this be?
>
> if ((tdx->vp_enter_ret & TDX_SW_ERROR) != TDX_SW_ERROR) {
This would arguably be a bug fix as well, because the "real" EXIT_REASON_EPT_MISCONFIG
path gets a false negative. E.g. when getting information for an EPT Misconfig
for the tracepoint, KVM really should print all information, not zeros.
At a glance, this exact change can probably be a separate patch too.
> <read values>
> } else {
> <zero values>
> }
>
> We'd need to use the unsafe version if we go with my suggestion[*], but other
> than that wrinkle, the above seems like the obviously correct fix (maybe too
> obvious)?
>
> [*] https://lore.kernel.org/all/anXxBzO41_5eaaOI@google.com
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 23:57 ` Sean Christopherson
2026-08-11 0:04 ` Sean Christopherson
@ 2026-08-11 0:19 ` Xiaoyao Li
1 sibling, 0 replies; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-11 0:19 UTC (permalink / raw)
To: Sean Christopherson; +Cc: sashiko-reviews, kvm, Paolo Bonzini
On 8/11/2026 7:57 AM, Sean Christopherson wrote:
> On Mon, Aug 10, 2026, Xiaoyao Li wrote:
>> On 8/10/2026 7:39 PM, sashiko-bot@kernel.org wrote:
>>>> @@ -2147,7 +2156,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
>>>> struct vcpu_tdx *tdx = to_tdx(vcpu);
>>>> *reason = tdx->vt.exit_reason.full;
>>>> - if (*reason != -1u) {
>>>> + if (tdx->vt.exit_reason.basic != -1) {
>>> [Severity: Medium]
>>> Will this check always evaluate to true due to C integer promotion rules?
>>>
>>> The basic field in union vmx_exit_reason is a 16-bit unsigned bitfield. When
>>> comparing it to -1, the unsigned 16-bit value is promoted to a signed 32-bit
>>> integer. If the value was set to -1 (65535), the comparison evaluates as
>>> 65535 != -1, which is always true.
>>>
>>
>> Well, how about something below on top of this patch?
>
> No, we need to not rely on magic exit_reason.basic values. Can't this be?
>
> if ((tdx->vp_enter_ret & TDX_SW_ERROR) != TDX_SW_ERROR) {
I think the reason of checking if (*reason != -1u) in the original
commit 095b71a03f49 ("KVM: TDX: Add a place holder to handle TDX VM
exit") was that, -1u means there is no valid Exit Reason in the lower 32
bits in vp_enter_ret.
Change it to check TDX_SW_ERROR, doesn't look correct to me. Set the
EPT_MISCONFIG magic handling aside, TDX_SW_ERROR only means the SEAMCALL
instruction faults, e.g., hitting #UD, #GP, or VMFAILINVALID. Just a
small subset of the cases where there is no valid Exit Reason.
> <read values>
> } else {
> <zero values>
> }
>
> We'd need to use the unsafe version if we go with my suggestion[*], but other
> than that wrinkle, the above seems like the obviously correct fix (maybe too
> obvious)?
>
> [*] https://lore.kernel.org/all/anXxBzO41_5eaaOI@google.com
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 11:21 ` [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling Xiaoyao Li
2026-08-10 11:39 ` sashiko-bot
@ 2026-08-11 0:03 ` Sean Christopherson
2026-08-11 3:17 ` Xiaoyao Li
2026-08-11 0:38 ` Edgecombe, Rick P
2 siblings, 1 reply; 18+ messages in thread
From: Sean Christopherson @ 2026-08-11 0:03 UTC (permalink / raw)
To: Xiaoyao Li
Cc: Paolo Bonzini, Rick Edgecombe, Kiryl Shutsemau, Nikolay Borisov,
kvm, linux-kernel, linux-coco
The shortlog is way too generic, and the changelog is light on details. Over
the weekend, I managed to forget why this was necessary, and it took me a few
seconds to recall why we need to avoid setting bits 31:16. Of course, one could
argue that says as much about me as it does the shortlog+changelog...
Oh, and shortlogs like "Fix the exit reason handling" sometimes lead to amusing
follow-ups like "Really fix the exit reason handling". Don't be that person :-)
Something like:
KVM: TDX: Don't clobber exit_reason[31:16] when TDX-Module didn't try VM-Entry
and then in the changelog explain precisely why KVM needs to avoid clobbering
those bits.
On Mon, Aug 10, 2026, Xiaoyao Li wrote:
> Get and check the exit reason from the low 16 bits of vp_enter_ret, and
> store the synthesized/transformed exit reason in the "basic" field.
>
> Some bits in the upper 16 bits in the exit reason have their own meanings
> and they might be 1. When handling the exit reason, only do handling on
> the lower 16 bits and keep the upper 16 bits unchanged. This change
> also helps remove the additional check in tdx_failed_vmentry().
>
> Note, due to the synthesized invalid exit reason, -1, is changed to
> assigned to the "basic" field, adjust the checking in tdx_get_exit_info()
> accordingly.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-11 0:03 ` Sean Christopherson
@ 2026-08-11 3:17 ` Xiaoyao Li
0 siblings, 0 replies; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-11 3:17 UTC (permalink / raw)
To: Sean Christopherson
Cc: Paolo Bonzini, Rick Edgecombe, Kiryl Shutsemau, Nikolay Borisov,
kvm, linux-kernel, linux-coco
On 8/11/2026 8:03 AM, Sean Christopherson wrote:
> The shortlog is way too generic, and the changelog is light on details. Over
> the weekend, I managed to forget why this was necessary, and it took me a few
> seconds to recall why we need to avoid setting bits 31:16. Of course, one could
> argue that says as much about me as it does the shortlog+changelog...
>
> Oh, and shortlogs like "Fix the exit reason handling" sometimes lead to amusing
> follow-ups like "Really fix the exit reason handling". Don't be that person :-)
>
> Something like:
>
> KVM: TDX: Don't clobber exit_reason[31:16] when TDX-Module didn't try VM-Entry
1. It's not only about clobbering the exit_reason[31:16], but also about
how to interpret the basic exit, e.g.. the change
- switch (exit_reason) {
+ switch (exit_reason.basic) {
2. It's not only about TDX module doesn't try VM entry, bus also about a
valid VM exit after successful VM entry. This patch also preserves the
exit_reason[31:16] for a valid VM exit. (One could argue that existing
code cannot clobber exit_reason[31;16] because the code to clobber it
requires the [31:16] to be 0, because of switch (exit_reason))
3. For the case where TDX module doesn't try VM-Entry, I'm not sure if
"clobber" is the correct word. There is no valid exit reason, so nothing
to be really clobbered. Just don't synthesize a exit reason with
non-zero bit 31:16.
My intent was just using one patch to handle them all, so as to make KVM
behave correctly after enabling Bus Lock VM exit for TDX in the next
patch. Because they are targeted for stable kernels.
What's your advice then? What do you think of spliting it into multiple
so that it's easier to write a shortlog and changelog for each one.
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling
2026-08-10 11:21 ` [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling Xiaoyao Li
2026-08-10 11:39 ` sashiko-bot
2026-08-11 0:03 ` Sean Christopherson
@ 2026-08-11 0:38 ` Edgecombe, Rick P
[not found] ` <6bb1328d-e995-4ad7-9744-3ab01d2ae591@intel.com>
2 siblings, 1 reply; 18+ messages in thread
From: Edgecombe, Rick P @ 2026-08-11 0:38 UTC (permalink / raw)
To: Li, Xiaoyao, pbonzini@redhat.com, seanjc@google.com
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, kas@kernel.org,
nik.borisov@suse.com, linux-kernel@vger.kernel.org
On Mon, 2026-08-10 at 19:21 +0800, Xiaoyao Li wrote:
> Get and check the exit reason from the low 16 bits of vp_enter_ret, and
> store the synthesized/transformed exit reason in the "basic" field.
>
> Some bits in the upper 16 bits in the exit reason have their own meanings
> and they might be 1. When handling the exit reason, only do handling on
> the lower 16 bits and keep the upper 16 bits unchanged. This change
> also helps remove the additional check in tdx_failed_vmentry().
>
> Note, due to the synthesized invalid exit reason, -1, is changed to
> assigned to the "basic" field, adjust the checking in tdx_get_exit_info()
> accordingly.
>
> Fixes: 095b71a03f49 ("KVM: TDX: Add a place holder to handle TDX VM exit")
> Fixes: c42856af8f70 ("KVM: TDX: Add a place holder for handler of TDX hypercalls (TDG.VP.VMCALL)")
> Cc: stable@vger.kernel.org
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> ---
> Changes in v2:
> - new patch
> ---
> arch/x86/kvm/vmx/tdx.c | 35 ++++++++++++++++++++++-------------
> 1 file changed, 22 insertions(+), 13 deletions(-)
>
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 7338ac0af693..a89885d550c9 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -921,10 +921,10 @@ static __always_inline u32 tdcall_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
> return EXIT_REASON_TDCALL;
> }
>
> -static __always_inline u32 tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
> +static __always_inline union vmx_exit_reason tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
> {
> struct vcpu_tdx *tdx = to_tdx(vcpu);
> - u32 exit_reason;
> + union vmx_exit_reason exit_reason;
>
> switch (tdx->vp_enter_ret & TDX_SEAMCALL_STATUS_MASK) {
> case TDX_SUCCESS:
> @@ -934,23 +934,33 @@ static __always_inline u32 tdx_to_vmx_exit_reason(struct kvm_vcpu *vcpu)
> case TDX_NON_RECOVERABLE_TD_WRONG_APIC_MODE:
> break;
> default:
> - return -1u;
> + /*
> + * Synthesize an invalid bogus Exit Reason, as the TDX-Module
I think this blurb came from Sean, but can we standardize on "TDX module"? The
code currently uses "TDX module" and "TDX-module" and "TDX-module" used much
less. I also don't see why it needs the "-".
> + * never attempted to run the vCPU, i.e. the Exit Reason is
> + * undefined, but this is NOT a failed VM-Enter.
> + */
> + return (union vmx_exit_reason) {
> + .basic = -1,
> + };
> }
>
> - exit_reason = tdx->vp_enter_ret;
> + exit_reason.full = (u32)tdx->vp_enter_ret;
>
> - switch (exit_reason) {
> + switch (exit_reason.basic) {
> case EXIT_REASON_TDCALL:
> if (tdvmcall_exit_type(vcpu))
> - return EXIT_REASON_VMCALL;
> -
> - return tdcall_to_vmx_exit_reason(vcpu);
> + exit_reason.basic = EXIT_REASON_VMCALL;
> + else
> + exit_reason.basic = tdcall_to_vmx_exit_reason(vcpu);
> + break;
> case EXIT_REASON_EPT_MISCONFIG:
> /*
> * Defer KVM_BUG_ON() until tdx_handle_exit() because this is in
> * non-instrumentable code with interrupts disabled.
> */
> - return -1u;
> + return (union vmx_exit_reason) {
> + .basic = -1,
> + };
We could make this return instead be a goto err; that returns this. Bonus is the
comment on the other one can cover them both. What do you think?
> default:
> break;
> }
> @@ -967,7 +977,7 @@ static noinstr void tdx_vcpu_enter_exit(struct kvm_vcpu *vcpu)
>
> tdx->vp_enter_ret = tdh_vp_enter(&tdx->vp, &tdx->vp_enter_args);
>
> - vt->exit_reason.full = tdx_to_vmx_exit_reason(vcpu);
> + vt->exit_reason = tdx_to_vmx_exit_reason(vcpu);
>
> vt->exit_qualification = tdx->vp_enter_args.rcx;
> tdx->ext_exit_qualification = tdx->vp_enter_args.rdx;
> @@ -981,8 +991,7 @@ static noinstr void tdx_vcpu_enter_exit(struct kvm_vcpu *vcpu)
>
> static bool tdx_failed_vmentry(struct kvm_vcpu *vcpu)
> {
> - return vmx_get_exit_reason(vcpu).failed_vmentry &&
> - vmx_get_exit_reason(vcpu).full != -1u;
> + return vmx_get_exit_reason(vcpu).failed_vmentry;
> }
>
> static fastpath_t tdx_exit_handlers_fastpath(struct kvm_vcpu *vcpu)
> @@ -2144,7 +2153,7 @@ void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
> struct vcpu_tdx *tdx = to_tdx(vcpu);
>
> *reason = tdx->vt.exit_reason.full;
> - if (*reason != -1u) {
> + if (tdx->vt.exit_reason.basic != -1) {
> *info1 = vmx_get_exit_qual(vcpu);
> *info2 = tdx->ext_exit_qualification;
> *intr_info = vmx_get_intr_info(vcpu);
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit
2026-08-10 11:21 [PATCH v2 0/3] KVM: TDX: Enable VM-DoS Prevention Features for TDX Xiaoyao Li
2026-08-10 11:21 ` [PATCH v2 1/3] KVM: TDX: Enable Notify VM exit Xiaoyao Li
2026-08-10 11:21 ` [PATCH v2 2/3] KVM: TDX: Fix the exit reason handling Xiaoyao Li
@ 2026-08-10 11:22 ` Xiaoyao Li
2026-08-10 11:46 ` sashiko-bot
2026-08-11 1:18 ` Edgecombe, Rick P
2 siblings, 2 replies; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-10 11:22 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: Rick Edgecombe, Kiryl Shutsemau, Nikolay Borisov, Xiaoyao Li, kvm,
linux-kernel, linux-coco
Enable Bus Lock VM exit functionality for TDX guests.
Userspace can enable KVM_BUS_LOCK_DETECTION_EXIT for TDX guests without
getting an error, but the feature is not actually enabled because KVM
does not yet program the TDX execution control or handle the resulting
exit.
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@vger.kernel.org
Originally-by: Chenyi Qiang <chenyi.qiang@intel.com>
Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
---
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 a89885d550c9..ac3f71643cd5 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1080,8 +1080,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);
@@ -2037,7 +2039,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;
@@ -2138,6 +2140,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;
}
@@ -2147,6 +2151,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)
{
@@ -3173,6 +3193,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
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit
2026-08-10 11:22 ` [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit Xiaoyao Li
@ 2026-08-10 11:46 ` sashiko-bot
2026-08-10 12:03 ` Xiaoyao Li
2026-08-11 1:18 ` Edgecombe, Rick P
1 sibling, 1 reply; 18+ messages in thread
From: sashiko-bot @ 2026-08-10 11:46 UTC (permalink / raw)
To: Xiaoyao Li; +Cc: kvm
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] The `vmx_handle_exit()` function silently drops negative error codes (fatal errors) when `bus_lock_detected` is true.
--
--- Patch [3]: [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit ---
commit 573aa824013208febeaa70c68e452e3344dd518c
Author: Xiaoyao Li <xiaoyao.li@intel.com>
KVM: TDX: Enable Bus Lock VM exit
This patch enables Bus Lock VM exit functionality for TDX guests by
programming the BUS_LOCK_DETECTION control in the TD VMCS and adding the
exit handler. It also handles clearing the bus_lock_detected bit to avoid
issues during the wait_for_sept_zap case.
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index 2c8844acbd43e..ee3c7a32361a4 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
[ ... ]
> @@ -2150,6 +2154,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;
> + }
[Severity: High]
This is a pre-existing issue, but since you fixed the negative return value
handling here for tdx_handle_exit() in v2, should a similar fix be applied
to the pre-existing vmx_handle_exit() in arch/x86/kvm/vmx/vmx.c?
Looking at vmx_handle_exit(), if __vmx_handle_exit() returns a negative
error code (e.g. -ENOMEM) and bus_lock_detected is true, it unconditionally
overrides the negative return value to 0:
if (vmx_get_exit_reason(vcpu).bus_lock_detected) {
if (ret > 0)
vcpu->run->exit_reason = KVM_EXIT_X86_BUS_LOCK;
vcpu->run->flags |= KVM_RUN_X86_BUS_LOCK;
return 0;
}
Because ret > 0 is false, it skips setting vcpu->run->exit_reason but still
returns 0 (success) to userspace.
Does this result in userspace receiving a successful return code but with a
stale or uninitialized exit_reason, likely leading to a VMM crash or
unexpected termination if a guest triggers a bus lock exit while KVM
hits an internal error?
> +
> + vcpu->run->flags |= KVM_RUN_X86_BUS_LOCK;
> + }
> + return ret;
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260810112200.2326727-1-xiaoyao.li@intel.com?part=3
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit
2026-08-10 11:46 ` sashiko-bot
@ 2026-08-10 12:03 ` Xiaoyao Li
0 siblings, 0 replies; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-10 12:03 UTC (permalink / raw)
To: sashiko-reviews; +Cc: kvm, Sean Christopherson, Paolo Bonzini
On 8/10/2026 7:46 PM, sashiko-bot@kernel.org wrote:
>> @@ -2150,6 +2154,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;
>> + }
> [Severity: High]
> This is a pre-existing issue, but since you fixed the negative return value
> handling here for tdx_handle_exit() in v2, should a similar fix be applied
> to the pre-existing vmx_handle_exit() in arch/x86/kvm/vmx/vmx.c?
VMX fix was sent already:
https://lore.kernel.org/all/20260806111923.1990562-2-xiaoyao.li@intel.com/
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit
2026-08-10 11:22 ` [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit Xiaoyao Li
2026-08-10 11:46 ` sashiko-bot
@ 2026-08-11 1:18 ` Edgecombe, Rick P
2026-08-11 1:44 ` Xiaoyao Li
1 sibling, 1 reply; 18+ messages in thread
From: Edgecombe, Rick P @ 2026-08-11 1:18 UTC (permalink / raw)
To: Li, Xiaoyao, pbonzini@redhat.com, seanjc@google.com
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, kas@kernel.org,
nik.borisov@suse.com, linux-kernel@vger.kernel.org
On Mon, 2026-08-10 at 19:22 +0800, Xiaoyao Li wrote:
> Enable Bus Lock VM exit functionality for TDX guests.
>
> Userspace can enable KVM_BUS_LOCK_DETECTION_EXIT for TDX guests without
> getting an error, but the feature is not actually enabled because KVM
> does not yet program the TDX execution control or handle the resulting
> exit.
A bit run-on to me. Why not break it up like it's explained in patch 1.
>
> 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@vger.kernel.org
> Originally-by: Chenyi Qiang <chenyi.qiang@intel.com>
> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
> ---
> 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.
Ha! This is probably just being a bit funny. But let's treat AI review as
suggestions only. If it is a good feedback, it can stand on it's own.
> ---
> 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 a89885d550c9..ac3f71643cd5 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -1080,8 +1080,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;
> + }
Hmm. Why is this the only part of exit_reason that we care about in this
scenario?
I went and looked for similar scenarios on the VMX side to see what it did, and
didn't find any. Same for you?
>
> trace_kvm_entry(vcpu, run_flags & KVM_RUN_FORCE_IMMEDIATE_EXIT);
>
> @@ -2037,7 +2039,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;
> @@ -2138,6 +2140,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;
> }
> @@ -2147,6 +2151,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;
> +}
Ok, so the plan is to consolidate this duplication on top of the backportable
fix.
> +
> void tdx_get_exit_info(struct kvm_vcpu *vcpu, u32 *reason,
> u64 *info1, u64 *info2, u32 *intr_info, u32 *error_code)
> {
> @@ -3173,6 +3193,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)
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH v2 3/3] KVM: TDX: Enable Bus Lock VM exit
2026-08-11 1:18 ` Edgecombe, Rick P
@ 2026-08-11 1:44 ` Xiaoyao Li
0 siblings, 0 replies; 18+ messages in thread
From: Xiaoyao Li @ 2026-08-11 1:44 UTC (permalink / raw)
To: Edgecombe, Rick P, pbonzini@redhat.com, seanjc@google.com
Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev, kas@kernel.org,
nik.borisov@suse.com, linux-kernel@vger.kernel.org
On 8/11/2026 9:18 AM, Edgecombe, Rick P wrote:
> On Mon, 2026-08-10 at 19:22 +0800, Xiaoyao Li wrote:
>> Enable Bus Lock VM exit functionality for TDX guests.
>>
>> Userspace can enable KVM_BUS_LOCK_DETECTION_EXIT for TDX guests without
>> getting an error, but the feature is not actually enabled because KVM
>> does not yet program the TDX execution control or handle the resulting
>> exit.
>
> A bit run-on to me. Why not break it up like it's explained in patch 1.
Will update it to way how patch 1 describes.
>>
>> 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@vger.kernel.org
>> Originally-by: Chenyi Qiang <chenyi.qiang@intel.com>
>> Signed-off-by: Xiaoyao Li <xiaoyao.li@intel.com>
>> ---
>> 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.
>
> Ha! This is probably just being a bit funny. But let's treat AI review as
> suggestions only. If it is a good feedback, it can stand on it's own.
yeah. Mostly for funny. I think the clarification itself makes sense.
>> ---
>> 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 a89885d550c9..ac3f71643cd5 100644
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
>> @@ -1080,8 +1080,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;
>> + }
>
> Hmm. Why is this the only part of exit_reason that we care about in this
> scenario?
Because it's the only path on TDX that it returns without updating the
vt->exit_reason. All the other cases go to tdx_vcpu_enter_exit() and
tdx_vcpu_enter_exit() updates the vt->exit_reason.
> I went and looked for similar scenarios on the VMX side to see what it did, and
> didn't find any. Same for you?
VMX can return early without reaching vmx_vcpu_enter_exit() as well. But
VMX ensures vt->exit_reason is updated when it returns early.
>>
>> trace_kvm_entry(vcpu, run_flags & KVM_RUN_FORCE_IMMEDIATE_EXIT);
>>
>> @@ -2037,7 +2039,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;
>> @@ -2138,6 +2140,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;
>> }
>> @@ -2147,6 +2151,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;
>> +}
>
> Ok, so the plan is to consolidate this duplication on top of the backportable
> fix.
yes. The consolidation also requires to first fix the VMX part[1]. So
this series only contains the necessary things that need to be
backported to stable kernels.
[1]
https://lore.kernel.org/all/20260806111923.1990562-2-xiaoyao.li@intel.com/
^ permalink raw reply [flat|nested] 18+ messages in thread