Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
@ 2026-08-27  3:18 Binbin Wu
  2026-08-27  3:18 ` [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
                   ` (4 more replies)
  0 siblings, 5 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-27  3:18 UTC (permalink / raw)
  To: linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao, binbin.wu

Hi,

The purpose of this patch series is to prevent userspace from enabling
host state clobbering features that KVM does not support for TDX.  A host
state clobbering feature exposed on a new TDX module/platform can corrupt
host state if KVM does not explicitly save and restore the related MSR(s)
across host/guest transitions.  If such a feature is blindly exposed to
and used by a TD, the host will behave unexpectedly.

Except for a few fixed-1 bits required for basic TDX support, host state
clobbering features are either directly configurable or gated by TD
ATTRIBUTES/XFAM.  So an allowlist covering only the directly configurable
CPUID bits, plus the corresponding filtering and validation, is sufficient
to serve the purpose while keeping the code footprint small.

Open question for Sean/Paolo
============================
This revision comes long after Sean confirmed the overall direction on
RFC v2 [1], due to internal discussions about a potential backward
compatibility issue: a CPUID field can change virtualization type to
directly configurable.  The TDX module can maintain backward
compatibility in most cases; the problematic case is a single bit that
was effectively "1" and non-configurable becoming directly configurable.
The only scenario we can envision for that is an x86 feature deprecation.

In that case the TDX module has to decide how to handle deprecation,
especially with respect to TD migration compatibility.  That
pre-existing VMs with the deprecated feature enabled cannot migrate from
an old platform to a new one is a problem shared by TDX and VMX, but the
TDX module additionally has to decide:
- Whether to allow TDs newly created on old platforms to migrate to new
  platforms.
- Whether to allow TDs created on new platforms to migrate to old
  platforms.

There are two options:
1. Do not offer the VMM the ability to configure the bit, i.e. simply
   report it as zero on platforms that no longer support the feature.
   This disallows both migration cases above.
2. Make the bit directly configurable so the VMM can clear it even on
   platforms that still support the feature, allowing both migration
   cases above.  However, since the bit is not in KVM's allowlist,
   userspace would no longer be able to enable it on old platforms after
   a TDX module update.

Adding all supported CPUID bits to the allowlist, regardless of their
virtualization type in the TDX module, would avoid the compatibility
issue for option 2, at the cost of a significantly larger series.

Given that x86 feature deprecation is expected to be very rare, and that
Intel will discuss such cases with the community beforehand, does the
approach taken by this series look acceptable?  If so, the goal for this
revision is to collect detailed feedback and, where appropriate,
Reviewed-by tags.

Expected host state clobbering behavior for TDX
===============================================
We also want to call for discussions about the expected host state
clobbering behavior for TDX here for future features.

For a normal VMX guest, VM entry/exit behavior for a given piece of CPU
state is architecturally defined: state is either switched by hardware via
VMCS host/guest fields, or left as the guest value on VM exit and managed
by KVM in software.

For TDs, the host/guest transition goes through TDH.VP.ENTER, and what the
TDX module does with a given piece of host state is defined by the TDX
module ABI rather than by the x86 architecture.

What we would like to align on is the expected baseline behavior of
TDH.VP.ENTER for future features.  The proposal is to have TDX simply
match VMX behavior, i.e. on return from TDH.VP.ENTER, state that VMX would
restore from the VMCS host fields is restored, and state that VMX would
leave as the guest value is clobbered.  That keeps a single model for VMM,
and means enabling a new feature for TDs requires the same work flow as
enabling it for VMX.

FRED is a useful concrete example.  Under VMX, the FRED host state in
IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP1-3 and
IA32_FRED_SSP1-3 is covered by the VMCS host-state area, so the TDX module
is expected to restore these MSRs on TDH.VP.ENTER return.  IA32_FRED_RSP0
and IA32_PL0_SSP (a.k.a. IA32_FRED_SSP0) are handled by software, so the
TDX module is expected to clobber them on TDH.VP.ENTER return.

The series
==========

Starting with v2 [2], the series takes a simpler, TDX-contained approach
instead of the comprehensive CPUID paranoid verification framework across
VMX, SVM, and TDX proposed in v1 [3].  It validates only the TDX directly
configurable CPUID bits, which are reported by the TDX module in
CPUID_CONFIG fields that the VMM can configure for a TD.  All filtering
and validation logic is isolated within TDX code.  This is sufficient to
address the host clobbering issue because:
- The TDX module will not introduce new host state clobbering features
  that are fixed-1.
- Non-directly configurable feature bits (i.e. features controlled by XFAM
  or ATTRIBUTES) cannot be enabled by userspace without KVM's support.

Specifically, this series builds a KVM-side allowlist of supported TDX
directly configurable CPUID bits to:
 - Filter KVM_TDX_CAPABILITIES
   Replace the hardcoded denylist to only report configurable bits that
   KVM explicitly supports.
 - Validate KVM_TDX_INIT_VM
   Reject any configurable bit that the TDX module allows but KVM does
   not support, as well as CPUID entries with an unexpected subleaf.

With this allowlist, newly added TDX configurable CPUID bits will not be
exposed to userspace until KVM explicitly opts in after fulfilling the
necessary virtualization requirements.

The allowlist consists of two parts:
- Feature CPUID bits, which are tracked in tdx_cpu_cfg_caps[] following
  the organization of kvm_cpu_caps[].  It holds KVM's supported masks for
  the TDX configurable CPUID feature bits.
- Non-feature multi-bit fields, which are handled at runtime for the CPUID
  registers holding such fields.

For compatibility with older TDX modules that report CORE_CAPABILITIES as
fixed-1, report CORE_CAPABILITIES as configurable even though KVM does not
support guest access to MSR_IA32_CORE_CAPS.  This allows userspace to keep
enabling CORE_CAPABILITIES when the bit changes from fixed-1 to directly
configurable, and allows userspace to infer that the bit is no longer
fixed-1 so it can adjust its expectations.

Known limitation:
- The series does not check KVM_SET_CPUID2 input for consistency with the
  CPUID configuration supplied through KVM_TDX_INIT_VM.  This is not
  required for host safety today because KVM does not use its vCPU CPUID
  model to decide whether to manage host-clobbering state for TDs.  A
  consistency check should be added if KVM ever starts relying on the vCPU
  CPUID model for such decisions.

Changes from v2 [2]:
- Drop the dedicated data structure introduced in v2; track only feature
  bits following the organization of kvm_cpu_caps[], and handle
  non-feature bits at runtime. (Sean)
- Add AMX_COMPLEX since it has been defined in the CPUID virtualization
  doc.
- Add CPUID.0x24.0.EBX[7:0] into allow list. There is a mismatch of the
  description about CPUID.0x24.0.EBX[7:0], which is listed as
  "XFAM & CPUID_Enabled & Native" but should be "XFAM & CPUID_Enabled &
  Configured & Native".
- Move the patch for CORE_CAPABILITIES earlier in the series to avoid
  breaking userspace during bisection. (Xiaoyao)
- Report CORE_CAPABILITIES as a configurable bit to userspace for
  backward compatibility, but drop the MSR_IA32_CORE_CAPS access code.
- Use two versions of macros to distinguish whether a supported TDX
  configurable CPUID bit should be checked against KVM's common CPU
  capabilities.
- Validate KVM_TDX_INIT_VM input against the allowlist instead of masking
  it, and additionally reject entries whose index does not match the
  TDX sysinfo configuration. (Sashiko)

Changes from v1 [3]:
 - Drop the overarching CPUID paranoid verification framework across
   VMX/SVM/TDX and the opt-in interface. (Sean)
 - Shift focus entirely to isolating and validating TDX directly
   configurable CPUID bits.

The series follows the CSV version of the CPUID virtualization document
from "Intel TDX Module ABI Definitions" [4], updated in June 2026.

AI tools were used to:
- Check the coverage of the directly configurable CPUID bits in the
  document against the allowlist in this series.
- Polish the cover letter and commit messages.
- Do code review.

[1] https://lore.kernel.org/kvm/aj1fqZEcApyd4sxi@google.com
[2] https://lore.kernel.org/kvm/20260604023314.3907511-1-binbin.wu@linux.intel.com
[3] https://lore.kernel.org/kvm/20260417073610.3246316-1-binbin.wu@linux.intel.com
[4] https://cdrdv2.intel.com/v1/dl/getContent/795381

Binbin Wu (4):
  KVM: TDX: Track configurable CPUID bits allowed by KVM
  KVM: TDX: Report CORE_CAPABILITIES as configurable
  KVM: TDX: Filter configurable CPUID bits
  KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM

 arch/x86/kvm/vmx/tdx.c | 258 ++++++++++++++++++++++++++++++++++++-----
 1 file changed, 229 insertions(+), 29 deletions(-)


base-commit: 76671054f9a1ff6abb976583cd8da37650acdc97
-- 
2.46.0


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-08-27  3:18 [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
@ 2026-08-27  3:18 ` Binbin Wu
  2026-09-01  6:29   ` Tony Lindgren
  2026-09-01 14:35   ` Xiaoyao Li
  2026-08-27  3:18 ` [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable Binbin Wu
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-27  3:18 UTC (permalink / raw)
  To: linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao, binbin.wu

Add tdx_cpu_cfg_caps[] to track the subset of TDX directly configurable
CPUID feature bits that KVM supports, and build the masks during TDX
hardware setup via tdx_initialize_cpu_cfg_caps().

The TDX module reports the CPUID bits that the VMM can directly configure
for a TD, but KVM cannot blindly expose all reported bits to userspace.
Certain features imply additional architectural state, e.g. one or more
MSRs, that KVM must explicitly manage across host/guest transitions to
prevent host state corruption.

Today KVM relies on a hardcoded denylist, i.e. it clears a few known
problematic bits, e.g. TSX and WAITPKG, and passes everything else through.
A denylist is fundamentally fragile while an allowlist inverts the default,
i.e. unknown configurable bits are hidden and not allowed to be enabled
until KVM explicitly opts in.

Except for a few fixed-1 bits required for basic TDX support, host state
clobbering features are either directly configurable or gated by TD
ATTRIBUTES/XFAM.  Tracking only the directly configurable feature bits is
therefore sufficient to serve the purpose while keeping the code footprint
small.

Organize tdx_cpu_cfg_caps[] following kvm_cpu_caps[] so that the masks can
be built with the similar feature-name based initializers.  CPUID registers
that hold directly configurable non-feature (multi-bit) fields are handled
separately.

The allowlist is consumed by later patches to filter KVM_TDX_CAPABILITIES
and to reject unsupported CPUID input to KVM_TDX_INIT_VM, so that newly
introduced TDX directly configurable CPUID feature bits stay hidden from
userspace until KVM explicitly opts in.

Add comments as placeholders for HLE, RTM and WAITPKG, which KVM doesn't
support for TDX yet.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
v3:
- Drop the new data structure in v2 and only track feature bits by
  following the organization of kvm_cpu_caps[], handle non-feature
  bits separately. (Sean)
- Use two versions of macros (TDX_CFG_F() VS. TDX_CFG_EXTRA_F()) to
  distinguish whether a supported TDX configurable CPUID bit should be
  checked against KVM's common cpu capabilities.
- Add AMX_COMPLEX since it has been defined in the CPUID virtualization doc.
---
 arch/x86/kvm/vmx/tdx.c | 145 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 145 insertions(+)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index b272c20586a7..d4a3a42cfd9d 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -52,6 +52,149 @@
 	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
 		     a1, a2, a3)
 
+static u32 tdx_cpu_cfg_caps[NR_KVM_CPU_CAPS] __ro_after_init;
+static_assert(ARRAY_SIZE(tdx_cpu_cfg_caps) == ARRAY_SIZE(kvm_cpu_caps));
+
+#define TDX_VALIDATE_CPU_CAP_USAGE(name)			\
+	BUILD_BUG_ON(__feature_leaf(X86_FEATURE_##name) !=	\
+		     tdx_cpu_cap_init_in_progress)
+
+/* For feature bit that KVM advertised through kvm_cpu_caps[]. */
+#define TDX_CFG_F(name)					\
+({							\
+	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
+	tdx_cfg_caps |= feature_bit(name);		\
+})
+
+/*
+ * For feature bit KVM allows for TDX guests even though it is not advertised
+ * through kvm_cpu_caps[], e.g. MWAIT.
+ */
+#define TDX_CFG_EXTRA_F(name)				\
+({							\
+	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
+	tdx_cfg_extra_caps |= feature_bit(name);	\
+})
+
+#define tdx_cpu_cfg_cap_init(leaf, feature_initializers...)		\
+do {									\
+	const u32 __maybe_unused tdx_cpu_cap_init_in_progress = leaf;	\
+	u32 tdx_cfg_extra_caps = 0;					\
+	u32 tdx_cfg_caps = 0;						\
+									\
+	feature_initializers						\
+	tdx_cpu_cfg_caps[leaf] = (tdx_cfg_caps & kvm_cpu_caps[leaf]) |	\
+				 tdx_cfg_extra_caps;			\
+} while (0)
+
+/*
+ * Track only CPUID feature bits that are directly configurable by userspace.
+ * Features controlled by XFAM or ATTRIBUTES are excluded; userspace cannot
+ * enable them until KVM adds support for the corresponding control.
+ */
+static void __init tdx_initialize_cpu_cfg_caps(void)
+{
+	tdx_cpu_cfg_cap_init(CPUID_1_ECX,
+		TDX_CFG_EXTRA_F(MWAIT),
+		TDX_CFG_F(TSC_DEADLINE_TIMER),
+		TDX_CFG_F(AVX),
+		TDX_CFG_F(F16C),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_1_EDX,
+		TDX_CFG_F(MCE),
+		TDX_CFG_F(MTRR),
+		TDX_CFG_F(MCA),
+		TDX_CFG_F(SELFSNOOP),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_7_0_EBX,
+		TDX_CFG_F(BMI1),
+		/* HLE */
+		TDX_CFG_F(BMI2),
+		TDX_CFG_F(ERMS),
+		/* RTM */
+		TDX_CFG_F(AVX512F),
+		TDX_CFG_F(AVX512DQ),
+		TDX_CFG_F(ADX),
+		TDX_CFG_F(AVX512IFMA),
+		TDX_CFG_F(AVX512PF),
+		TDX_CFG_F(AVX512ER),
+		TDX_CFG_F(AVX512CD),
+		TDX_CFG_F(AVX512BW),
+		TDX_CFG_F(AVX512VL),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_7_ECX,
+		TDX_CFG_F(UMIP),
+		/* WAITPKG */
+		TDX_CFG_F(AVX512_VBMI2),
+		TDX_CFG_F(GFNI),
+		TDX_CFG_F(VAES),
+		TDX_CFG_F(VPCLMULQDQ),
+		TDX_CFG_F(AVX512_VNNI),
+		TDX_CFG_F(AVX512_BITALG),
+		TDX_CFG_F(AVX512_VPOPCNTDQ),
+		TDX_CFG_F(LA57),
+		TDX_CFG_F(RDPID),
+		TDX_CFG_F(CLDEMOTE),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_7_EDX,
+		TDX_CFG_F(AVX512_4VNNIW),
+		TDX_CFG_F(AVX512_4FMAPS),
+		TDX_CFG_F(FSRM),
+		TDX_CFG_F(AVX512_VP2INTERSECT),
+		TDX_CFG_F(SERIALIZE),
+		TDX_CFG_F(TSXLDTRK),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_7_1_EAX,
+		TDX_CFG_F(SHA512),
+		TDX_CFG_F(SM3),
+		TDX_CFG_F(SM4),
+		TDX_CFG_F(AVX_VNNI),
+		TDX_CFG_F(AVX512_BF16),
+		TDX_CFG_F(CMPCCXADD),
+		TDX_CFG_F(FZRM),
+		TDX_CFG_F(FSRS),
+		TDX_CFG_F(FSRC),
+		TDX_CFG_F(LKGS),
+		TDX_CFG_F(WRMSRNS),
+		TDX_CFG_F(AMX_FP16),
+		TDX_CFG_F(AVX_IFMA),
+		TDX_CFG_F(LAM),
+		TDX_CFG_F(MOVRS),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_7_1_EDX,
+		TDX_CFG_F(AVX_VNNI_INT8),
+		TDX_CFG_F(AVX_NE_CONVERT),
+		TDX_CFG_F(AMX_COMPLEX),
+		TDX_CFG_F(AVX_VNNI_INT16),
+		TDX_CFG_F(PREFETCHITI),
+		TDX_CFG_F(AVX10),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_7_2_EDX,
+		TDX_CFG_F(DDPD_U),
+		TDX_CFG_F(MCDT_NO),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_1E_1_EAX,
+		TDX_CFG_F(AMX_FP8),
+		TDX_CFG_F(AMX_TF32),
+		TDX_CFG_F(AMX_AVX512),
+		TDX_CFG_F(AMX_MOVRS),
+	);
+
+	tdx_cpu_cfg_cap_init(CPUID_8000_0008_EBX,
+		TDX_CFG_F(WBNOINVD),
+	);
+}
+
+#undef TDX_CFG_F
+#undef TDX_CFG_EXTRA_F
 
 bool enable_tdx __ro_after_init;
 module_param_named(tdx, enable_tdx, bool, 0444);
@@ -3481,6 +3624,8 @@ int __init tdx_hardware_setup(void)
 		return r;
 	}
 
+	tdx_initialize_cpu_cfg_caps();
+
 	KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_tdx);
 
 	vt_x86_ops.vm_size = max_t(unsigned int, vt_x86_ops.vm_size, sizeof(struct kvm_tdx));
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable
  2026-08-27  3:18 [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
  2026-08-27  3:18 ` [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
@ 2026-08-27  3:18 ` Binbin Wu
  2026-09-01  6:45   ` Tony Lindgren
  2026-09-02 17:43   ` Kishen Maloor
  2026-08-27  3:18 ` [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits Binbin Wu
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-27  3:18 UTC (permalink / raw)
  To: linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao, binbin.wu

Add CORE_CAPABILITIES (CPUID.0x7.0.EDX[30]) to KVM's allowlist of TDX
directly configurable CPUID feature bits, even though KVM doesn't support
MSR_IA32_CORE_CAPS for TDX guests, to accommodate legacy TDX module
behavior.

Older TDX specs define the CORE_CAPABILITIES CPUID bit as fixed-1, so
userspace may expect the bit to be enabled for TDs.  If the bit becomes
directly configurable in a newer TDX module but is not reported as such to
userspace, userspace can no longer enable it once KVM starts validating
the CPUID configuration input.

Reporting CORE_CAPABILITIES as configurable keeps userspace able to enable
the bit across the fixed-1 => configurable transition, and lets userspace
infer that the bit is no longer fixed-1 so it can adjust its expectations.

Keep MSR_IA32_CORE_CAPS unsupported for TDX guests, as existing TDX users
have not needed guest access to the MSR, and advertising the CPUID bit as
configurable is enough for userspace to handle the legacy-module
compatibility case.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
v3:
- Move this patch earlier in the series to avoid breaking userspace during
  bisection. (Xiaoyao)
- Drop the code for MSR_IA32_CORE_CAPS access.
---
 arch/x86/kvm/vmx/tdx.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index d4a3a42cfd9d..b020518717ac 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -147,6 +147,12 @@ static void __init tdx_initialize_cpu_cfg_caps(void)
 		TDX_CFG_F(AVX512_VP2INTERSECT),
 		TDX_CFG_F(SERIALIZE),
 		TDX_CFG_F(TSXLDTRK),
+		/*
+		 * KVM does not support MSR_IA32_CORE_CAPS, but older TDX specs
+		 * define this bit as fixed-1.  Report it as configurable so
+		 * userspace can know the feature is no longer a fixed-1 bit.
+		 */
+		TDX_CFG_EXTRA_F(CORE_CAPABILITIES),
 	);
 
 	tdx_cpu_cfg_cap_init(CPUID_7_1_EAX,
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits
  2026-08-27  3:18 [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
  2026-08-27  3:18 ` [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
  2026-08-27  3:18 ` [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable Binbin Wu
@ 2026-08-27  3:18 ` Binbin Wu
  2026-09-01  6:44   ` Tony Lindgren
  2026-09-03  8:04   ` Xiaoyao Li
  2026-08-27  3:18 ` [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
  2026-08-27 19:33 ` [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Edgecombe, Rick P
  4 siblings, 2 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-27  3:18 UTC (permalink / raw)
  To: linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao, binbin.wu

Filter the directly configurable CPUID bits reported through
KVM_TDX_CAPABILITIES against KVM's TDX allowlist, and drop the hardcoded
denylist based filtering.

The TDX module reports all directly configurable CPUID bits that it
supports for a TD, but KVM must not expose bits that it doesn't support,
as blindly exposing a host state clobbering feature can lead to host state
corruption.  The existing denylist, which clears only TSX and WAITPKG, is
not fail-safe.

Add tdx_get_allowed_cfg_cpuid_mask() to get the mask of directly
configurable bits allowed by KVM for a given CPUID register, covering both
feature bits, which come from tdx_cpu_cfg_caps[], and non-feature bits,
which are enumerated at runtime.  Apply the mask to every CPUID register
reported through KVM_TDX_CAPABILITIES.

With the allowlist in place, newly introduced TDX directly configurable
CPUID bits stay hidden from userspace until KVM explicitly opts in.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
v3:
- Handle non-feature leafs at runtime. (Sean)
- Add CPUID.0x24.0.EBX[7:0] into allow list. There is a mismatch of the
  description about CPUID.0x24.0.EBX[7:0], which is listed as
  "XFAM & CPUID_Enabled & Native" but should be "XFAM & CPUID_Enabled &
  Configured & Native".
---
 arch/x86/kvm/vmx/tdx.c | 84 +++++++++++++++++++++++++++++++++---------
 1 file changed, 66 insertions(+), 18 deletions(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index b020518717ac..e8951353de73 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -277,34 +277,76 @@ static bool has_tsx(const struct kvm_cpuid_entry2 *entry)
 	       (entry->ebx & TDX_FEATURE_TSX);
 }
 
-static void clear_tsx(struct kvm_cpuid_entry2 *entry)
-{
-	entry->ebx &= ~TDX_FEATURE_TSX;
-}
-
 static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry)
 {
 	return entry->function == 7 && entry->index == 0 &&
 	       (entry->ecx & __feature_bit(X86_FEATURE_WAITPKG));
 }
 
-static void clear_waitpkg(struct kvm_cpuid_entry2 *entry)
+static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
 {
-	entry->ecx &= ~__feature_bit(X86_FEATURE_WAITPKG);
+	return has_tsx(entry) || has_waitpkg(entry);
 }
 
-static void tdx_clear_unsupported_cpuid(struct kvm_cpuid_entry2 *entry)
+#define TDX_CPUID_ALL_ALLOWED_MASK	GENMASK_U32(31, 0)
+
+static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
 {
-	if (has_tsx(entry))
-		clear_tsx(entry);
+	/*
+	 * For a leaf/subleaf/register that will never be repurposed to hold
+	 * feature bits, it's safe to return TDX_CPUID_ALL_ALLOWED_MASK, i.e.
+	 * leave the TDX module's CPUID config mask intact.
+	 */
+	switch (function) {
+	case 1:
+		if (reg == CPUID_EAX || reg == CPUID_EBX)
+			return TDX_CPUID_ALL_ALLOWED_MASK;
+		return 0;
+	case 4:
+	case 0x18:
+	case 0x1f:
+		return TDX_CPUID_ALL_ALLOWED_MASK;
+	case 0x24:
+		if (index == 0 && reg == CPUID_EBX)
+			return GENMASK_U32(7, 0);
+		return 0;
+	case 0x80000008:
+		if (reg == CPUID_EAX)
+			return TDX_CPUID_ALL_ALLOWED_MASK;
+		return 0;
+	default:
+		return 0;
+	}
+}
 
-	if (has_waitpkg(entry))
-		clear_waitpkg(entry);
+static u32 tdx_cfg_feature_mask(u32 function, u32 index, int reg)
+{
+	for (int i = 0; i < NR_KVM_CPU_CAPS; i++) {
+		const struct cpuid_reg *cpuid = &reverse_cpuid[i];
+
+		if (!cpuid->function)
+			continue;
+
+		if (cpuid->function == function && cpuid->index == index &&
+		    cpuid->reg == reg)
+			return tdx_cpu_cfg_caps[i];
+	}
+
+	return 0;
 }
 
-static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
+static u32 tdx_get_allowed_cfg_cpuid_mask(u32 function, u32 index, int reg)
 {
-	return has_tsx(entry) || has_waitpkg(entry);
+	u32 non_feature_mask = tdx_cfg_non_feature_mask(function, index, reg);
+
+	if (non_feature_mask == TDX_CPUID_ALL_ALLOWED_MASK)
+		return TDX_CPUID_ALL_ALLOWED_MASK;
+
+	/*
+	 * It's possible that a CPUID register contains both feature and
+	 * non-feature bits.
+	 */
+	return non_feature_mask | tdx_cfg_feature_mask(function, index, reg);
 }
 
 #define KVM_TDX_CPUID_NO_SUBLEAF	((__u32)-1)
@@ -330,8 +372,6 @@ static void td_init_cpuid_entry2(struct kvm_cpuid_entry2 *entry, unsigned char i
 	 */
 	if (entry->function == 0x80000008)
 		entry->eax = tdx_set_guest_phys_addr_bits(entry->eax, 0xff);
-
-	tdx_clear_unsupported_cpuid(entry);
 }
 
 #define TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT	BIT(1)
@@ -354,8 +394,16 @@ static int init_kvm_tdx_caps(const struct tdx_sys_info_td_conf *td_conf,
 	caps->user_tdvmcallinfo_1_r11 =
 		TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT;
 
-	for (i = 0; i < td_conf->num_cpuid_config; i++)
-		td_init_cpuid_entry2(&caps->cpuid.entries[i], i);
+	for (i = 0; i < td_conf->num_cpuid_config; i++) {
+		struct kvm_cpuid_entry2 *e = &caps->cpuid.entries[i];
+
+		td_init_cpuid_entry2(e, i);
+		/* Only report the configurable bits allowed by KVM. */
+		e->eax &= tdx_get_allowed_cfg_cpuid_mask(e->function, e->index, CPUID_EAX);
+		e->ebx &= tdx_get_allowed_cfg_cpuid_mask(e->function, e->index, CPUID_EBX);
+		e->ecx &= tdx_get_allowed_cfg_cpuid_mask(e->function, e->index, CPUID_ECX);
+		e->edx &= tdx_get_allowed_cfg_cpuid_mask(e->function, e->index, CPUID_EDX);
+	}
 
 	return 0;
 }
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
  2026-08-27  3:18 [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
                   ` (2 preceding siblings ...)
  2026-08-27  3:18 ` [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits Binbin Wu
@ 2026-08-27  3:18 ` Binbin Wu
  2026-08-27  3:24   ` sashiko-bot
  2026-09-01  6:47   ` Tony Lindgren
  2026-08-27 19:33 ` [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Edgecombe, Rick P
  4 siblings, 2 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-27  3:18 UTC (permalink / raw)
  To: linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao, binbin.wu

Validate the CPUID configuration provided by userspace through
KVM_TDX_INIT_VM against KVM's TDX allowlist, and drop the hardcoded
denylist based check.

The TDX module lets the VMM configure certain CPUID features for a TD at
initialization time, but KVM must strictly govern which of them userspace
can actually enable, otherwise a host state clobbering feature could be
enabled behind KVM's back.  The existing check only rejects TSX and
WAITPKG, i.e. it is not fail-safe, as any bit that a future TDX module
makes configurable would be accepted even if KVM has no idea about the
feature.

Add tdx_has_unsupported_cfg_cpuid_bit() and reject KVM_TDX_INIT_VM if
userspace sets any bit outside the mask returned by
tdx_get_allowed_cfg_cpuid_mask().  There is no need to first mask the
userspace input with the bits the TDX module reports as directly
configurable, as anything outside that set is rejected by the TDX module
itself.

Also reject CPUID entries whose index differs from the value expected by
the TDX module, as kvm_find_cpuid_entry2() ignores the index when
KVM_CPUID_FLAG_SIGNIFCANT_INDEX is cleared, and so a mismatching entry
could otherwise be applied to the wrong subleaf.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
v3:
- Check CPUID entry index mismatch b/t userspace input and TDX sysinfo
  configuration. (Sashiko)
- No need to mask the userspace input with TDX module reported directly
  configurable bits first, since the userspace input should be subset of
  directly configurable bits. Otherwise, the input will be rejected by
  the TDX module.
---
 arch/x86/kvm/vmx/tdx.c | 41 +++++++++++++++++++++--------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index e8951353de73..12dea8775fd4 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -269,25 +269,6 @@ static u32 tdx_set_guest_phys_addr_bits(const u32 eax, int addr_bits)
 	return (eax & ~GENMASK(23, 16)) | (addr_bits & 0xff) << 16;
 }
 
-#define TDX_FEATURE_TSX (__feature_bit(X86_FEATURE_HLE) | __feature_bit(X86_FEATURE_RTM))
-
-static bool has_tsx(const struct kvm_cpuid_entry2 *entry)
-{
-	return entry->function == 7 && entry->index == 0 &&
-	       (entry->ebx & TDX_FEATURE_TSX);
-}
-
-static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry)
-{
-	return entry->function == 7 && entry->index == 0 &&
-	       (entry->ecx & __feature_bit(X86_FEATURE_WAITPKG));
-}
-
-static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
-{
-	return has_tsx(entry) || has_waitpkg(entry);
-}
-
 #define TDX_CPUID_ALL_ALLOWED_MASK	GENMASK_U32(31, 0)
 
 static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
@@ -2533,6 +2514,17 @@ static int setup_tdparams_eptp_controls(struct kvm_cpuid2 *cpuid,
 	return 0;
 }
 
+static bool tdx_has_unsupported_cfg_cpuid_bit(const struct kvm_cpuid_entry2 *entry)
+{
+	u32 function = entry->function;
+	u32 index = entry->index;
+
+	return (entry->eax & ~tdx_get_allowed_cfg_cpuid_mask(function, index, CPUID_EAX)) ||
+	       (entry->ebx & ~tdx_get_allowed_cfg_cpuid_mask(function, index, CPUID_EBX)) ||
+	       (entry->ecx & ~tdx_get_allowed_cfg_cpuid_mask(function, index, CPUID_ECX)) ||
+	       (entry->edx & ~tdx_get_allowed_cfg_cpuid_mask(function, index, CPUID_EDX));
+}
+
 static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
 				 struct td_params *td_params)
 {
@@ -2556,7 +2548,16 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
 		if (!entry)
 			continue;
 
-		if (tdx_unsupported_cpuid(entry))
+		/*
+		 * Reject entries whose index does not match the expected one.
+		 * This catches userspace passing a CPUID entry with the
+		 * KVM_CPUID_FLAG_SIGNIFCANT_INDEX flag cleared when the index
+		 * is significant.
+		 */
+		if (entry->index != tmp.index)
+			return -EINVAL;
+
+		if (tdx_has_unsupported_cfg_cpuid_bit(entry))
 			return -EINVAL;
 
 		copy_cnt++;
-- 
2.46.0


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
  2026-08-27  3:18 ` [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
@ 2026-08-27  3:24   ` sashiko-bot
  2026-08-27  7:25     ` Binbin Wu
  2026-09-01  6:47   ` Tony Lindgren
  1 sibling, 1 reply; 44+ messages in thread
From: sashiko-bot @ 2026-08-27  3:24 UTC (permalink / raw)
  To: Binbin Wu; +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Missing bounds check on the hardware-reported `num_cpuid_config` leads to an out-of-bounds heap write when initializing TD parameters if the TDX module reports more than 48 CPUID configuration leaves.
--

commit 491ef15b15a75d61b2ded06ddb90ff6562206292
Author: Binbin Wu <binbin.wu@linux.intel.com>

KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM

This commit validates the CPUID configuration provided by userspace
through KVM_TDX_INIT_VM against KVM's TDX allowlist. It drops the
hardcoded denylist-based check and instead rejects entries matching
unsupported CPUID bits or entries with mismatching subleaf indices.

> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index e8951353de73c..12dea8775fd4f 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
[ ... ]
> @@ -2556,7 +2548,16 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
>  		if (!entry)
>  			continue;
>  
> -		if (tdx_unsupported_cpuid(entry))
> +		/*
> +		 * Reject entries whose index does not match the expected one.
> +		 * This catches userspace passing a CPUID entry with the
> +		 * KVM_CPUID_FLAG_SIGNIFCANT_INDEX flag cleared when the index
> +		 * is significant.
> +		 */
> +		if (entry->index != tmp.index)
> +			return -EINVAL;
> +
> +		if (tdx_has_unsupported_cfg_cpuid_bit(entry))
>  			return -EINVAL;
>  
>  		copy_cnt++;

[Severity: High]
This is a pre-existing issue, but does this loop in setup_tdparams_cpuids()
lack a bounds check on the hardware-reported td_conf->num_cpuid_config?

Looking at the loop just below this diff in arch/x86/kvm/vmx/tdx.c:

    for (i = 0; i < td_conf->num_cpuid_config; i++) {
        ...
        value = &td_params->cpuid_values[i];
        value->eax = entry->eax;
        ...

The target td_params is allocated with a strict 1024-byte size bound
in tdx_td_init():

    td_params = kzalloc_obj(struct td_params);

However, the hardware-reported num_cpuid_config can be up to 128. Because
struct td_params contains preceding fields and is bounded to 1024 bytes,
the cpuid_values flex array can safely hold a maximum of 48 entries.

If a TDX module supports more than 48 CPUID configuration leaves, this
iteration will blindly index past the 48th element, resulting in an
out-of-bounds heap write with user-controlled CPUID values.

Should num_cpuid_config be validated against the maximum capacity of
the td_params allocation?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260827031837.2863609-1-binbin.wu@linux.intel.com?part=4

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
  2026-08-27  3:24   ` sashiko-bot
@ 2026-08-27  7:25     ` Binbin Wu
  0 siblings, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-27  7:25 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: kvm



On 8/27/2026 11:24 AM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [High] Missing bounds check on the hardware-reported `num_cpuid_config` leads to an out-of-bounds heap write when initializing TD parameters if the TDX module reports more than 48 CPUID configuration leaves.
> --
> 
> commit 491ef15b15a75d61b2ded06ddb90ff6562206292
> Author: Binbin Wu <binbin.wu@linux.intel.com>
> 
> KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
> 
> This commit validates the CPUID configuration provided by userspace
> through KVM_TDX_INIT_VM against KVM's TDX allowlist. It drops the
> hardcoded denylist-based check and instead rejects entries matching
> unsupported CPUID bits or entries with mismatching subleaf indices.
> 
>> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
>> index e8951353de73c..12dea8775fd4f 100644
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
> [ ... ]
>> @@ -2556,7 +2548,16 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid,
>>  		if (!entry)
>>  			continue;
>>  
>> -		if (tdx_unsupported_cpuid(entry))
>> +		/*
>> +		 * Reject entries whose index does not match the expected one.
>> +		 * This catches userspace passing a CPUID entry with the
>> +		 * KVM_CPUID_FLAG_SIGNIFCANT_INDEX flag cleared when the index
>> +		 * is significant.
>> +		 */
>> +		if (entry->index != tmp.index)
>> +			return -EINVAL;
>> +
>> +		if (tdx_has_unsupported_cfg_cpuid_bit(entry))
>>  			return -EINVAL;
>>  
>>  		copy_cnt++;
> 
> [Severity: High]
> This is a pre-existing issue, but does this loop in setup_tdparams_cpuids()
> lack a bounds check on the hardware-reported td_conf->num_cpuid_config?
> 
> Looking at the loop just below this diff in arch/x86/kvm/vmx/tdx.c:
> 
>     for (i = 0; i < td_conf->num_cpuid_config; i++) {
>         ...
>         value = &td_params->cpuid_values[i];
>         value->eax = entry->eax;
>         ...
> 
> The target td_params is allocated with a strict 1024-byte size bound
> in tdx_td_init():
> 
>     td_params = kzalloc_obj(struct td_params);
> 
> However, the hardware-reported num_cpuid_config can be up to 128. Because
> struct td_params contains preceding fields and is bounded to 1024 bytes,
> the cpuid_values flex array can safely hold a maximum of 48 entries.
> 
> If a TDX module supports more than 48 CPUID configuration leaves, this
> iteration will blindly index past the 48th element, resulting in an
> out-of-bounds heap write with user-controlled CPUID values.
> 
> Should num_cpuid_config be validated against the maximum capacity of
> the td_params allocation?
> 

td_conf->num_cpuid_config is reported by the TDX module and gives the
number of leaves with directly configurable CPUIDs. struct td_params is
defined per the TDX spec with a fixed size of 1024 bytes, which is large
enough to hold every directly configurable CPUID leaf, i.e. exactly
num_cpuid_config entries. So the TDX module should never report a number
larger than td_params can accommodate.

So I think the finding is not a real vulnerability, but a cheap one-time
sanity check is still defensible.

I will send it as a separate hardening patch if there is no objection.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-08-27  3:18 [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
                   ` (3 preceding siblings ...)
  2026-08-27  3:18 ` [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
@ 2026-08-27 19:33 ` Edgecombe, Rick P
  2026-08-28  3:19   ` Binbin Wu
  4 siblings, 1 reply; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-08-27 19:33 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, Li, Xiaoyao, pbonzini@redhat.com,
	andrew.cooper3@citrix.com, nik.borisov@suse.com

On Thu, 2026-08-27 at 11:18 +0800, Binbin Wu wrote:
> Hi,
> 
> The purpose of this patch series is to prevent userspace from enabling
> host state clobbering features that KVM does not support for TDX.  A host
> state clobbering feature exposed on a new TDX module/platform can corrupt
> host state if KVM does not explicitly save and restore the related MSR(s)
> across host/guest transitions.  If such a feature is blindly exposed to
> and used by a TD, the host will behave unexpectedly.
> 
> Except for a few fixed-1 bits required for basic TDX support, host state
> clobbering features are either directly configurable or gated by TD
> ATTRIBUTES/XFAM.  So an allowlist covering only the directly configurable
> CPUID bits, plus the corresponding filtering and validation, is sufficient
> to serve the purpose while keeping the code footprint small.
> 
> Open question for Sean/Paolo
> ============================
> This revision comes long after Sean confirmed the overall direction on
> RFC v2 [1], due to internal discussions about a potential backward
> compatibility issue: a CPUID field can change virtualization type to
> directly configurable.  The TDX module can maintain backward
> compatibility in most cases; the problematic case is a single bit that
> was effectively "1" and non-configurable becoming directly configurable.
> The only scenario we can envision for that is an x86 feature deprecation.
> 
> In that case the TDX module has to decide how to handle deprecation,
> especially with respect to TD migration compatibility.  That
> pre-existing VMs with the deprecated feature enabled cannot migrate from
> an old platform to a new one is a problem shared by TDX and VMX, but the
> TDX module additionally has to decide:
> - Whether to allow TDs newly created on old platforms to migrate to new
>   platforms.
> - Whether to allow TDs created on new platforms to migrate to old
>   platforms.
> 
> There are two options:
> 1. Do not offer the VMM the ability to configure the bit, i.e. simply
>    report it as zero on platforms that no longer support the feature.
>    This disallows both migration cases above.
> 2. Make the bit directly configurable so the VMM can clear it even on
>    platforms that still support the feature, allowing both migration
>    cases above.  However, since the bit is not in KVM's allowlist,
>    userspace would no longer be able to enable it on old platforms after
>    a TDX module update.
> 
> Adding all supported CPUID bits to the allowlist, regardless of their
> virtualization type in the TDX module, would avoid the compatibility
> issue for option 2, at the cost of a significantly larger series.

I think we could only do this if no new fixed-1 bits are added. If they were,
then a future fixes-1 bit could be added then deprecated. An old kernel would
not know about it.

But we will not see new fixed-1 bits?

> 
> Given that x86 feature deprecation is expected to be very rare, and that
> Intel will discuss such cases with the community beforehand, does the
> approach taken by this series look acceptable?
> 

In the event a feature bit is turned configurable to support creating TDs that
can be migrated to new platforms without the feature, then the desired value for
the bit on the old platform will be 0. Which is what it would end up being set
as, if the bit was not in the KVM side allow list. So everything will work as
desired for that use?

But a user on the old platform that didn't care about migration and was using
the feature, would suddenly lose it after TDX module upgrade that turned the bit
configurable

But it isn't a kernel bug, so I'd think to punt on this and let TDX module
figure out a solution if/when the time comes. Probably various opt-in knobs to
allow for working around it. If they are not worried, we don't need to worry and
bloat the kernel to prepare for it.

>   If so, the goal for this
> revision is to collect detailed feedback and, where appropriate,
> Reviewed-by tags.
> 
> Expected host state clobbering behavior for TDX
> ===============================================
> We also want to call for discussions about the expected host state
> clobbering behavior for TDX here for future features.
> 
> For a normal VMX guest, VM entry/exit behavior for a given piece of CPU
> state is architecturally defined: state is either switched by hardware via
> VMCS host/guest fields, or left as the guest value on VM exit and managed
> by KVM in software.
> 
> For TDs, the host/guest transition goes through TDH.VP.ENTER, and what the
> TDX module does with a given piece of host state is defined by the TDX
> module ABI rather than by the x86 architecture.
> 
> What we would like to align on is the expected baseline behavior of
> TDH.VP.ENTER for future features.  The proposal is to have TDX simply
> match VMX behavior, i.e. on return from TDH.VP.ENTER, state that VMX would
> restore from the VMCS host fields is restored, and state that VMX would
> leave as the guest value is clobbered.  That keeps a single model for VMM,
> and means enabling a new feature for TDs requires the same work flow as
> enabling it for VMX.

Ideally the TDX save/restore would share code with normal VMs. On the other hand
if we don't share enter/exit paths sufficiently, we may need to duplicate some
save/restore in tdx code. Depending on how much of which category we have, it
could be better for the kernel to have either one.

And if TDX always saved/restored all state across VP.ENTER, then we don't need
bit filtering? What are the problems then with exposing everything to userspace
as we currently do?

> 
> FRED is a useful concrete example.  Under VMX, the FRED host state in
> IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP1-3 and
> IA32_FRED_SSP1-3 is covered by the VMCS host-state area, so the TDX module
> is expected to restore these MSRs on TDH.VP.ENTER return.  IA32_FRED_RSP0
> and IA32_PL0_SSP (a.k.a. IA32_FRED_SSP0) are handled by software, so the
> TDX module is expected to clobber them on TDH.VP.ENTER return.

And so the ability to have a design like this for the feature depends on CPUID
bit filtering to be in place, otherwise new modules on old kernels can clobber
host state unexpectedly. Future features that follow this approach will need
some VMM opt-in to say "VMM is filtering CPUID bit config", so TDX can safely
expose new clobbering bits. Otherwise, features like FRED will be problems on
old kernels. Do we want it? Where would it get plugged in?

> 
> The series
> ==========
> 
> Starting with v2 [2], the series takes a simpler, TDX-contained approach
> instead of the comprehensive CPUID paranoid verification framework across
> VMX, SVM, and TDX proposed in v1 [3].  It validates only the TDX directly
> configurable CPUID bits, which are reported by the TDX module in
> CPUID_CONFIG fields that the VMM can configure for a TD.  All filtering
> and validation logic is isolated within TDX code.  This is sufficient to
> address the host clobbering issue because:
> - The TDX module will not introduce new host state clobbering features
>   that are fixed-1.
> - Non-directly configurable feature bits (i.e. features controlled by XFAM
>   or ATTRIBUTES) cannot be enabled by userspace without KVM's support.
> 
> Specifically, this series builds a KVM-side allowlist of supported TDX
> directly configurable CPUID bits to:
>  - Filter KVM_TDX_CAPABILITIES
>    Replace the hardcoded denylist to only report configurable bits that
>    KVM explicitly supports.
>  - Validate KVM_TDX_INIT_VM
>    Reject any configurable bit that the TDX module allows but KVM does
>    not support, as well as CPUID entries with an unexpected subleaf.
> 
> With this allowlist, newly added TDX configurable CPUID bits will not be
> exposed to userspace until KVM explicitly opts in after fulfilling the
> necessary virtualization requirements.
> 
> The allowlist consists of two parts:
> - Feature CPUID bits, which are tracked in tdx_cpu_cfg_caps[] following
>   the organization of kvm_cpu_caps[].  It holds KVM's supported masks for
>   the TDX configurable CPUID feature bits.
> - Non-feature multi-bit fields, which are handled at runtime for the CPUID
>   registers holding such fields.
> 
> For compatibility with older TDX modules that report CORE_CAPABILITIES as
> fixed-1, report CORE_CAPABILITIES as configurable even though KVM does not
> support guest access to MSR_IA32_CORE_CAPS.  This allows userspace to keep
> enabling CORE_CAPABILITIES when the bit changes from fixed-1 to directly
> configurable, and allows userspace to infer that the bit is no longer
> fixed-1 so it can adjust its expectations.
> 
> Known limitation:
> - The series does not check KVM_SET_CPUID2 input for consistency with the
>   CPUID configuration supplied through KVM_TDX_INIT_VM.  This is not
>   required for host safety today because KVM does not use its vCPU CPUID
>   model to decide whether to manage host-clobbering state for TDs.  A
>   consistency check should be added if KVM ever starts relying on the vCPU
>   CPUID model for such decisions.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-08-27 19:33 ` [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Edgecombe, Rick P
@ 2026-08-28  3:19   ` Binbin Wu
  2026-08-28 16:58     ` Edgecombe, Rick P
  2026-09-01  9:38     ` Xiaoyao Li
  0 siblings, 2 replies; 44+ messages in thread
From: Binbin Wu @ 2026-08-28  3:19 UTC (permalink / raw)
  To: Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, Li, Xiaoyao, pbonzini@redhat.com,
	andrew.cooper3@citrix.com, nik.borisov@suse.com

On 8/28/2026 3:33 AM, Edgecombe, Rick P wrote:
> On Thu, 2026-08-27 at 11:18 +0800, Binbin Wu wrote:
>> Hi,
>>
>> The purpose of this patch series is to prevent userspace from enabling
>> host state clobbering features that KVM does not support for TDX.  A host
>> state clobbering feature exposed on a new TDX module/platform can corrupt
>> host state if KVM does not explicitly save and restore the related MSR(s)
>> across host/guest transitions.  If such a feature is blindly exposed to
>> and used by a TD, the host will behave unexpectedly.
>>
>> Except for a few fixed-1 bits required for basic TDX support, host state
>> clobbering features are either directly configurable or gated by TD
>> ATTRIBUTES/XFAM.  So an allowlist covering only the directly configurable
>> CPUID bits, plus the corresponding filtering and validation, is sufficient
>> to serve the purpose while keeping the code footprint small.
>>
>> Open question for Sean/Paolo
>> ============================
>> This revision comes long after Sean confirmed the overall direction on
>> RFC v2 [1], due to internal discussions about a potential backward
>> compatibility issue: a CPUID field can change virtualization type to
>> directly configurable.  The TDX module can maintain backward
>> compatibility in most cases; the problematic case is a single bit that
>> was effectively "1" and non-configurable becoming directly configurable.
>> The only scenario we can envision for that is an x86 feature deprecation.
>>
>> In that case the TDX module has to decide how to handle deprecation,
>> especially with respect to TD migration compatibility.  That
>> pre-existing VMs with the deprecated feature enabled cannot migrate from
>> an old platform to a new one is a problem shared by TDX and VMX, but the
>> TDX module additionally has to decide:
>> - Whether to allow TDs newly created on old platforms to migrate to new
>>   platforms.
>> - Whether to allow TDs created on new platforms to migrate to old
>>   platforms.
>>
>> There are two options:
>> 1. Do not offer the VMM the ability to configure the bit, i.e. simply
>>    report it as zero on platforms that no longer support the feature.
>>    This disallows both migration cases above.
>> 2. Make the bit directly configurable so the VMM can clear it even on
>>    platforms that still support the feature, allowing both migration
>>    cases above.  However, since the bit is not in KVM's allowlist,
>>    userspace would no longer be able to enable it on old platforms after
>>    a TDX module update.
>>
>> Adding all supported CPUID bits to the allowlist, regardless of their
>> virtualization type in the TDX module, would avoid the compatibility
>> issue for option 2, at the cost of a significantly larger series.
> 
> I think we could only do this if no new fixed-1 bits are added. If they were,
> then a future fixes-1 bit could be added then deprecated. An old kernel would
> not know about it.
> 
> But we will not see new fixed-1 bits?

The expectation is that no new fixed-1 bits will be added after the initial TDX
basic support. A new fixed-1 bit means the x86 architecture itself leaves the
TDX module no choice, so the TDX module will not add one unless some very
unusual future architectural change forces it to (and it's hard to see such a
design passing the design review in practice). If that ever does happen, it
would imply a significant architectural change, and we can figure out how to
handle it then.

> 
>>
>> Given that x86 feature deprecation is expected to be very rare, and that
>> Intel will discuss such cases with the community beforehand, does the
>> approach taken by this series look acceptable?
>>
> 
> In the event a feature bit is turned configurable to support creating TDs that
> can be migrated to new platforms without the feature, then the desired value for
> the bit on the old platform will be 0. Which is what it would end up being set
> as, if the bit was not in the KVM side allow list. So everything will work as
> desired for that use?

Yes, it would work for migration cases.

> 
> But a user on the old platform that didn't care about migration and was using
> the feature, would suddenly lose it after TDX module upgrade that turned the bit
> configurable

Yes. This is exactly the backward compatibility issue for option 2.
Though I am not sure how important it is when losing a feature that is being
deprecated.

> 
> But it isn't a kernel bug, so I'd think to punt on this and let TDX module
> figure out a solution if/when the time comes. Probably various opt-in knobs to
> allow for working around it.

Do you mean on the old platforms, the according TDX module versions add opt-in
knobs to allow the "effective 1 -> directly configurable" change?


> If they are not worried, we don't need to worry and
> bloat the kernel to prepare for it.
> 
>>   If so, the goal for this
>> revision is to collect detailed feedback and, where appropriate,
>> Reviewed-by tags.
>>
>> Expected host state clobbering behavior for TDX
>> ===============================================
>> We also want to call for discussions about the expected host state
>> clobbering behavior for TDX here for future features.
>>
>> For a normal VMX guest, VM entry/exit behavior for a given piece of CPU
>> state is architecturally defined: state is either switched by hardware via
>> VMCS host/guest fields, or left as the guest value on VM exit and managed
>> by KVM in software.
>>
>> For TDs, the host/guest transition goes through TDH.VP.ENTER, and what the
>> TDX module does with a given piece of host state is defined by the TDX
>> module ABI rather than by the x86 architecture.
>>
>> What we would like to align on is the expected baseline behavior of
>> TDH.VP.ENTER for future features.  The proposal is to have TDX simply
>> match VMX behavior, i.e. on return from TDH.VP.ENTER, state that VMX would
>> restore from the VMCS host fields is restored, and state that VMX would
>> leave as the guest value is clobbered.  That keeps a single model for VMM,
>> and means enabling a new feature for TDs requires the same work flow as
>> enabling it for VMX.
> 
> Ideally the TDX save/restore would share code with normal VMs. On the other hand
> if we don't share enter/exit paths sufficiently, we may need to duplicate some
> save/restore in tdx code.

It probably needs some TDX specific handling, since the TDX module clobbers the
MSRs (setting them to either their INIT values or some default values), whereas
in the VMX case the guest values are left.

 Depending on how much of which category we have, it
> could be better for the kernel to have either one.
> 
> And if TDX always saved/restored all state across VP.ENTER, then we don't need
> bit filtering? What are the problems then with exposing everything to userspace
> as we currently do?

One consideration is performance.

- When The TDX module clobbers an MSR, there are 1 RDMSR + 2 WRMSR
  TDX WRMSR to restore guest value
  ---
  TDX RDMSR to save guest value
  TDX WRMSR to set to default value
- When The TDX module save/restore an MSR, there are 2 RDMSR + 2 WRMSR
  TDX RDMSR to save host value
  TDX WRMSR to restore guest value
  ---
  TDX RDMSR to save guest value
  TDX WRMSR to restore host value

In most cases where the TDX module chooses to clobber an MSR rather than restore
the host value, that MSR isn't consumed in ring 0, so the Linux kernel/KVM
simply restores the value before returning to userspace.

That means for most TD entry/exit paths there is one extra MSR read per MSR.

Previously in the PUCK meeting, we proposed that the TDX module preserve host
state by default for any new feature, and provide an interface for the host VMM
to opt in to "don't preserve" as an optimization. That proposal wasn't pursued,
since Sean suggested letting KVM do the CPUID validation for TDX instead.

> 
>>
>> FRED is a useful concrete example.  Under VMX, the FRED host state in
>> IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP1-3 and
>> IA32_FRED_SSP1-3 is covered by the VMCS host-state area, so the TDX module
>> is expected to restore these MSRs on TDH.VP.ENTER return.  IA32_FRED_RSP0
>> and IA32_PL0_SSP (a.k.a. IA32_FRED_SSP0) are handled by software, so the
>> TDX module is expected to clobber them on TDH.VP.ENTER return.
> 
> And so the ability to have a design like this for the feature depends on CPUID
> bit filtering to be in place, otherwise new modules on old kernels can clobber
> host state unexpectedly. 

Yes.

> Future features that follow this approach will need
> some VMM opt-in to say "VMM is filtering CPUID bit config", so TDX can safely
> expose new clobbering bits. Otherwise, features like FRED will be problems on
> old kernels.

If FRED support lands in KVM for non-TDX VMs before this filtering/invalidation
is in place, adding FRED to the hardcoded denylist would work as a temporary
solution.

But that only holds for a well-behaved userspace VMM. QEMU, for example, only
enables features supported by both KVM and TDX, so if FRED isn't supported in
KVM for non-TDX VMs, QEMU won't enable it for TDX either.

A malicious userspace VMM, however, can set a feature regardless of KVM's
reported CPU capabilities, and could still cause trouble.

> Do we want it? Where would it get plugged in?

So if the approach in this series is taken, I think we still need such an opt-in
interface to tell the TDX module that the VMM is now filtering the CPUID bits so
that the TDX module knows that it's safe to report new host state clobbering
features.



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-08-28  3:19   ` Binbin Wu
@ 2026-08-28 16:58     ` Edgecombe, Rick P
  2026-08-31  5:01       ` Binbin Wu
  2026-09-01  9:38     ` Xiaoyao Li
  1 sibling, 1 reply; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-08-28 16:58 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, Li, Xiaoyao, pbonzini@redhat.com,
	andrew.cooper3@citrix.com, nik.borisov@suse.com

On Fri, 2026-08-28 at 11:19 +0800, Binbin Wu wrote:
> > 
> > But it isn't a kernel bug, so I'd think to punt on this and let TDX module
> > figure out a solution if/when the time comes. Probably various opt-in knobs
> > to allow for working around it.
> 
> Do you mean on the old platforms, the according TDX module versions add opt-in
> knobs to allow the "effective 1 -> directly configurable" change?

Yea. Or the other way. Forcing the old fixed-1 bits to 1 automatically. Could be
like a quirk like config thing. User/admin can decide if they want migration
flexible design, or backwards compatibility for existing TDs. BUT, we could work
out the details later if we think we have options.

I think I've convinced myself we have options and can close this one. Agreed?

<snip>
> 
> 
> If FRED support lands in KVM for non-TDX VMs before this
> filtering/invalidation is in place, adding FRED to the hardcoded denylist
> would work as a temporary solution.

This could easily happen.

> 
> But that only holds for a well-behaved userspace VMM. QEMU, for example, only
> enables features supported by both KVM and TDX, so if FRED isn't supported in
> KVM for non-TDX VMs, QEMU won't enable it for TDX either.
> 
> A malicious userspace VMM, however, can set a feature regardless of KVM's
> reported CPU capabilities, and could still cause trouble.

Right. It the problem I thought we would need an opt-in to avoid.

> 
> > Do we want it? Where would it get plugged in?
> 
> So if the approach in this series is taken, I think we still need such an opt-
> in interface to tell the TDX module that the VMM is now filtering the CPUID
> bits so that the TDX module knows that it's safe to report new host state
> clobbering features.

Yep. Can we think about what it would look like? Easiest would be a bit passed
in TDH_SYS_CONFIG. But then arch/x86 is saying how KVM will behave. Ok to me,
for the simplicity. Could come with a nice comment.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-08-28 16:58     ` Edgecombe, Rick P
@ 2026-08-31  5:01       ` Binbin Wu
  2026-09-01  9:42         ` Xiaoyao Li
  0 siblings, 1 reply; 44+ messages in thread
From: Binbin Wu @ 2026-08-31  5:01 UTC (permalink / raw)
  To: Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, Li, Xiaoyao, pbonzini@redhat.com,
	andrew.cooper3@citrix.com, nik.borisov@suse.com

On 8/29/2026 12:58 AM, Edgecombe, Rick P wrote:
> On Fri, 2026-08-28 at 11:19 +0800, Binbin Wu wrote:
>>>
>>> But it isn't a kernel bug, so I'd think to punt on this and let TDX module
>>> figure out a solution if/when the time comes. Probably various opt-in knobs
>>> to allow for working around it.
>>
>> Do you mean on the old platforms, the according TDX module versions add opt-in
>> knobs to allow the "effective 1 -> directly configurable" change?
> 
> Yea. Or the other way. Forcing the old fixed-1 bits to 1 automatically. Could be
> like a quirk like config thing. User/admin can decide if they want migration
> flexible design, or backwards compatibility for existing TDs.

It's all about the new created TDs on the old platforms. For existing TDs, the
runtime TDX module update should not change the shape of the TDs.

> BUT, we could work
> out the details later if we think we have options.
> 
> I think I've convinced myself we have options and can close this one. Agreed?

Agree.

> 
> <snip>
>>
>>
>> If FRED support lands in KVM for non-TDX VMs before this
>> filtering/invalidation is in place, adding FRED to the hardcoded denylist
>> would work as a temporary solution.
> 
> This could easily happen.
> 
>>
>> But that only holds for a well-behaved userspace VMM. QEMU, for example, only
>> enables features supported by both KVM and TDX, so if FRED isn't supported in
>> KVM for non-TDX VMs, QEMU won't enable it for TDX either.
>>
>> A malicious userspace VMM, however, can set a feature regardless of KVM's
>> reported CPU capabilities, and could still cause trouble.
> 
> Right. It the problem I thought we would need an opt-in to avoid.
> 
>>
>>> Do we want it? Where would it get plugged in?
>>
>> So if the approach in this series is taken, I think we still need such an opt-
>> in interface to tell the TDX module that the VMM is now filtering the CPUID
>> bits so that the TDX module knows that it's safe to report new host state
>> clobbering features.
> 
> Yep. Can we think about what it would look like? Easiest would be a bit passed
> in TDH_SYS_CONFIG. But then arch/x86 is saying how KVM will behave. Ok to me,
> for the simplicity. Could come with a nice comment.

The TDX module is initialized before KVM is loaded. I guess the upstream kernel
doesn't support out of tree KVM code, so we can assume if the kernel has the code to
opt-in the new host state clobbering features, KVM must have implemented the TDX
CPUID filtering and validation?

Also, do you think it's reasonable to backport this patch series to stable/LTS
kernels as an alternative?


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-08-27  3:18 ` [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
@ 2026-09-01  6:29   ` Tony Lindgren
  2026-09-01  8:23     ` Binbin Wu
  2026-09-01 14:35   ` Xiaoyao Li
  1 sibling, 1 reply; 44+ messages in thread
From: Tony Lindgren @ 2026-09-01  6:29 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On Thu, Aug 27, 2026 at 11:18:34AM +0800, Binbin Wu wrote:
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -52,6 +52,149 @@
>  	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
>  		     a1, a2, a3)
>  
> +static u32 tdx_cpu_cfg_caps[NR_KVM_CPU_CAPS] __ro_after_init;
> +static_assert(ARRAY_SIZE(tdx_cpu_cfg_caps) == ARRAY_SIZE(kvm_cpu_caps));
> +
> +#define TDX_VALIDATE_CPU_CAP_USAGE(name)			\
> +	BUILD_BUG_ON(__feature_leaf(X86_FEATURE_##name) !=	\
> +		     tdx_cpu_cap_init_in_progress)
> +
> +/* For feature bit that KVM advertised through kvm_cpu_caps[]. */
> +#define TDX_CFG_F(name)					\
> +({							\
> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
> +	tdx_cfg_caps |= feature_bit(name);		\
> +})
> +
> +/*
> + * For feature bit KVM allows for TDX guests even though it is not advertised
> + * through kvm_cpu_caps[], e.g. MWAIT.
> + */
> +#define TDX_CFG_EXTRA_F(name)				\
> +({							\
> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
> +	tdx_cfg_extra_caps |= feature_bit(name);	\
> +})
> +
> +#define tdx_cpu_cfg_cap_init(leaf, feature_initializers...)		\
> +do {									\
> +	const u32 __maybe_unused tdx_cpu_cap_init_in_progress = leaf;	\
> +	u32 tdx_cfg_extra_caps = 0;					\
> +	u32 tdx_cfg_caps = 0;						\
> +									\
> +	feature_initializers						\
> +	tdx_cpu_cfg_caps[leaf] = (tdx_cfg_caps & kvm_cpu_caps[leaf]) |	\
> +				 tdx_cfg_extra_caps;			\
> +} while (0)

How about make some of the above into just static functions for easier
readabilyt?

And then drop the __maybe_unused for tdx_cpu_cap_init_in_progress?

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits
  2026-08-27  3:18 ` [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits Binbin Wu
@ 2026-09-01  6:44   ` Tony Lindgren
  2026-09-01  8:42     ` Binbin Wu
  2026-09-03  8:04   ` Xiaoyao Li
  1 sibling, 1 reply; 44+ messages in thread
From: Tony Lindgren @ 2026-09-01  6:44 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On Thu, Aug 27, 2026 at 11:18:36AM +0800, Binbin Wu wrote:
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
...
> +static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
>  {
> -	if (has_tsx(entry))
> -		clear_tsx(entry);
> +	/*
> +	 * For a leaf/subleaf/register that will never be repurposed to hold
> +	 * feature bits, it's safe to return TDX_CPUID_ALL_ALLOWED_MASK, i.e.
> +	 * leave the TDX module's CPUID config mask intact.
> +	 */
> +	switch (function) {
> +	case 1:
> +		if (reg == CPUID_EAX || reg == CPUID_EBX)
> +			return TDX_CPUID_ALL_ALLOWED_MASK;
> +		return 0;
> +	case 4:
> +	case 0x18:
> +	case 0x1f:
> +		return TDX_CPUID_ALL_ALLOWED_MASK;
> +	case 0x24:
> +		if (index == 0 && reg == CPUID_EBX)
> +			return GENMASK_U32(7, 0);
> +		return 0;
> +	case 0x80000008:
> +		if (reg == CPUID_EAX)
> +			return TDX_CPUID_ALL_ALLOWED_MASK;
> +		return 0;
> +	default:
> +		return 0;
> +	}
> +}

How about rename the above to something simpler like tdx_get_cpuid_bits()?
Sorry I don't have anything better to suggest for naming.

> +static u32 tdx_cfg_feature_mask(u32 function, u32 index, int reg)
> +{
> +	for (int i = 0; i < NR_KVM_CPU_CAPS; i++) {
> +		const struct cpuid_reg *cpuid = &reverse_cpuid[i];
> +
> +		if (!cpuid->function)
> +			continue;
> +
> +		if (cpuid->function == function && cpuid->index == index &&
> +		    cpuid->reg == reg)
> +			return tdx_cpu_cfg_caps[i];
> +	}
> +
> +	return 0;
>  }

And then the above to tdx_get_cpuid_feature_bits()?
  
> -static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
> +static u32 tdx_get_allowed_cfg_cpuid_mask(u32 function, u32 index, int reg)
>  {
> -	return has_tsx(entry) || has_waitpkg(entry);
> +	u32 non_feature_mask = tdx_cfg_non_feature_mask(function, index, reg);
> +
> +	if (non_feature_mask == TDX_CPUID_ALL_ALLOWED_MASK)
> +		return TDX_CPUID_ALL_ALLOWED_MASK;
> +
> +	/*
> +	 * It's possible that a CPUID register contains both feature and
> +	 * non-feature bits.
> +	 */
> +	return non_feature_mask | tdx_cfg_feature_mask(function, index, reg);
>  }

And then tdx_get_cpuid_mask()?

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable
  2026-08-27  3:18 ` [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable Binbin Wu
@ 2026-09-01  6:45   ` Tony Lindgren
  2026-09-02 17:43   ` Kishen Maloor
  1 sibling, 0 replies; 44+ messages in thread
From: Tony Lindgren @ 2026-09-01  6:45 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On Thu, Aug 27, 2026 at 11:18:35AM +0800, Binbin Wu wrote:
> Add CORE_CAPABILITIES (CPUID.0x7.0.EDX[30]) to KVM's allowlist of TDX
> directly configurable CPUID feature bits, even though KVM doesn't support
> MSR_IA32_CORE_CAPS for TDX guests, to accommodate legacy TDX module
> behavior.
> 
> Older TDX specs define the CORE_CAPABILITIES CPUID bit as fixed-1, so
> userspace may expect the bit to be enabled for TDs.  If the bit becomes
> directly configurable in a newer TDX module but is not reported as such to
> userspace, userspace can no longer enable it once KVM starts validating
> the CPUID configuration input.
> 
> Reporting CORE_CAPABILITIES as configurable keeps userspace able to enable
> the bit across the fixed-1 => configurable transition, and lets userspace
> infer that the bit is no longer fixed-1 so it can adjust its expectations.
> 
> Keep MSR_IA32_CORE_CAPS unsupported for TDX guests, as existing TDX users
> have not needed guest access to the MSR, and advertising the CPUID bit as
> configurable is enough for userspace to handle the legacy-module
> compatibility case.

Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM
  2026-08-27  3:18 ` [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
  2026-08-27  3:24   ` sashiko-bot
@ 2026-09-01  6:47   ` Tony Lindgren
  1 sibling, 0 replies; 44+ messages in thread
From: Tony Lindgren @ 2026-09-01  6:47 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On Thu, Aug 27, 2026 at 11:18:37AM +0800, Binbin Wu wrote:
> Validate the CPUID configuration provided by userspace through
> KVM_TDX_INIT_VM against KVM's TDX allowlist, and drop the hardcoded
> denylist based check.
> 
> The TDX module lets the VMM configure certain CPUID features for a TD at
> initialization time, but KVM must strictly govern which of them userspace
> can actually enable, otherwise a host state clobbering feature could be
> enabled behind KVM's back.  The existing check only rejects TSX and
> WAITPKG, i.e. it is not fail-safe, as any bit that a future TDX module
> makes configurable would be accepted even if KVM has no idea about the
> feature.
> 
> Add tdx_has_unsupported_cfg_cpuid_bit() and reject KVM_TDX_INIT_VM if
> userspace sets any bit outside the mask returned by
> tdx_get_allowed_cfg_cpuid_mask().  There is no need to first mask the
> userspace input with the bits the TDX module reports as directly
> configurable, as anything outside that set is rejected by the TDX module
> itself.
> 
> Also reject CPUID entries whose index differs from the value expected by
> the TDX module, as kvm_find_cpuid_entry2() ignores the index when
> KVM_CPUID_FLAG_SIGNIFCANT_INDEX is cleared, and so a mismatching entry
> could otherwise be applied to the wrong subleaf.

This nicely cleans up the earlier handling:

Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-01  6:29   ` Tony Lindgren
@ 2026-09-01  8:23     ` Binbin Wu
  2026-09-01  8:27       ` Tony Lindgren
  0 siblings, 1 reply; 44+ messages in thread
From: Binbin Wu @ 2026-09-01  8:23 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On 9/1/2026 2:29 PM, Tony Lindgren wrote:
> On Thu, Aug 27, 2026 at 11:18:34AM +0800, Binbin Wu wrote:
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
>> @@ -52,6 +52,149 @@
>>  	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
>>  		     a1, a2, a3)
>>  
>> +static u32 tdx_cpu_cfg_caps[NR_KVM_CPU_CAPS] __ro_after_init;
>> +static_assert(ARRAY_SIZE(tdx_cpu_cfg_caps) == ARRAY_SIZE(kvm_cpu_caps));
>> +
>> +#define TDX_VALIDATE_CPU_CAP_USAGE(name)			\
>> +	BUILD_BUG_ON(__feature_leaf(X86_FEATURE_##name) !=	\
>> +		     tdx_cpu_cap_init_in_progress)
>> +
>> +/* For feature bit that KVM advertised through kvm_cpu_caps[]. */
>> +#define TDX_CFG_F(name)					\
>> +({							\
>> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
>> +	tdx_cfg_caps |= feature_bit(name);		\
>> +})
>> +
>> +/*
>> + * For feature bit KVM allows for TDX guests even though it is not advertised
>> + * through kvm_cpu_caps[], e.g. MWAIT.
>> + */
>> +#define TDX_CFG_EXTRA_F(name)				\
>> +({							\
>> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
>> +	tdx_cfg_extra_caps |= feature_bit(name);	\
>> +})
>> +
>> +#define tdx_cpu_cfg_cap_init(leaf, feature_initializers...)		\
>> +do {									\
>> +	const u32 __maybe_unused tdx_cpu_cap_init_in_progress = leaf;	\
>> +	u32 tdx_cfg_extra_caps = 0;					\
>> +	u32 tdx_cfg_caps = 0;						\
>> +									\
>> +	feature_initializers						\
>> +	tdx_cpu_cfg_caps[leaf] = (tdx_cfg_caps & kvm_cpu_caps[leaf]) |	\
>> +				 tdx_cfg_extra_caps;			\
>> +} while (0)
> 
> How about make some of the above into just static functions for easier
> readabilyt?

Thanks for your review!

This deliberately mirrors the existing kvm_cpu_cap_init() / F() / XXX_F()
pattern in arch/x86/kvm/cpuid.c.

Similar to kvm_cpu_cap_init(), tdx_cpu_cfg_cap_init() takes a variadic list of
statements that mutate two local accumulators (tdx_cfg_caps, tdx_cfg_extra_caps). 
That's inherently a macro-scoped construct.

> 
> And then drop the __maybe_unused for tdx_cpu_cap_init_in_progress?




^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-01  8:23     ` Binbin Wu
@ 2026-09-01  8:27       ` Tony Lindgren
  0 siblings, 0 replies; 44+ messages in thread
From: Tony Lindgren @ 2026-09-01  8:27 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On Tue, Sep 01, 2026 at 04:23:00PM +0800, Binbin Wu wrote:
> On 9/1/2026 2:29 PM, Tony Lindgren wrote:
> > On Thu, Aug 27, 2026 at 11:18:34AM +0800, Binbin Wu wrote:
> >> --- a/arch/x86/kvm/vmx/tdx.c
> >> +++ b/arch/x86/kvm/vmx/tdx.c
> >> @@ -52,6 +52,149 @@
> >>  	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
> >>  		     a1, a2, a3)
> >>  
> >> +static u32 tdx_cpu_cfg_caps[NR_KVM_CPU_CAPS] __ro_after_init;
> >> +static_assert(ARRAY_SIZE(tdx_cpu_cfg_caps) == ARRAY_SIZE(kvm_cpu_caps));
> >> +
> >> +#define TDX_VALIDATE_CPU_CAP_USAGE(name)			\
> >> +	BUILD_BUG_ON(__feature_leaf(X86_FEATURE_##name) !=	\
> >> +		     tdx_cpu_cap_init_in_progress)
> >> +
> >> +/* For feature bit that KVM advertised through kvm_cpu_caps[]. */
> >> +#define TDX_CFG_F(name)					\
> >> +({							\
> >> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
> >> +	tdx_cfg_caps |= feature_bit(name);		\
> >> +})
> >> +
> >> +/*
> >> + * For feature bit KVM allows for TDX guests even though it is not advertised
> >> + * through kvm_cpu_caps[], e.g. MWAIT.
> >> + */
> >> +#define TDX_CFG_EXTRA_F(name)				\
> >> +({							\
> >> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
> >> +	tdx_cfg_extra_caps |= feature_bit(name);	\
> >> +})
> >> +
> >> +#define tdx_cpu_cfg_cap_init(leaf, feature_initializers...)		\
> >> +do {									\
> >> +	const u32 __maybe_unused tdx_cpu_cap_init_in_progress = leaf;	\
> >> +	u32 tdx_cfg_extra_caps = 0;					\
> >> +	u32 tdx_cfg_caps = 0;						\
> >> +									\
> >> +	feature_initializers						\
> >> +	tdx_cpu_cfg_caps[leaf] = (tdx_cfg_caps & kvm_cpu_caps[leaf]) |	\
> >> +				 tdx_cfg_extra_caps;			\
> >> +} while (0)
> > 
> > How about make some of the above into just static functions for easier
> > readabilyt?
> 
> Thanks for your review!
> 
> This deliberately mirrors the existing kvm_cpu_cap_init() / F() / XXX_F()
> pattern in arch/x86/kvm/cpuid.c.
> 
> Similar to kvm_cpu_cap_init(), tdx_cpu_cfg_cap_init() takes a variadic list of
> statements that mutate two local accumulators (tdx_cfg_caps, tdx_cfg_extra_caps). 
> That's inherently a macro-scoped construct.

Ah OK thanks I now noticed the feature_initializers.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits
  2026-09-01  6:44   ` Tony Lindgren
@ 2026-09-01  8:42     ` Binbin Wu
  2026-09-01  9:09       ` Tony Lindgren
  0 siblings, 1 reply; 44+ messages in thread
From: Binbin Wu @ 2026-09-01  8:42 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On 9/1/2026 2:44 PM, Tony Lindgren wrote:
> On Thu, Aug 27, 2026 at 11:18:36AM +0800, Binbin Wu wrote:
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
> ...
>> +static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
>>  {
>> -	if (has_tsx(entry))
>> -		clear_tsx(entry);
>> +	/*
>> +	 * For a leaf/subleaf/register that will never be repurposed to hold
>> +	 * feature bits, it's safe to return TDX_CPUID_ALL_ALLOWED_MASK, i.e.
>> +	 * leave the TDX module's CPUID config mask intact.
>> +	 */
>> +	switch (function) {
>> +	case 1:
>> +		if (reg == CPUID_EAX || reg == CPUID_EBX)
>> +			return TDX_CPUID_ALL_ALLOWED_MASK;
>> +		return 0;
>> +	case 4:
>> +	case 0x18:
>> +	case 0x1f:
>> +		return TDX_CPUID_ALL_ALLOWED_MASK;
>> +	case 0x24:
>> +		if (index == 0 && reg == CPUID_EBX)
>> +			return GENMASK_U32(7, 0);
>> +		return 0;
>> +	case 0x80000008:
>> +		if (reg == CPUID_EAX)
>> +			return TDX_CPUID_ALL_ALLOWED_MASK;
>> +		return 0;
>> +	default:
>> +		return 0;
>> +	}
>> +}
> 
> How about rename the above to something simpler like tdx_get_cpuid_bits()?
> Sorry I don't have anything better to suggest for naming.
> 
>> +static u32 tdx_cfg_feature_mask(u32 function, u32 index, int reg)
>> +{
>> +	for (int i = 0; i < NR_KVM_CPU_CAPS; i++) {
>> +		const struct cpuid_reg *cpuid = &reverse_cpuid[i];
>> +
>> +		if (!cpuid->function)
>> +			continue;
>> +
>> +		if (cpuid->function == function && cpuid->index == index &&
>> +		    cpuid->reg == reg)
>> +			return tdx_cpu_cfg_caps[i];
>> +	}
>> +
>> +	return 0;
>>  }
> 
> And then the above to tdx_get_cpuid_feature_bits()?
>   
>> -static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
>> +static u32 tdx_get_allowed_cfg_cpuid_mask(u32 function, u32 index, int reg)
>>  {
>> -	return has_tsx(entry) || has_waitpkg(entry);
>> +	u32 non_feature_mask = tdx_cfg_non_feature_mask(function, index, reg);
>> +
>> +	if (non_feature_mask == TDX_CPUID_ALL_ALLOWED_MASK)
>> +		return TDX_CPUID_ALL_ALLOWED_MASK;
>> +
>> +	/*
>> +	 * It's possible that a CPUID register contains both feature and
>> +	 * non-feature bits.
>> +	 */
>> +	return non_feature_mask | tdx_cfg_feature_mask(function, index, reg);
>>  }
> 
> And then tdx_get_cpuid_mask()?

How about:
tdx_get_cpuid_cfg_non_feature_mask()
tdx_get_cpuid_cfg_feature_mask()
tdx_get_cpuid_cfg_mask()


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits
  2026-09-01  8:42     ` Binbin Wu
@ 2026-09-01  9:09       ` Tony Lindgren
  0 siblings, 0 replies; 44+ messages in thread
From: Tony Lindgren @ 2026-09-01  9:09 UTC (permalink / raw)
  To: Binbin Wu
  Cc: linux-kernel, kvm, seanjc, pbonzini, dave.hansen, andrew.cooper3,
	nik.borisov, kas, rick.p.edgecombe, xiaoyao.li, chao.gao

On Tue, Sep 01, 2026 at 04:42:20PM +0800, Binbin Wu wrote:
> On 9/1/2026 2:44 PM, Tony Lindgren wrote:
> > On Thu, Aug 27, 2026 at 11:18:36AM +0800, Binbin Wu wrote:
> >> --- a/arch/x86/kvm/vmx/tdx.c
> >> +++ b/arch/x86/kvm/vmx/tdx.c
> > ...
> >> +static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
> >>  {
> >> -	if (has_tsx(entry))
> >> -		clear_tsx(entry);
> >> +	/*
> >> +	 * For a leaf/subleaf/register that will never be repurposed to hold
> >> +	 * feature bits, it's safe to return TDX_CPUID_ALL_ALLOWED_MASK, i.e.
> >> +	 * leave the TDX module's CPUID config mask intact.
> >> +	 */
> >> +	switch (function) {
> >> +	case 1:
> >> +		if (reg == CPUID_EAX || reg == CPUID_EBX)
> >> +			return TDX_CPUID_ALL_ALLOWED_MASK;
> >> +		return 0;
> >> +	case 4:
> >> +	case 0x18:
> >> +	case 0x1f:
> >> +		return TDX_CPUID_ALL_ALLOWED_MASK;
> >> +	case 0x24:
> >> +		if (index == 0 && reg == CPUID_EBX)
> >> +			return GENMASK_U32(7, 0);
> >> +		return 0;
> >> +	case 0x80000008:
> >> +		if (reg == CPUID_EAX)
> >> +			return TDX_CPUID_ALL_ALLOWED_MASK;
> >> +		return 0;
> >> +	default:
> >> +		return 0;
> >> +	}
> >> +}
> > 
> > How about rename the above to something simpler like tdx_get_cpuid_bits()?
> > Sorry I don't have anything better to suggest for naming.
> > 
> >> +static u32 tdx_cfg_feature_mask(u32 function, u32 index, int reg)
> >> +{
> >> +	for (int i = 0; i < NR_KVM_CPU_CAPS; i++) {
> >> +		const struct cpuid_reg *cpuid = &reverse_cpuid[i];
> >> +
> >> +		if (!cpuid->function)
> >> +			continue;
> >> +
> >> +		if (cpuid->function == function && cpuid->index == index &&
> >> +		    cpuid->reg == reg)
> >> +			return tdx_cpu_cfg_caps[i];
> >> +	}
> >> +
> >> +	return 0;
> >>  }
> > 
> > And then the above to tdx_get_cpuid_feature_bits()?
> >   
> >> -static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
> >> +static u32 tdx_get_allowed_cfg_cpuid_mask(u32 function, u32 index, int reg)
> >>  {
> >> -	return has_tsx(entry) || has_waitpkg(entry);
> >> +	u32 non_feature_mask = tdx_cfg_non_feature_mask(function, index, reg);
> >> +
> >> +	if (non_feature_mask == TDX_CPUID_ALL_ALLOWED_MASK)
> >> +		return TDX_CPUID_ALL_ALLOWED_MASK;
> >> +
> >> +	/*
> >> +	 * It's possible that a CPUID register contains both feature and
> >> +	 * non-feature bits.
> >> +	 */
> >> +	return non_feature_mask | tdx_cfg_feature_mask(function, index, reg);
> >>  }
> > 
> > And then tdx_get_cpuid_mask()?
> 
> How about:
> tdx_get_cpuid_cfg_non_feature_mask()
> tdx_get_cpuid_cfg_feature_mask()
> tdx_get_cpuid_cfg_mask()

I'd be happy with that.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-08-28  3:19   ` Binbin Wu
  2026-08-28 16:58     ` Edgecombe, Rick P
@ 2026-09-01  9:38     ` Xiaoyao Li
  2026-09-01 17:41       ` Edgecombe, Rick P
  1 sibling, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-01  9:38 UTC (permalink / raw)
  To: Binbin Wu, Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, pbonzini@redhat.com, andrew.cooper3@citrix.com,
	nik.borisov@suse.com

On 8/28/2026 11:19 AM, Binbin Wu wrote:
> On 8/28/2026 3:33 AM, Edgecombe, Rick P wrote:
>> On Thu, 2026-08-27 at 11:18 +0800, Binbin Wu wrote:

<snip>

>>> Expected host state clobbering behavior for TDX
>>> ===============================================
>>> We also want to call for discussions about the expected host state
>>> clobbering behavior for TDX here for future features.
>>>
>>> For a normal VMX guest, VM entry/exit behavior for a given piece of CPU
>>> state is architecturally defined: state is either switched by hardware via
>>> VMCS host/guest fields, or left as the guest value on VM exit and managed
>>> by KVM in software.
>>>
>>> For TDs, the host/guest transition goes through TDH.VP.ENTER, and what the
>>> TDX module does with a given piece of host state is defined by the TDX
>>> module ABI rather than by the x86 architecture.
>>>
>>> What we would like to align on is the expected baseline behavior of
>>> TDH.VP.ENTER for future features.  The proposal is to have TDX simply
>>> match VMX behavior, i.e. on return from TDH.VP.ENTER, state that VMX would
>>> restore from the VMCS host fields is restored, and state that VMX would
>>> leave as the guest value is clobbered.  That keeps a single model for VMM,
>>> and means enabling a new feature for TDs requires the same work flow as
>>> enabling it for VMX.
>>
>> Ideally the TDX save/restore would share code with normal VMs. On the other hand
>> if we don't share enter/exit paths sufficiently, we may need to duplicate some
>> save/restore in tdx code.

(Copy the FRED example here for reference)

 >>>
 >>> FRED is a useful concrete example.  Under VMX, the FRED host state in
 >>> IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP1-3 and
 >>> IA32_FRED_SSP1-3 is covered by the VMCS host-state area, so the TDX 
module
 >>> is expected to restore these MSRs on TDH.VP.ENTER return. 
IA32_FRED_RSP0
 >>> and IA32_PL0_SSP (a.k.a. IA32_FRED_SSP0) are handled by software, 
so the
 >>> TDX module is expected to clobber them on TDH.VP.ENTER return.

What I get, is not matching VMX behavior but matching the behavior KVM 
will perform for VMX. They are based on the assumption that KVM will 
always enable the save/restore VMCS fields for a new feature. But I 
don't think we can guarantee it.

To me, "have TDX simply match VMX behavior" means:

1. if the VMX unconditionally save/restore a state, then TDX will do so.

2. if there are vm-entry/vm-exit load/save VMCS fields for a state, then 
provide the equivalent per-TD configurable interfaces which matches the 
VMCS fields.

> It probably needs some TDX specific handling, since the TDX module clobbers the
> MSRs (setting them to either their INIT values or some default values), whereas
> in the VMX case the guest values are left.
> 
>> Depending on how much of which category we have, it
>> could be better for the kernel to have either one.
>>
>> And if TDX always saved/restored all state across VP.ENTER, then we don't need
>> bit filtering? What are the problems then with exposing everything to userspace
>> as we currently do?

IMO, allowing userspace to expose/enable a new feature to a guest 
without KVM first evaluating it is always dangerous. It's not just about 
the state clobbering. We can know the implication for a new feature.

For example, a feature consumes global per-socket resources. Allowing 
guest to use the feature might slowdown the host.

Another example is a feature is used to catch bad behaviors, and in this 
case host would like to enforce the feature being forced on for the 
guest instead of allowing the guest to use (disable) the feature freely.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-08-31  5:01       ` Binbin Wu
@ 2026-09-01  9:42         ` Xiaoyao Li
  2026-09-01 10:21           ` Xiaoyao Li
  2026-09-02 16:09           ` Edgecombe, Rick P
  0 siblings, 2 replies; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-01  9:42 UTC (permalink / raw)
  To: Binbin Wu, Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, pbonzini@redhat.com, andrew.cooper3@citrix.com,
	nik.borisov@suse.com

On 8/31/2026 1:01 PM, Binbin Wu wrote:
>>> So if the approach in this series is taken, I think we still need such an opt-
>>> in interface to tell the TDX module that the VMM is now filtering the CPUID
>>> bits so that the TDX module knows that it's safe to report new host state
>>> clobbering features.
>> Yep. Can we think about what it would look like? Easiest would be a bit passed
>> in TDH_SYS_CONFIG. But then arch/x86 is saying how KVM will behave. Ok to me,
>> for the simplicity. Could come with a nice comment.

Can you just treat current KVM behavior of allowing userspace to enable 
any configurable bits as the bug of KVM and backport this series as 
Binbin suggested below? Instead of introducing more opt-in knobs.

> The TDX module is initialized before KVM is loaded. I guess the upstream kernel
> doesn't support out of tree KVM code, so we can assume if the kernel has the code to
> opt-in the new host state clobbering features, KVM must have implemented the TDX
> CPUID filtering and validation?
> 
> Also, do you think it's reasonable to backport this patch series to stable/LTS
> kernels as an alternative?



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-01  9:42         ` Xiaoyao Li
@ 2026-09-01 10:21           ` Xiaoyao Li
  2026-09-02 16:09           ` Edgecombe, Rick P
  1 sibling, 0 replies; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-01 10:21 UTC (permalink / raw)
  To: Binbin Wu, Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: Gao, Chao, seanjc@google.com, dave.hansen@linux.intel.com,
	kas@kernel.org, pbonzini@redhat.com, andrew.cooper3@citrix.com,
	nik.borisov@suse.com

On 9/1/2026 5:42 PM, Xiaoyao Li wrote:
> On 8/31/2026 1:01 PM, Binbin Wu wrote:
>>>> So if the approach in this series is taken, I think we still need 
>>>> such an opt-
>>>> in interface to tell the TDX module that the VMM is now filtering 
>>>> the CPUID
>>>> bits so that the TDX module knows that it's safe to report new host 
>>>> state
>>>> clobbering features.
>>> Yep. Can we think about what it would look like? Easiest would be a 
>>> bit passed
>>> in TDH_SYS_CONFIG. But then arch/x86 is saying how KVM will behave. 
>>> Ok to me,
>>> for the simplicity. Could come with a nice comment.
> 
> Can you just treat current KVM behavior of allowing userspace to enable 

well, I meant "can we"...

> any configurable bits as the bug of KVM and backport this series as 
> Binbin suggested below? Instead of introducing more opt-in knobs.
> 
>> The TDX module is initialized before KVM is loaded. I guess the 
>> upstream kernel
>> doesn't support out of tree KVM code, so we can assume if the kernel 
>> has the code to
>> opt-in the new host state clobbering features, KVM must have 
>> implemented the TDX
>> CPUID filtering and validation?
>>
>> Also, do you think it's reasonable to backport this patch series to 
>> stable/LTS
>> kernels as an alternative?
> 


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-08-27  3:18 ` [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
  2026-09-01  6:29   ` Tony Lindgren
@ 2026-09-01 14:35   ` Xiaoyao Li
  2026-09-02  0:33     ` Binbin Wu
  1 sibling, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-01 14:35 UTC (permalink / raw)
  To: Binbin Wu, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 8/27/2026 11:18 AM, Binbin Wu wrote:
> Add tdx_cpu_cfg_caps[] to track the subset of TDX directly configurable
> CPUID feature bits that KVM supports, and build the masks during TDX
> hardware setup via tdx_initialize_cpu_cfg_caps().
> 
> The TDX module reports the CPUID bits that the VMM can directly configure
> for a TD, but KVM cannot blindly expose all reported bits to userspace.
> Certain features imply additional architectural state, e.g. one or more
> MSRs, that KVM must explicitly manage across host/guest transitions to
> prevent host state corruption.
> 
> Today KVM relies on a hardcoded denylist, i.e. it clears a few known
> problematic bits, e.g. TSX and WAITPKG, and passes everything else through.
> A denylist is fundamentally fragile while an allowlist inverts the default,
> i.e. unknown configurable bits are hidden and not allowed to be enabled
> until KVM explicitly opts in.
> 
> Except for a few fixed-1 bits required for basic TDX support, host state
> clobbering features are either directly configurable or gated by TD
> ATTRIBUTES/XFAM.  

> Tracking only the directly configurable feature bits is
> therefore sufficient to serve the purpose while keeping the code footprint
> small.

I'm not clear how it is therefore sufficient. We at least need to 
explain that ATTRIBUTS/XFAM are validated separately by KVM already?
> Organize tdx_cpu_cfg_caps[] following kvm_cpu_caps[] so that the masks can
> be built with the similar feature-name based initializers.  CPUID registers
> that hold directly configurable non-feature (multi-bit) fields are handled
> separately.
> 
> The allowlist is consumed by later patches to filter KVM_TDX_CAPABILITIES
> and to reject unsupported CPUID input to KVM_TDX_INIT_VM, so that newly
> introduced TDX directly configurable CPUID feature bits stay hidden from
> userspace until KVM explicitly opts in.
> 
> Add comments as placeholders for HLE, RTM and WAITPKG, which KVM doesn't
> support for TDX yet.
> 
> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
> ---
> v3:
> - Drop the new data structure in v2 and only track feature bits by
>    following the organization of kvm_cpu_caps[], handle non-feature
>    bits separately. (Sean)
> - Use two versions of macros (TDX_CFG_F() VS. TDX_CFG_EXTRA_F()) to
>    distinguish whether a supported TDX configurable CPUID bit should be
>    checked against KVM's common cpu capabilities.
> - Add AMX_COMPLEX since it has been defined in the CPUID virtualization doc.
> ---
>   arch/x86/kvm/vmx/tdx.c | 145 +++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 145 insertions(+)
> 
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index b272c20586a7..d4a3a42cfd9d 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -52,6 +52,149 @@
>   	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
>   		     a1, a2, a3)
>   
> +static u32 tdx_cpu_cfg_caps[NR_KVM_CPU_CAPS] __ro_after_init;
> +static_assert(ARRAY_SIZE(tdx_cpu_cfg_caps) == ARRAY_SIZE(kvm_cpu_caps));
> +
> +#define TDX_VALIDATE_CPU_CAP_USAGE(name)			\
> +	BUILD_BUG_ON(__feature_leaf(X86_FEATURE_##name) !=	\
> +		     tdx_cpu_cap_init_in_progress)
> +
> +/* For feature bit that KVM advertised through kvm_cpu_caps[]. */

I would say it

For feature bit that needs to be cap'ed by kvm_cpu_caps[]

> +#define TDX_CFG_F(name)					\
> +({							\
> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
> +	tdx_cfg_caps |= feature_bit(name);		\
> +})
> +
> +/*
> + * For feature bit KVM allows for TDX guests even though it is not advertised
> + * through kvm_cpu_caps[], e.g. MWAIT.
> + */
> +#define TDX_CFG_EXTRA_F(name)				\

EXTRA doesn't sound like a fit name, though

> +({							\
> +	TDX_VALIDATE_CPU_CAP_USAGE(name);		\
> +	tdx_cfg_extra_caps |= feature_bit(name);	\
> +})
> +
> +#define tdx_cpu_cfg_cap_init(leaf, feature_initializers...)		\
> +do {									\
> +	const u32 __maybe_unused tdx_cpu_cap_init_in_progress = leaf;	\
> +	u32 tdx_cfg_extra_caps = 0;					\
> +	u32 tdx_cfg_caps = 0;						\
> +									\
> +	feature_initializers						\
> +	tdx_cpu_cfg_caps[leaf] = (tdx_cfg_caps & kvm_cpu_caps[leaf]) |	\
> +				 tdx_cfg_extra_caps;			\
> +} while (0)
> +
> +/*
> + * Track only CPUID feature bits that are directly configurable by userspace.

the "by userspace" is misleading. It's just the directly configurable 
CPUID bits reported by TDX module.

> + * Features controlled by XFAM or ATTRIBUTES are excluded; userspace cannot
> + * enable them until KVM adds support for the corresponding control.
> + */

I don't like the comments. How about somthing

/*
  * Intialize tdx_cpu_cfg_caps[], which is list of CPUID features that
  * KVM supports for TDX. It only covers the directly configurable CPIUD
  * bits reported by TDX module. Features controlled by XFAM and
  * ATTRIBUTES are maintained separately.
  */

> +static void __init tdx_initialize_cpu_cfg_caps(void)
> +{
> +	tdx_cpu_cfg_cap_init(CPUID_1_ECX,
> +		TDX_CFG_EXTRA_F(MWAIT),
> +		TDX_CFG_F(TSC_DEADLINE_TIMER),
> +		TDX_CFG_F(AVX),
> +		TDX_CFG_F(F16C),
> +	);

TDX 1.5.24 on SPR report configurable bits of CPUID_1_ECX as
0x31044988, which have

- bit 3		MWAIT
- bit 7		EST
- bit 8		TM2
- bit 11	SDBG
- bit 14	XTPR
- bit 18	DCA
- bit 24	TSC_DEADLINE_TIMER
- bit 28	AVX
- bit 29	F16C

but EST/TM2/SDBG/XTPR/DCA are not list here. I guess the reason is 
kvm_cpu_cap[] doesn't support it. If so, it seems to guard twice:
1. mentally/manually check if it a feature is supported in kvm_cpu_caps[]

2. kvm_cpu_caps guarding in tdx_cpu_cfg_cap_init().

I think 1) is not necessary, we can rely on 2)

BTW, this seems also breaks the current userspace after this series.
- Before, EST/TM2/SDBG/XTPR/DCA are allowed to be exposed to TD
- After, they are not.

If we cares CORE_CAPABILITIES in patch 2, why EST/TM2/SDBG/XTPR/DCA 
don't matter?

(I don't check the following leafs..)
> +	tdx_cpu_cfg_cap_init(CPUID_1_EDX,
> +		TDX_CFG_F(MCE),
> +		TDX_CFG_F(MTRR),
> +		TDX_CFG_F(MCA),
> +		TDX_CFG_F(SELFSNOOP),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_7_0_EBX,
> +		TDX_CFG_F(BMI1),
> +		/* HLE */
> +		TDX_CFG_F(BMI2),
> +		TDX_CFG_F(ERMS),
> +		/* RTM */
> +		TDX_CFG_F(AVX512F),
> +		TDX_CFG_F(AVX512DQ),
> +		TDX_CFG_F(ADX),
> +		TDX_CFG_F(AVX512IFMA),
> +		TDX_CFG_F(AVX512PF),
> +		TDX_CFG_F(AVX512ER),
> +		TDX_CFG_F(AVX512CD),
> +		TDX_CFG_F(AVX512BW),
> +		TDX_CFG_F(AVX512VL),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_7_ECX,
> +		TDX_CFG_F(UMIP),
> +		/* WAITPKG */
> +		TDX_CFG_F(AVX512_VBMI2),
> +		TDX_CFG_F(GFNI),
> +		TDX_CFG_F(VAES),
> +		TDX_CFG_F(VPCLMULQDQ),
> +		TDX_CFG_F(AVX512_VNNI),
> +		TDX_CFG_F(AVX512_BITALG),
> +		TDX_CFG_F(AVX512_VPOPCNTDQ),
> +		TDX_CFG_F(LA57),
> +		TDX_CFG_F(RDPID),
> +		TDX_CFG_F(CLDEMOTE),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_7_EDX,
> +		TDX_CFG_F(AVX512_4VNNIW),
> +		TDX_CFG_F(AVX512_4FMAPS),
> +		TDX_CFG_F(FSRM),
> +		TDX_CFG_F(AVX512_VP2INTERSECT),
> +		TDX_CFG_F(SERIALIZE),
> +		TDX_CFG_F(TSXLDTRK),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_7_1_EAX,
> +		TDX_CFG_F(SHA512),
> +		TDX_CFG_F(SM3),
> +		TDX_CFG_F(SM4),
> +		TDX_CFG_F(AVX_VNNI),
> +		TDX_CFG_F(AVX512_BF16),
> +		TDX_CFG_F(CMPCCXADD),
> +		TDX_CFG_F(FZRM),
> +		TDX_CFG_F(FSRS),
> +		TDX_CFG_F(FSRC),
> +		TDX_CFG_F(LKGS),
> +		TDX_CFG_F(WRMSRNS),
> +		TDX_CFG_F(AMX_FP16),
> +		TDX_CFG_F(AVX_IFMA),
> +		TDX_CFG_F(LAM),
> +		TDX_CFG_F(MOVRS),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_7_1_EDX,
> +		TDX_CFG_F(AVX_VNNI_INT8),
> +		TDX_CFG_F(AVX_NE_CONVERT),
> +		TDX_CFG_F(AMX_COMPLEX),
> +		TDX_CFG_F(AVX_VNNI_INT16),
> +		TDX_CFG_F(PREFETCHITI),
> +		TDX_CFG_F(AVX10),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_7_2_EDX,
> +		TDX_CFG_F(DDPD_U),
> +		TDX_CFG_F(MCDT_NO),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_1E_1_EAX,
> +		TDX_CFG_F(AMX_FP8),
> +		TDX_CFG_F(AMX_TF32),
> +		TDX_CFG_F(AMX_AVX512),
> +		TDX_CFG_F(AMX_MOVRS),
> +	);
> +
> +	tdx_cpu_cfg_cap_init(CPUID_8000_0008_EBX,
> +		TDX_CFG_F(WBNOINVD),
> +	);
> +}
> +
> +#undef TDX_CFG_F
> +#undef TDX_CFG_EXTRA_F
>   
>   bool enable_tdx __ro_after_init;
>   module_param_named(tdx, enable_tdx, bool, 0444);
> @@ -3481,6 +3624,8 @@ int __init tdx_hardware_setup(void)
>   		return r;
>   	}
>   
> +	tdx_initialize_cpu_cfg_caps();
> +
>   	KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_tdx);
>   
>   	vt_x86_ops.vm_size = max_t(unsigned int, vt_x86_ops.vm_size, sizeof(struct kvm_tdx));


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-01  9:38     ` Xiaoyao Li
@ 2026-09-01 17:41       ` Edgecombe, Rick P
  2026-09-02 10:29         ` Xiaoyao Li
  0 siblings, 1 reply; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-09-01 17:41 UTC (permalink / raw)
  To: Li, Xiaoyao, kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: nik.borisov@suse.com, pbonzini@redhat.com, kas@kernel.org,
	seanjc@google.com, Gao, Chao, dave.hansen@linux.intel.com,
	andrew.cooper3@citrix.com

On Tue, 2026-09-01 at 17:38 +0800, Xiaoyao Li wrote:
> > > Ideally the TDX save/restore would share code with normal VMs. On the
> > > other hand if we don't share enter/exit paths sufficiently, we may need to
> > > duplicate some save/restore in tdx code.
> 
> (Copy the FRED example here for reference)
> 
>  >>>
>  >>> FRED is a useful concrete example.  Under VMX, the FRED host state in
>  >>> IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP1-3 and
>  >>> IA32_FRED_SSP1-3 is covered by the VMCS host-state area, so the TDX 
> module
>  >>> is expected to restore these MSRs on TDH.VP.ENTER return. 
> IA32_FRED_RSP0
>  >>> and IA32_PL0_SSP (a.k.a. IA32_FRED_SSP0) are handled by software, 
> so the
>  >>> TDX module is expected to clobber them on TDH.VP.ENTER return.
> 
> What I get, is not matching VMX behavior but matching the behavior KVM 
> will perform for VMX. They are based on the assumption that KVM will 
> always enable the save/restore VMCS fields for a new feature. But I 
> don't think we can guarantee it.
> 
> To me, "have TDX simply match VMX behavior" means:
> 
> 1. if the VMX unconditionally save/restore a state, then TDX will do so.
> 
> 2. if there are vm-entry/vm-exit load/save VMCS fields for a state, then 
> provide the equivalent per-TD configurable interfaces which matches the 
> VMCS fields.

What do you mean by this? Expose a TDX module interface to configure the clobber
behavior for each feature with load/save configuration? That was similar to what
we originally discussed, before pivoting to this solution.

I was thinking if you configured a feature (for example shadow stack), it would
automatically set the VMCS save/restore settings associated with that feature.
(VM_EXIT_LOAD_CET_STATE/VM_ENTRY_LOAD_CET_STATE)

This won't necessarily match KVM's behavior, because it could decide to not use
the features. But we can probably get close with a simple rule that can make
sense for all the VMMs.

If later we want a host clobber interface on top of the bit filtering, in order
to minimize TDX special handling, we can probably add it later for features we
care about. I'd think we don't need it right now.




^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-01 14:35   ` Xiaoyao Li
@ 2026-09-02  0:33     ` Binbin Wu
  2026-09-02 15:09       ` Xiaoyao Li
  0 siblings, 1 reply; 44+ messages in thread
From: Binbin Wu @ 2026-09-02  0:33 UTC (permalink / raw)
  To: Xiaoyao Li, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao



On 9/1/2026 10:35 PM, Xiaoyao Li wrote:
> On 8/27/2026 11:18 AM, Binbin Wu wrote:
>> Add tdx_cpu_cfg_caps[] to track the subset of TDX directly configurable
>> CPUID feature bits that KVM supports, and build the masks during TDX
>> hardware setup via tdx_initialize_cpu_cfg_caps().
>>
>> The TDX module reports the CPUID bits that the VMM can directly configure
>> for a TD, but KVM cannot blindly expose all reported bits to userspace.
>> Certain features imply additional architectural state, e.g. one or more
>> MSRs, that KVM must explicitly manage across host/guest transitions to
>> prevent host state corruption.
>>
>> Today KVM relies on a hardcoded denylist, i.e. it clears a few known
>> problematic bits, e.g. TSX and WAITPKG, and passes everything else through.
>> A denylist is fundamentally fragile while an allowlist inverts the default,
>> i.e. unknown configurable bits are hidden and not allowed to be enabled
>> until KVM explicitly opts in.
>>
>> Except for a few fixed-1 bits required for basic TDX support, host state
>> clobbering features are either directly configurable or gated by TD
>> ATTRIBUTES/XFAM.  
> 
>> Tracking only the directly configurable feature bits is
>> therefore sufficient to serve the purpose while keeping the code footprint
>> small.
> 
> I'm not clear how it is therefore sufficient. We at least need to explain that ATTRIBUTS/XFAM are validated separately by KVM already?

I was trying to say this by "gated by TD ATTRIBUTES/XFAM", I will describe it
more clearly.

>> Organize tdx_cpu_cfg_caps[] following kvm_cpu_caps[] so that the masks can
>> be built with the similar feature-name based initializers.  CPUID registers
>> that hold directly configurable non-feature (multi-bit) fields are handled
>> separately.
>>
>> The allowlist is consumed by later patches to filter KVM_TDX_CAPABILITIES
>> and to reject unsupported CPUID input to KVM_TDX_INIT_VM, so that newly
>> introduced TDX directly configurable CPUID feature bits stay hidden from
>> userspace until KVM explicitly opts in.
>>
>> Add comments as placeholders for HLE, RTM and WAITPKG, which KVM doesn't
>> support for TDX yet.
>>
>> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
>> ---
>> v3:
>> - Drop the new data structure in v2 and only track feature bits by
>>    following the organization of kvm_cpu_caps[], handle non-feature
>>    bits separately. (Sean)
>> - Use two versions of macros (TDX_CFG_F() VS. TDX_CFG_EXTRA_F()) to
>>    distinguish whether a supported TDX configurable CPUID bit should be
>>    checked against KVM's common cpu capabilities.
>> - Add AMX_COMPLEX since it has been defined in the CPUID virtualization doc.
>> ---
>>   arch/x86/kvm/vmx/tdx.c | 145 +++++++++++++++++++++++++++++++++++++++++
>>   1 file changed, 145 insertions(+)
>>
>> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
>> index b272c20586a7..d4a3a42cfd9d 100644
>> --- a/arch/x86/kvm/vmx/tdx.c
>> +++ b/arch/x86/kvm/vmx/tdx.c
>> @@ -52,6 +52,149 @@
>>       __TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
>>                a1, a2, a3)
>>   +static u32 tdx_cpu_cfg_caps[NR_KVM_CPU_CAPS] __ro_after_init;
>> +static_assert(ARRAY_SIZE(tdx_cpu_cfg_caps) == ARRAY_SIZE(kvm_cpu_caps));
>> +
>> +#define TDX_VALIDATE_CPU_CAP_USAGE(name)            \
>> +    BUILD_BUG_ON(__feature_leaf(X86_FEATURE_##name) !=    \
>> +             tdx_cpu_cap_init_in_progress)
>> +
>> +/* For feature bit that KVM advertised through kvm_cpu_caps[]. */
> 
> I would say it
> 
> For feature bit that needs to be cap'ed by kvm_cpu_caps[]
> 
>> +#define TDX_CFG_F(name)                    \
>> +({                            \
>> +    TDX_VALIDATE_CPU_CAP_USAGE(name);        \
>> +    tdx_cfg_caps |= feature_bit(name);        \
>> +})
>> +
>> +/*
>> + * For feature bit KVM allows for TDX guests even though it is not advertised
>> + * through kvm_cpu_caps[], e.g. MWAIT.
>> + */
>> +#define TDX_CFG_EXTRA_F(name)                \
> 
> EXTRA doesn't sound like a fit name, though

I also struggled with naming this macro and couldn't come up with a better one.
Any suggestion?

> 
>> +({                            \
>> +    TDX_VALIDATE_CPU_CAP_USAGE(name);        \
>> +    tdx_cfg_extra_caps |= feature_bit(name);    \
>> +})
>> +
>> +#define tdx_cpu_cfg_cap_init(leaf, feature_initializers...)        \
>> +do {                                    \
>> +    const u32 __maybe_unused tdx_cpu_cap_init_in_progress = leaf;    \
>> +    u32 tdx_cfg_extra_caps = 0;                    \
>> +    u32 tdx_cfg_caps = 0;                        \
>> +                                    \
>> +    feature_initializers                        \
>> +    tdx_cpu_cfg_caps[leaf] = (tdx_cfg_caps & kvm_cpu_caps[leaf]) |    \
>> +                 tdx_cfg_extra_caps;            \
>> +} while (0)
>> +
>> +/*
>> + * Track only CPUID feature bits that are directly configurable by userspace.
> 
> the "by userspace" is misleading. It's just the directly configurable CPUID bits reported by TDX module.
> 
>> + * Features controlled by XFAM or ATTRIBUTES are excluded; userspace cannot
>> + * enable them until KVM adds support for the corresponding control.
>> + */
> 
> I don't like the comments. How about somthing
> 
> /*
>  * Intialize tdx_cpu_cfg_caps[], which is list of CPUID features that
>  * KVM supports for TDX. It only covers the directly configurable CPIUD
>  * bits reported by TDX module. Features controlled by XFAM and
>  * ATTRIBUTES are maintained separately.
>  */
> 
Thanks, it reads better.

>> +static void __init tdx_initialize_cpu_cfg_caps(void)
>> +{
>> +    tdx_cpu_cfg_cap_init(CPUID_1_ECX,
>> +        TDX_CFG_EXTRA_F(MWAIT),
>> +        TDX_CFG_F(TSC_DEADLINE_TIMER),
>> +        TDX_CFG_F(AVX),
>> +        TDX_CFG_F(F16C),
>> +    );
> 
> TDX 1.5.24 on SPR report configurable bits of CPUID_1_ECX as
> 0x31044988, which have
> 
> - bit 3        MWAIT
> - bit 7        EST
> - bit 8        TM2
> - bit 11    SDBG
> - bit 14    XTPR
> - bit 18    DCA
> - bit 24    TSC_DEADLINE_TIMER
> - bit 28    AVX
> - bit 29    F16C
> 
> but EST/TM2/SDBG/XTPR/DCA are not list here. I guess the reason is kvm_cpu_cap[] doesn't support it. If so, it seems to guard twice:
> 1. mentally/manually check if it a feature is supported in kvm_cpu_caps[]
> 
> 2. kvm_cpu_caps guarding in tdx_cpu_cfg_cap_init().
> 
> I think 1) is not necessary, we can rely on 2)

In general, if a feature is not supported by the common KVM CPU caps, I prefer not
to add it to the list to save a few lines of code, which probably is dead code,
unless people find it too confusing.
I can add a comment to clarify this.

> 
> BTW, this seems also breaks the current userspace after this series.
> - Before, EST/TM2/SDBG/XTPR/DCA are allowed to be exposed to TD
> - After, they are not.

This does change the values returned by KVM_TDX_CAPABILITIES. However, my
understanding is that userspace is generally expected to only configure
features supported by both KVM and TDX, i.e. except for the features initialized
via TDX_CFG_EXTRA_F(), userspace is not expected to configure features not advertised
by kvm_cpu_caps[].
I can call this out in the changelog, and maybe also the doc for KVM_TDX_CAPABILITIES.

> 
> If we cares CORE_CAPABILITIES in patch 2, why EST/TM2/SDBG/XTPR/DCA don't matter?

Because CORE_CAPABILITIES was previously defined as fixed-1 in some old spec and
the QEMU marks it as fixed1. EST/TM2/SDBG/XTPR/DCA are not the case.



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-01 17:41       ` Edgecombe, Rick P
@ 2026-09-02 10:29         ` Xiaoyao Li
  2026-09-02 13:13           ` Edgecombe, Rick P
  0 siblings, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-02 10:29 UTC (permalink / raw)
  To: Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, binbin.wu@linux.intel.com
  Cc: nik.borisov@suse.com, pbonzini@redhat.com, kas@kernel.org,
	seanjc@google.com, Gao, Chao, dave.hansen@linux.intel.com,
	andrew.cooper3@citrix.com

On 9/2/2026 1:41 AM, Edgecombe, Rick P wrote:
> On Tue, 2026-09-01 at 17:38 +0800, Xiaoyao Li wrote:
>>>> Ideally the TDX save/restore would share code with normal VMs. On the
>>>> other hand if we don't share enter/exit paths sufficiently, we may need to
>>>> duplicate some save/restore in tdx code.
>>
>> (Copy the FRED example here for reference)
>>
>>   >>>
>>   >>> FRED is a useful concrete example.  Under VMX, the FRED host state in
>>   >>> IA32_FRED_CONFIG, IA32_FRED_STKLVLS, IA32_FRED_RSP1-3 and
>>   >>> IA32_FRED_SSP1-3 is covered by the VMCS host-state area, so the TDX
>> module
>>   >>> is expected to restore these MSRs on TDH.VP.ENTER return.
>> IA32_FRED_RSP0
>>   >>> and IA32_PL0_SSP (a.k.a. IA32_FRED_SSP0) are handled by software,
>> so the
>>   >>> TDX module is expected to clobber them on TDH.VP.ENTER return.
>>
>> What I get, is not matching VMX behavior but matching the behavior KVM
>> will perform for VMX. They are based on the assumption that KVM will
>> always enable the save/restore VMCS fields for a new feature. But I
>> don't think we can guarantee it.
>>
>> To me, "have TDX simply match VMX behavior" means:
>>
>> 1. if the VMX unconditionally save/restore a state, then TDX will do so.
>>
>> 2. if there are vm-entry/vm-exit load/save VMCS fields for a state, then
>> provide the equivalent per-TD configurable interfaces which matches the
>> VMCS fields.
> 
> What do you mean by this? Expose a TDX module interface to configure the clobber
> behavior for each feature with load/save configuration? That was similar to what
> we originally discussed, before pivoting to this solution.

yeah. This is what I meant. I was trying to show my literal 
understanding on "The proposal is to have TDX simply match VMX 
behavior". i.e., I don't think "have TDX simply match VMX behavior" is a 
good name/summary for what Binbin has proposed.

> I was thinking if you configured a feature (for example shadow stack), it would
> automatically set the VMCS save/restore settings associated with that feature.
> (VM_EXIT_LOAD_CET_STATE/VM_ENTRY_LOAD_CET_STATE)
> 
> This won't necessarily match KVM's behavior, because it could decide to not use
> the features. But we can probably get close with a simple rule that can make
> sense for all the VMMs.

So the proposal is making TDX behave as if the relevant VMCS save/load 
controls (if any) are set around TDH.VP.ENTER.

In fact, what matters for host vmm is just the VM_EXIT_LOAD_XXX control. 
So the proposal becomes "If there is VM_EXIT_LOAD_XXX control for a 
state, TDX needs to restore the host state after TDH.VP.ENTER. If no 
such contorl, TDX sets the state to INIT state after TDH.VP.ENTER".

It's a fancy idea. And it provides a clear rule of how TDX handles 
states of a feature so that host VMM developers don't need to read the 
TDX module API to figure out what's the value of a state after TDH.VP.ENTER.

It's helpful for host VMM developers, though I'm not sure on TDX module 
developers.

> If later we want a host clobber interface on top of the bit filtering, in order
> to minimize TDX special handling, we can probably add it later for features we
> care about. I'd think we don't need it right now.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-02 10:29         ` Xiaoyao Li
@ 2026-09-02 13:13           ` Edgecombe, Rick P
  2026-09-02 13:39             ` Xiaoyao Li
  2026-09-02 16:26             ` Binbin Wu
  0 siblings, 2 replies; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-09-02 13:13 UTC (permalink / raw)
  To: Li, Xiaoyao, kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: andrew.cooper3@citrix.com, pbonzini@redhat.com,
	nik.borisov@suse.com, kas@kernel.org, seanjc@google.com,
	Gao, Chao, dave.hansen@linux.intel.com

On Wed, 2026-09-02 at 18:29 +0800, Xiaoyao Li wrote:
> So the proposal is making TDX behave as if the relevant VMCS save/load 
> controls (if any) are set around TDH.VP.ENTER.
> 
> In fact, what matters for host vmm is just the VM_EXIT_LOAD_XXX control. 
> So the proposal becomes "If there is VM_EXIT_LOAD_XXX control for a 
> state, TDX needs to restore the host state after TDH.VP.ENTER. If no 
> such contorl, TDX sets the state to INIT state after TDH.VP.ENTER".
> 
> It's a fancy idea. And it provides a clear rule of how TDX handles 
> states of a feature so that host VMM developers don't need to read the 
> TDX module API to figure out what's the value of a state after TDH.VP.ENTER.
> 
> It's helpful for host VMM developers, though I'm not sure on TDX module 
> developers.

I don't think they have agreed to it yet (Binbin?), but I think it mostly works
this way already. Why do you think it is a burden on TDX module developers?

Also, I think this can be the guideline. We could have exceptions.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-02 13:13           ` Edgecombe, Rick P
@ 2026-09-02 13:39             ` Xiaoyao Li
  2026-09-02 13:53               ` Edgecombe, Rick P
  2026-09-02 16:26             ` Binbin Wu
  1 sibling, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-02 13:39 UTC (permalink / raw)
  To: Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, binbin.wu@linux.intel.com
  Cc: andrew.cooper3@citrix.com, pbonzini@redhat.com,
	nik.borisov@suse.com, kas@kernel.org, seanjc@google.com,
	Gao, Chao, dave.hansen@linux.intel.com

On 9/2/2026 9:13 PM, Edgecombe, Rick P wrote:
> On Wed, 2026-09-02 at 18:29 +0800, Xiaoyao Li wrote:
>> So the proposal is making TDX behave as if the relevant VMCS save/load 
>> controls (if any) are set around TDH.VP.ENTER.
>>
>> In fact, what matters for host vmm is just the VM_EXIT_LOAD_XXX control. 
>> So the proposal becomes "If there is VM_EXIT_LOAD_XXX control for a 
>> state, TDX needs to restore the host state after TDH.VP.ENTER. If no 
>> such contorl, TDX sets the state to INIT state after TDH.VP.ENTER".
>>
>> It's a fancy idea. And it provides a clear rule of how TDX handles 
>> states of a feature so that host VMM developers don't need to read the 
>> TDX module API to figure out what's the value of a state after TDH.VP.ENTER.
>>
>> It's helpful for host VMM developers, though I'm not sure on TDX module 
>> developers.
> 
> I don't think they have agreed to it yet (Binbin?), but I think it mostly works
> this way already. Why do you think it is a burden on TDX module developers?

Because it can bring confusion to TDX module developers. VM_EXIT_LOAD_XXX control
is used by SEAM VMCS to load states for TDX module execution context. And I think
for most features SEAM VMCS doesn't set it (I don't check it though).

SEAMCALL is kind of a VM exit, and SEAMRET is kind of a VM entry. To automatically
save and restore the host state, what TDX needs are VM_EXIT_SAVE_XXX, VM_ENTRY_LOAD_XXX,
and vmcs guest state for XXX.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-02 13:39             ` Xiaoyao Li
@ 2026-09-02 13:53               ` Edgecombe, Rick P
  2026-09-02 14:21                 ` Xiaoyao Li
  0 siblings, 1 reply; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-09-02 13:53 UTC (permalink / raw)
  To: Li, Xiaoyao, kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: Gao, Chao, pbonzini@redhat.com, nik.borisov@suse.com,
	kas@kernel.org, seanjc@google.com, andrew.cooper3@citrix.com,
	dave.hansen@linux.intel.com

On Wed, 2026-09-02 at 21:39 +0800, Xiaoyao Li wrote:
> > I don't think they have agreed to it yet (Binbin?), but I think it mostly
> > works this way already. Why do you think it is a burden on TDX module
> > developers?
> 
> Because it can bring confusion to TDX module developers. VM_EXIT_LOAD_XXX
> control is used by SEAM VMCS to load states for TDX module execution context.
> And I think for most features SEAM VMCS doesn't set it (I don't check it
> though).
> 
> SEAMCALL is kind of a VM exit, and SEAMRET is kind of a VM entry. To
> automatically save and restore the host state, what TDX needs are
> VM_EXIT_SAVE_XXX, VM_ENTRY_LOAD_XXX, and vmcs guest state for XXX.

I'd think we could avoid adding options for configuration that won't be used. If
we did have a clobber control interface, matching VMX bits is an interesting
idea.

I'm a bit torn between wanting to fix the area once and for all with a full
solution, and wanting to get this increasingly blocking CPUID bit fix in. I'm
leaning towards just do the bit filtering and give the save/restore guidelines.

Then we can do a save/restore control later if we find the guidelines are not
sufficient.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-02 13:53               ` Edgecombe, Rick P
@ 2026-09-02 14:21                 ` Xiaoyao Li
  0 siblings, 0 replies; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-02 14:21 UTC (permalink / raw)
  To: Edgecombe, Rick P, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org, binbin.wu@linux.intel.com
  Cc: Gao, Chao, pbonzini@redhat.com, nik.borisov@suse.com,
	kas@kernel.org, seanjc@google.com, andrew.cooper3@citrix.com,
	dave.hansen@linux.intel.com

On 9/2/2026 9:53 PM, Edgecombe, Rick P wrote:
> On Wed, 2026-09-02 at 21:39 +0800, Xiaoyao Li wrote:
>>> I don't think they have agreed to it yet (Binbin?), but I think it mostly
>>> works this way already. Why do you think it is a burden on TDX module
>>> developers?
>>
>> Because it can bring confusion to TDX module developers. VM_EXIT_LOAD_XXX
>> control is used by SEAM VMCS to load states for TDX module execution context.
>> And I think for most features SEAM VMCS doesn't set it (I don't check it
>> though).
>>
>> SEAMCALL is kind of a VM exit, and SEAMRET is kind of a VM entry. To
>> automatically save and restore the host state, what TDX needs are
>> VM_EXIT_SAVE_XXX, VM_ENTRY_LOAD_XXX, and vmcs guest state for XXX.
> 
> I'd think we could avoid adding options for configuration that won't be used. If
> we did have a clobber control interface, matching VMX bits is an interesting
> idea.
> 
> I'm a bit torn between wanting to fix the area once and for all with a full
> solution, and wanting to get this increasingly blocking CPUID bit fix in. 

> I'm
> leaning towards just do the bit filtering and give the save/restore guidelines.

I agree.

I always believe the bit filtering introduced by this series makes KVM
safer and it's anyway useful, while how TDX/TDX module save/restore host
states can be another separate topic.

> Then we can do a save/restore control later if we find the guidelines are not
> sufficient.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-02  0:33     ` Binbin Wu
@ 2026-09-02 15:09       ` Xiaoyao Li
  2026-09-02 16:19         ` Binbin Wu
  0 siblings, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-02 15:09 UTC (permalink / raw)
  To: Binbin Wu, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 9/2/2026 8:33 AM, Binbin Wu wrote:
>>> +static void __init tdx_initialize_cpu_cfg_caps(void)
>>> +{
>>> +    tdx_cpu_cfg_cap_init(CPUID_1_ECX,
>>> +        TDX_CFG_EXTRA_F(MWAIT),
>>> +        TDX_CFG_F(TSC_DEADLINE_TIMER),
>>> +        TDX_CFG_F(AVX),
>>> +        TDX_CFG_F(F16C),
>>> +    );
>> TDX 1.5.24 on SPR report configurable bits of CPUID_1_ECX as
>> 0x31044988, which have
>>
>> - bit 3        MWAIT
>> - bit 7        EST
>> - bit 8        TM2
>> - bit 11    SDBG
>> - bit 14    XTPR
>> - bit 18    DCA
>> - bit 24    TSC_DEADLINE_TIMER
>> - bit 28    AVX
>> - bit 29    F16C
>>
>> but EST/TM2/SDBG/XTPR/DCA are not list here. I guess the reason is kvm_cpu_cap[] doesn't support it. If so, it seems to guard twice:
>> 1. mentally/manually check if it a feature is supported in kvm_cpu_caps[]
>>
>> 2. kvm_cpu_caps guarding in tdx_cpu_cfg_cap_init().
>>
>> I think 1) is not necessary, we can rely on 2)
> In general, if a feature is not supported by the common KVM CPU caps, 

For kvm-intel.ko, kvm_cpu_caps[] just means the supported CPUID features
for VMX VMs. Treat it as the common KVM CPU caps is a bit arguable.

> I prefer not
> to add it to the list to save a few lines of code, which probably is dead code,

I don't think it's dead code. It shows that these features are
virtualizable to TDs from the POV. of TDX.

In the end, they might be disallowed to be configured to TDs because KVM
doesn't allow them for VMX VMs. This is also the point I want to discuss.
Do we really want to make such restriction that KVM cannot enable/allow a
feature for TDs unless KVM first enables/allows it for VMX VMs? What's
reason behind it?

> unless people find it too confusing.
> I can add a comment to clarify this.
> 
>> BTW, this seems also breaks the current userspace after this series.
>> - Before, EST/TM2/SDBG/XTPR/DCA are allowed to be exposed to TD
>> - After, they are not.
> This does change the values returned by KVM_TDX_CAPABILITIES. However, my
> understanding is that userspace is generally expected to only configure
> features supported by both KVM and TDX, i.e. except for the features initialized
> via TDX_CFG_EXTRA_F(), userspace is not expected to configure features not advertised
> by kvm_cpu_caps[].
> I can call this out in the changelog, and maybe also the doc for KVM_TDX_CAPABILITIES.

yeah. This changes KVM's behavior and we definitely need to call it out,
and provide justification.

>> If we cares CORE_CAPABILITIES in patch 2, why EST/TM2/SDBG/XTPR/DCA don't matter?
> Because CORE_CAPABILITIES was previously defined as fixed-1 in some old spec and
> the QEMU marks it as fixed1. EST/TM2/SDBG/XTPR/DCA are not the case.

I see. You added patch 2 because without it QEMU breaks. While for
EST/TM2/SDBG/XTPR/DCA, QEMU doesn't break after they are turned to
non-configurable. QEMU cannot represent all the userspace VMM. It still has
the potential to breaks other userspace VMMs.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-01  9:42         ` Xiaoyao Li
  2026-09-01 10:21           ` Xiaoyao Li
@ 2026-09-02 16:09           ` Edgecombe, Rick P
  2026-09-02 16:21             ` Binbin Wu
  1 sibling, 1 reply; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-09-02 16:09 UTC (permalink / raw)
  To: Li, Xiaoyao, kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: nik.borisov@suse.com, pbonzini@redhat.com, kas@kernel.org,
	seanjc@google.com, Gao, Chao, dave.hansen@linux.intel.com,
	andrew.cooper3@citrix.com

On Tue, 2026-09-01 at 17:42 +0800, Xiaoyao Li wrote:
> On 8/31/2026 1:01 PM, Binbin Wu wrote:
> > > > So if the approach in this series is taken, I think we still need such
> > > > an opt- in interface to tell the TDX module that the VMM is now
> > > > filtering the CPUID bits so that the TDX module knows that it's safe to
> > > > report new host state clobbering features.
> > > Yep. Can we think about what it would look like? Easiest would be a bit
> > > passed in TDH_SYS_CONFIG. But then arch/x86 is saying how KVM will behave.
> > > Ok to me, for the simplicity. Could come with a nice comment.
> 
> Can you just treat current KVM behavior of allowing userspace to enable 
> any configurable bits as the bug of KVM and backport this series as 
> Binbin suggested below? Instead of introducing more opt-in knobs.

Ok, so if we are agreed on the other branch of the thread, the only big question
is: Do we want an opt-in for future clobbering CPUID bits.

I think either is ok. I don't love the precedent that we asserted that no new
clobber bits could be added without opt-in, and then we would backport changes
to allow this anyway. But on pure code, the backport would be simpler in the
long term. If you guys are strongly in favor, I can agree.

Are we sure no other VMM needs an opt-in, before finalizing it though? Binbin,
can flag this to the TDX module team?

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-02 15:09       ` Xiaoyao Li
@ 2026-09-02 16:19         ` Binbin Wu
  2026-09-02 16:22           ` Edgecombe, Rick P
  2026-09-03  7:28           ` Xiaoyao Li
  0 siblings, 2 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-02 16:19 UTC (permalink / raw)
  To: Xiaoyao Li, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 9/2/2026 11:09 PM, Xiaoyao Li wrote:
> On 9/2/2026 8:33 AM, Binbin Wu wrote:
>>>> +static void __init tdx_initialize_cpu_cfg_caps(void)
>>>> +{
>>>> +    tdx_cpu_cfg_cap_init(CPUID_1_ECX,
>>>> +        TDX_CFG_EXTRA_F(MWAIT),
>>>> +        TDX_CFG_F(TSC_DEADLINE_TIMER),
>>>> +        TDX_CFG_F(AVX),
>>>> +        TDX_CFG_F(F16C),
>>>> +    );
>>> TDX 1.5.24 on SPR report configurable bits of CPUID_1_ECX as
>>> 0x31044988, which have
>>>
>>> - bit 3        MWAIT
>>> - bit 7        EST
>>> - bit 8        TM2
>>> - bit 11    SDBG
>>> - bit 14    XTPR
>>> - bit 18    DCA
>>> - bit 24    TSC_DEADLINE_TIMER
>>> - bit 28    AVX
>>> - bit 29    F16C
>>>
>>> but EST/TM2/SDBG/XTPR/DCA are not list here. I guess the reason is kvm_cpu_cap[] doesn't support it. If so, it seems to guard twice:
>>> 1. mentally/manually check if it a feature is supported in kvm_cpu_caps[]
>>>
>>> 2. kvm_cpu_caps guarding in tdx_cpu_cfg_cap_init().
>>>
>>> I think 1) is not necessary, we can rely on 2)
>> In general, if a feature is not supported by the common KVM CPU caps, 
> 
> For kvm-intel.ko, kvm_cpu_caps[] just means the supported CPUID features
> for VMX VMs. Treat it as the common KVM CPU caps is a bit arguable.
> 
>> I prefer not
>> to add it to the list to save a few lines of code, which probably is dead code,
> 
> I don't think it's dead code. It shows that these features are
> virtualizable to TDs from the POV. of TDX.

It depends on whether KVM allows userspace to set features for TDs that are not support
for non-TDX VMs (,except for a few exceptions).

In this version, TDX_CFG_F() already check against kvm_cpu_caps[], if these features
are not in kvm_cpu_caps[], it will not be exposed to userspace anyway.

> 
> In the end, they might be disallowed to be configured to TDs because KVM
> doesn't allow them for VMX VMs. This is also the point I want to discuss.
> Do we really want to make such restriction that KVM cannot enable/allow a
> feature for TDs unless KVM first enables/allows it for VMX VMs? What's
> reason behind it?

Sean mentioned it that "generally speaking, KVM shouldn't allow features
that KVM doesn't support for non-TDX VMs" in
https://lore.kernel.org/kvm/aj1fi_0SBxMK5WOB@google.com/

> 
>> unless people find it too confusing.
>> I can add a comment to clarify this.
>>
>>> BTW, this seems also breaks the current userspace after this series.
>>> - Before, EST/TM2/SDBG/XTPR/DCA are allowed to be exposed to TD
>>> - After, they are not.
>> This does change the values returned by KVM_TDX_CAPABILITIES. However, my
>> understanding is that userspace is generally expected to only configure
>> features supported by both KVM and TDX, i.e. except for the features initialized
>> via TDX_CFG_EXTRA_F(), userspace is not expected to configure features not advertised
>> by kvm_cpu_caps[].
>> I can call this out in the changelog, and maybe also the doc for KVM_TDX_CAPABILITIES.
> 
> yeah. This changes KVM's behavior and we definitely need to call it out,
> and provide justification.
> 
>>> If we cares CORE_CAPABILITIES in patch 2, why EST/TM2/SDBG/XTPR/DCA don't matter?
>> Because CORE_CAPABILITIES was previously defined as fixed-1 in some old spec and
>> the QEMU marks it as fixed1. EST/TM2/SDBG/XTPR/DCA are not the case.
> 
> I see. You added patch 2 because without it QEMU breaks. While for
> EST/TM2/SDBG/XTPR/DCA, QEMU doesn't break after they are turned to
> non-configurable. QEMU cannot represent all the userspace VMM. It still has
> the potential to breaks other userspace VMMs.

I think the risk is pretty low.
I am not sure if Sean could provide some insight about this in google's userspace
VMM.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-02 16:09           ` Edgecombe, Rick P
@ 2026-09-02 16:21             ` Binbin Wu
  0 siblings, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-02 16:21 UTC (permalink / raw)
  To: Edgecombe, Rick P, Li, Xiaoyao, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: nik.borisov@suse.com, pbonzini@redhat.com, kas@kernel.org,
	seanjc@google.com, Gao, Chao, dave.hansen@linux.intel.com,
	andrew.cooper3@citrix.com

On 9/3/2026 12:09 AM, Edgecombe, Rick P wrote:
> On Tue, 2026-09-01 at 17:42 +0800, Xiaoyao Li wrote:
>> On 8/31/2026 1:01 PM, Binbin Wu wrote:
>>>>> So if the approach in this series is taken, I think we still need such
>>>>> an opt- in interface to tell the TDX module that the VMM is now
>>>>> filtering the CPUID bits so that the TDX module knows that it's safe to
>>>>> report new host state clobbering features.
>>>> Yep. Can we think about what it would look like? Easiest would be a bit
>>>> passed in TDH_SYS_CONFIG. But then arch/x86 is saying how KVM will behave.
>>>> Ok to me, for the simplicity. Could come with a nice comment.
>>
>> Can you just treat current KVM behavior of allowing userspace to enable 
>> any configurable bits as the bug of KVM and backport this series as 
>> Binbin suggested below? Instead of introducing more opt-in knobs.
> 
> Ok, so if we are agreed on the other branch of the thread, the only big question
> is: Do we want an opt-in for future clobbering CPUID bits.
> 
> I think either is ok. I don't love the precedent that we asserted that no new
> clobber bits could be added without opt-in, and then we would backport changes
> to allow this anyway. But on pure code, the backport would be simpler in the
> long term. If you guys are strongly in favor, I can agree.
> 
> Are we sure no other VMM needs an opt-in, before finalizing it though? Binbin,
> can flag this to the TDX module team?

AFAIK, no other VMM complained about the host clobbering issue.
I will check it with the TDX module team.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-02 16:19         ` Binbin Wu
@ 2026-09-02 16:22           ` Edgecombe, Rick P
  2026-09-02 16:25             ` Binbin Wu
  2026-09-03  7:28           ` Xiaoyao Li
  1 sibling, 1 reply; 44+ messages in thread
From: Edgecombe, Rick P @ 2026-09-02 16:22 UTC (permalink / raw)
  To: Li, Xiaoyao, kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	binbin.wu@linux.intel.com
  Cc: kas@kernel.org, pbonzini@redhat.com, nik.borisov@suse.com,
	seanjc@google.com, Gao, Chao, dave.hansen@linux.intel.com,
	andrew.cooper3@citrix.com

On Thu, 2026-09-03 at 00:19 +0800, Binbin Wu wrote:
> > I see. You added patch 2 because without it QEMU breaks. While for
> > EST/TM2/SDBG/XTPR/DCA, QEMU doesn't break after they are turned to
> > non-configurable. QEMU cannot represent all the userspace VMM. It still has
> > the potential to breaks other userspace VMMs.
> 
> I think the risk is pretty low.
> I am not sure if Sean could provide some insight about this in google's
> userspace VMM.

Can't we fix the issue if we are wrong?

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-02 16:22           ` Edgecombe, Rick P
@ 2026-09-02 16:25             ` Binbin Wu
  0 siblings, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-02 16:25 UTC (permalink / raw)
  To: Edgecombe, Rick P, Li, Xiaoyao, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: kas@kernel.org, pbonzini@redhat.com, nik.borisov@suse.com,
	seanjc@google.com, Gao, Chao, dave.hansen@linux.intel.com,
	andrew.cooper3@citrix.com

On 9/3/2026 12:22 AM, Edgecombe, Rick P wrote:
> On Thu, 2026-09-03 at 00:19 +0800, Binbin Wu wrote:
>>> I see. You added patch 2 because without it QEMU breaks. While for
>>> EST/TM2/SDBG/XTPR/DCA, QEMU doesn't break after they are turned to
>>> non-configurable. QEMU cannot represent all the userspace VMM. It still has
>>> the potential to breaks other userspace VMMs.
>>
>> I think the risk is pretty low.
>> I am not sure if Sean could provide some insight about this in google's
>> userspace VMM.
> 
> Can't we fix the issue if we are wrong?

I think it could be fixed to add the missing bits (if any) as bug fix.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits
  2026-09-02 13:13           ` Edgecombe, Rick P
  2026-09-02 13:39             ` Xiaoyao Li
@ 2026-09-02 16:26             ` Binbin Wu
  1 sibling, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-02 16:26 UTC (permalink / raw)
  To: Edgecombe, Rick P, Li, Xiaoyao, kvm@vger.kernel.org,
	linux-kernel@vger.kernel.org
  Cc: andrew.cooper3@citrix.com, pbonzini@redhat.com,
	nik.borisov@suse.com, kas@kernel.org, seanjc@google.com,
	Gao, Chao, dave.hansen@linux.intel.com

On 9/2/2026 9:13 PM, Edgecombe, Rick P wrote:
> On Wed, 2026-09-02 at 18:29 +0800, Xiaoyao Li wrote:
>> So the proposal is making TDX behave as if the relevant VMCS save/load 
>> controls (if any) are set around TDH.VP.ENTER.
>>
>> In fact, what matters for host vmm is just the VM_EXIT_LOAD_XXX control. 
>> So the proposal becomes "If there is VM_EXIT_LOAD_XXX control for a 
>> state, TDX needs to restore the host state after TDH.VP.ENTER. If no 
>> such contorl, TDX sets the state to INIT state after TDH.VP.ENTER".
>>
>> It's a fancy idea. And it provides a clear rule of how TDX handles 
>> states of a feature so that host VMM developers don't need to read the 
>> TDX module API to figure out what's the value of a state after TDH.VP.ENTER.
>>
>> It's helpful for host VMM developers, though I'm not sure on TDX module 
>> developers.
> 
> I don't think they have agreed to it yet (Binbin?), 

Not yet. We just brought the topic to the community for discussion first.

> but I think it mostly works
> this way already. Why do you think it is a burden on TDX module developers?
> 
> Also, I think this can be the guideline. We could have exceptions.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable
  2026-08-27  3:18 ` [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable Binbin Wu
  2026-09-01  6:45   ` Tony Lindgren
@ 2026-09-02 17:43   ` Kishen Maloor
       [not found]     ` <d47c8cc6-242b-4ebf-89f2-0909abdaadd5@linux.intel.com>
  1 sibling, 1 reply; 44+ messages in thread
From: Kishen Maloor @ 2026-09-02 17:43 UTC (permalink / raw)
  To: Binbin Wu, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao

On 8/26/26 8:18 PM, Binbin Wu wrote:
> Reporting CORE_CAPABILITIES as configurable keeps userspace able to enable
> the bit across the fixed-1 => configurable transition, and lets userspace
> infer that the bit is no longer fixed-1 so it can adjust its expectations.
> ...
> @@ -147,6 +147,12 @@ static void __init tdx_initialize_cpu_cfg_caps(void)
> +		/*
> +		 * KVM does not support MSR_IA32_CORE_CAPS, but older TDX specs
> +		 * define this bit as fixed-1.  Report it as configurable so
> +		 * userspace can know the feature is no longer a fixed-1 bit.
> +		 */
> +		TDX_CFG_EXTRA_F(CORE_CAPABILITIES),

Would a mask of the bits that are fixed-1 across the modules KVM supports today
be worth carrying, or adding to the allowed set?
I assume it would be hardcoded, just as the allowed list is.

If a module update later made one of them configurable, userspace would keep the
ability to set it -- something it has today with the denylist. And since such
bits are already enabled in every TD running now, continuing to accept them 
can't turn on anything that isn't already on.

A bit that becomes fixed-1 in the future and configurable after a subsequent
module update would still need a patch to the mask, just as this patch does.
Is CORE_CAPABILITIES the only fixed-1 case so far?


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable
       [not found]     ` <d47c8cc6-242b-4ebf-89f2-0909abdaadd5@linux.intel.com>
@ 2026-09-03  6:10       ` Kishen Maloor
  2026-09-03  8:12         ` Binbin Wu
  0 siblings, 1 reply; 44+ messages in thread
From: Kishen Maloor @ 2026-09-03  6:10 UTC (permalink / raw)
  To: Binbin Wu, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao

On 9/2/26 7:22 PM, Binbin Wu wrote:
> On 9/3/2026 1:43 AM, Kishen Maloor wrote:
>> On 8/26/26 8:18 PM, Binbin Wu wrote:
> ...
> 
> Actually this is the #VE reduction on fixed-1 bit, which changes a previous fixed-1
> bit to directly configurable.
> There are several cases of this category, i.e. MCA/MCE/MTRR/CORE_CAPABILITIES.
> However, CORE_CAPABILITIES is the only case that KVM doesn't support for non-TDX
> VMs
> I will add these info to the change log.


The cover letter highlights the deprecation case, but it sounds like
you hit this now due to #VE reduction. Is further #VE reduction expected?
If this is altogether rare, then yeah, added measures aren't necessary.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-02 16:19         ` Binbin Wu
  2026-09-02 16:22           ` Edgecombe, Rick P
@ 2026-09-03  7:28           ` Xiaoyao Li
  2026-09-03  8:57             ` Binbin Wu
  1 sibling, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-03  7:28 UTC (permalink / raw)
  To: Binbin Wu, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 9/3/2026 12:19 AM, Binbin Wu wrote:
> On 9/2/2026 11:09 PM, Xiaoyao Li wrote:
>> On 9/2/2026 8:33 AM, Binbin Wu wrote:
>>>>> +static void __init tdx_initialize_cpu_cfg_caps(void)
>>>>> +{
>>>>> +    tdx_cpu_cfg_cap_init(CPUID_1_ECX,
>>>>> +        TDX_CFG_EXTRA_F(MWAIT),
>>>>> +        TDX_CFG_F(TSC_DEADLINE_TIMER),
>>>>> +        TDX_CFG_F(AVX),
>>>>> +        TDX_CFG_F(F16C),
>>>>> +    );
>>>> TDX 1.5.24 on SPR report configurable bits of CPUID_1_ECX as
>>>> 0x31044988, which have
>>>>
>>>> - bit 3        MWAIT
>>>> - bit 7        EST
>>>> - bit 8        TM2
>>>> - bit 11    SDBG
>>>> - bit 14    XTPR
>>>> - bit 18    DCA
>>>> - bit 24    TSC_DEADLINE_TIMER
>>>> - bit 28    AVX
>>>> - bit 29    F16C
>>>>
>>>> but EST/TM2/SDBG/XTPR/DCA are not list here. I guess the reason is kvm_cpu_cap[] doesn't support it. If so, it seems to guard twice:
>>>> 1. mentally/manually check if it a feature is supported in kvm_cpu_caps[]
>>>>
>>>> 2. kvm_cpu_caps guarding in tdx_cpu_cfg_cap_init().
>>>>
>>>> I think 1) is not necessary, we can rely on 2)
>>> In general, if a feature is not supported by the common KVM CPU caps, 
>> For kvm-intel.ko, kvm_cpu_caps[] just means the supported CPUID features
>> for VMX VMs. Treat it as the common KVM CPU caps is a bit arguable.
>>
>>> I prefer not
>>> to add it to the list to save a few lines of code, which probably is dead code,
>> I don't think it's dead code. It shows that these features are
>> virtualizable to TDs from the POV. of TDX.
> It depends on whether KVM allows userspace to set features for TDs that are not support
> for non-TDX VMs (,except for a few exceptions).
> 
> In this version, TDX_CFG_F() already check against kvm_cpu_caps[], if these features
> are not in kvm_cpu_caps[], it will not be exposed to userspace anyway.
>

I still think the reasoning that we omit them because they are not
contained in kvm_cpu_caps[] sounds not right. Based on it, so when we are
going to add a new feature for TDX, we need to first manually check the KVM
code to see if that feature is contained in kvm_cpu_caps[] already. If not,
we just don't add it to TDX's list. Then why need to cap the result
kvm_cpu_caps[] for TDX_CFG_F() again? Just for safety in case human make
mistake and misread the code of kvm_cpu_caps[]?

I think they are two independent steps:
1. list the CPUID features that KVM can support for TDs.
2. apply additional restrictions, e.g., if a feature is not allowed for
non-TDX VMs, it cannot be allowed for TDs.

>> In the end, they might be disallowed to be configured to TDs because KVM
>> doesn't allow them for VMX VMs. This is also the point I want to discuss.
>> Do we really want to make such restriction that KVM cannot enable/allow a
>> feature for TDs unless KVM first enables/allows it for VMX VMs? What's
>> reason behind it?
> Sean mentioned it that "generally speaking, KVM shouldn't allow features
> that KVM doesn't support for non-TDX VMs" in
> https://lore.kernel.org/kvm/aj1fi_0SBxMK5WOB@google.com/

For existing features, it might make some sense. But for new features, I
don't think so. It defines the enabling order for new features that we must
enable a feature for non-TDX VMs first and then TDs. And people might want
to bypass this rule by abusing the TDX_CFG_EXTRA_F() when only one line of
TDX_CFG_EXTRA_F() is enough to enable a feature for TDs but more effort
required to enable it for non-TDX VMs.

Maybe I miss somthing. I would like to see stronger reasons for such decision.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits
  2026-08-27  3:18 ` [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits Binbin Wu
  2026-09-01  6:44   ` Tony Lindgren
@ 2026-09-03  8:04   ` Xiaoyao Li
  2026-09-03  8:23     ` Binbin Wu
  1 sibling, 1 reply; 44+ messages in thread
From: Xiaoyao Li @ 2026-09-03  8:04 UTC (permalink / raw)
  To: Binbin Wu, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 8/27/2026 11:18 AM, Binbin Wu wrote:
> Filter the directly configurable CPUID bits reported through
> KVM_TDX_CAPABILITIES against KVM's TDX allowlist, and drop the hardcoded
> denylist based filtering.
> 
> The TDX module reports all directly configurable CPUID bits that it
> supports for a TD, but KVM must not expose bits that it doesn't support,
> as blindly exposing a host state clobbering feature can lead to host state
> corruption.  The existing denylist, which clears only TSX and WAITPKG, is
> not fail-safe.
> 
> Add tdx_get_allowed_cfg_cpuid_mask() to get the mask of directly
> configurable bits allowed by KVM for a given CPUID register, covering both
> feature bits, which come from tdx_cpu_cfg_caps[], and non-feature bits,
> which are enumerated at runtime.  Apply the mask to every CPUID register
> reported through KVM_TDX_CAPABILITIES.
> 
> With the allowlist in place, newly introduced TDX directly configurable
> CPUID bits stay hidden from userspace until KVM explicitly opts in.
> 
> Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
> ---
> v3:
> - Handle non-feature leafs at runtime. (Sean)
> - Add CPUID.0x24.0.EBX[7:0] into allow list. There is a mismatch of the
>   description about CPUID.0x24.0.EBX[7:0], which is listed as
>   "XFAM & CPUID_Enabled & Native" but should be "XFAM & CPUID_Enabled &
>   Configured & Native".
> ---
>  arch/x86/kvm/vmx/tdx.c | 84 +++++++++++++++++++++++++++++++++---------
>  1 file changed, 66 insertions(+), 18 deletions(-)
> 
> diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
> index b020518717ac..e8951353de73 100644
> --- a/arch/x86/kvm/vmx/tdx.c
> +++ b/arch/x86/kvm/vmx/tdx.c
> @@ -277,34 +277,76 @@ static bool has_tsx(const struct kvm_cpuid_entry2 *entry)
>  	       (entry->ebx & TDX_FEATURE_TSX);
>  }
>  
> -static void clear_tsx(struct kvm_cpuid_entry2 *entry)
> -{
> -	entry->ebx &= ~TDX_FEATURE_TSX;
> -}
> -
>  static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry)
>  {
>  	return entry->function == 7 && entry->index == 0 &&
>  	       (entry->ecx & __feature_bit(X86_FEATURE_WAITPKG));
>  }
>  
> -static void clear_waitpkg(struct kvm_cpuid_entry2 *entry)
> +static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry)
>  {
> -	entry->ecx &= ~__feature_bit(X86_FEATURE_WAITPKG);
> +	return has_tsx(entry) || has_waitpkg(entry);
>  }
>  
> -static void tdx_clear_unsupported_cpuid(struct kvm_cpuid_entry2 *entry)
> +#define TDX_CPUID_ALL_ALLOWED_MASK	GENMASK_U32(31, 0)
> +
> +static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
>  {
> -	if (has_tsx(entry))
> -		clear_tsx(entry);
> +	/*
> +	 * For a leaf/subleaf/register that will never be repurposed to hold
> +	 * feature bits, it's safe to return TDX_CPUID_ALL_ALLOWED_MASK, i.e.
> +	 * leave the TDX module's CPUID config mask intact.
> +	 */

I don't think blindly return TDX_CPUID_ALL_ALLOWED_MASK, i.e. all-1s, is a
good idea. It's just like the current behavior that KVM doesn't gate
anything and allows userspace to set anything that is allowed by TDX
module. For example, ...

> +	switch (function) {
> +	case 1:
> +		if (reg == CPUID_EAX || reg == CPUID_EBX)
> +			return TDX_CPUID_ALL_ALLOWED_MASK;

... TDX module returns 0x0fff3fff for CPUID.1.EAX currently. If KVM makes
the mask as all-1s, then if in the future the reserved field [15:14] and
[31:28] are defined for new things and new TDX module starts to report them
as configurable, then the bits will be configurable by userspace on old
kernels while we don't know if its safe for KVM/kernel.

> +		return 0;
> +	case 4:
> +	case 0x18:
> +	case 0x1f:
> +		return TDX_CPUID_ALL_ALLOWED_MASK;
> +	case 0x24:
> +		if (index == 0 && reg == CPUID_EBX)
> +			return GENMASK_U32(7, 0);
> +		return 0;
> +	case 0x80000008:
> +		if (reg == CPUID_EAX)
> +			return TDX_CPUID_ALL_ALLOWED_MASK;
> +		return 0;
> +	default:
> +		return 0;
> +	}
> +}



^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable
  2026-09-03  6:10       ` Kishen Maloor
@ 2026-09-03  8:12         ` Binbin Wu
  0 siblings, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-03  8:12 UTC (permalink / raw)
  To: Kishen Maloor, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, xiaoyao.li, chao.gao

On 9/3/2026 2:10 PM, Kishen Maloor wrote:
> On 9/2/26 7:22 PM, Binbin Wu wrote:
>> On 9/3/2026 1:43 AM, Kishen Maloor wrote:
>>> On 8/26/26 8:18 PM, Binbin Wu wrote:
>> ...
>>
>> Actually this is the #VE reduction on fixed-1 bit, which changes a previous fixed-1
>> bit to directly configurable.
>> There are several cases of this category, i.e. MCA/MCE/MTRR/CORE_CAPABILITIES.
>> However, CORE_CAPABILITIES is the only case that KVM doesn't support for non-TDX
>> VMs
>> I will add these info to the change log.
> 
> 
> The cover letter highlights the deprecation case, but it sounds like
> you hit this now due to #VE reduction. Is further #VE reduction expected?
> If this is altogether rare, then yeah, added measures aren't necessary.

No new #VE reductions are expected.


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits
  2026-09-03  8:04   ` Xiaoyao Li
@ 2026-09-03  8:23     ` Binbin Wu
  0 siblings, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-03  8:23 UTC (permalink / raw)
  To: Xiaoyao Li, linux-kernel, kvm
  Cc: seanjc, pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 9/3/2026 4:04 PM, Xiaoyao Li wrote:
>> +static u32 tdx_cfg_non_feature_mask(u32 function, u32 index, int reg)
>>  {
>> -	if (has_tsx(entry))
>> -		clear_tsx(entry);
>> +	/*
>> +	 * For a leaf/subleaf/register that will never be repurposed to hold
>> +	 * feature bits, it's safe to return TDX_CPUID_ALL_ALLOWED_MASK, i.e.
>> +	 * leave the TDX module's CPUID config mask intact.
>> +	 */
> 
> I don't think blindly return TDX_CPUID_ALL_ALLOWED_MASK, i.e. all-1s, is a
> good idea. It's just like the current behavior that KVM doesn't gate
> anything and allows userspace to set anything that is allowed by TDX
> module. For example, ...

Sean suggested that "Realistically, CPUID.0x1.E{A,B}X are never going to be
repurposed to hold feature bits, and so generating a mask of allowed bits adds
unnecessary cognitive load and maintenance.  Ditto for CPUID 0x4, 0x18, and 0x1F."
https://lore.kernel.org/kvm/aj1fi_0SBxMK5WOB@google.com/

And I added 0x80000008.EAX as well.

> 
>> +	switch (function) {
>> +	case 1:
>> +		if (reg == CPUID_EAX || reg == CPUID_EBX)
>> +			return TDX_CPUID_ALL_ALLOWED_MASK;
> 
> ... TDX module returns 0x0fff3fff for CPUID.1.EAX currently. If KVM makes
> the mask as all-1s, then if in the future the reserved field [15:14] and
> [31:28] are defined for new things and new TDX module starts to report them
> as configurable, then the bits will be configurable by userspace on old
> kernels while we don't know if its safe for KVM/kernel.
> 
>> +		return 0;
>> +	case 4:
>> +	case 0x18:
>> +	case 0x1f:
>> +		return TDX_CPUID_ALL_ALLOWED_MASK;
>> +	case 0x24:
>> +		if (index == 0 && reg == CPUID_EBX)
>> +			return GENMASK_U32(7, 0);
>> +		return 0;
>> +	case 0x80000008:
>> +		if (reg == CPUID_EAX)
>> +			return TDX_CPUID_ALL_ALLOWED_MASK;
>> +		return 0;
>> +	default:
>> +		return 0;
>> +	}
>> +}
> 


^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM
  2026-09-03  7:28           ` Xiaoyao Li
@ 2026-09-03  8:57             ` Binbin Wu
  0 siblings, 0 replies; 44+ messages in thread
From: Binbin Wu @ 2026-09-03  8:57 UTC (permalink / raw)
  To: Xiaoyao Li, seanjc, linux-kernel, kvm
  Cc: pbonzini, dave.hansen, andrew.cooper3, nik.borisov, kas,
	rick.p.edgecombe, chao.gao

On 9/3/2026 3:28 PM, Xiaoyao Li wrote:
> On 9/3/2026 12:19 AM, Binbin Wu wrote:
>> On 9/2/2026 11:09 PM, Xiaoyao Li wrote:
>>> On 9/2/2026 8:33 AM, Binbin Wu wrote:
>>>>>> +static void __init tdx_initialize_cpu_cfg_caps(void)
>>>>>> +{
>>>>>> +    tdx_cpu_cfg_cap_init(CPUID_1_ECX,
>>>>>> +        TDX_CFG_EXTRA_F(MWAIT),
>>>>>> +        TDX_CFG_F(TSC_DEADLINE_TIMER),
>>>>>> +        TDX_CFG_F(AVX),
>>>>>> +        TDX_CFG_F(F16C),
>>>>>> +    );
>>>>> TDX 1.5.24 on SPR report configurable bits of CPUID_1_ECX as
>>>>> 0x31044988, which have
>>>>>
>>>>> - bit 3        MWAIT
>>>>> - bit 7        EST
>>>>> - bit 8        TM2
>>>>> - bit 11    SDBG
>>>>> - bit 14    XTPR
>>>>> - bit 18    DCA
>>>>> - bit 24    TSC_DEADLINE_TIMER
>>>>> - bit 28    AVX
>>>>> - bit 29    F16C
>>>>>
>>>>> but EST/TM2/SDBG/XTPR/DCA are not list here. I guess the reason is kvm_cpu_cap[] doesn't support it. If so, it seems to guard twice:
>>>>> 1. mentally/manually check if it a feature is supported in kvm_cpu_caps[]
>>>>>
>>>>> 2. kvm_cpu_caps guarding in tdx_cpu_cfg_cap_init().
>>>>>
>>>>> I think 1) is not necessary, we can rely on 2)
>>>> In general, if a feature is not supported by the common KVM CPU caps, 
>>> For kvm-intel.ko, kvm_cpu_caps[] just means the supported CPUID features
>>> for VMX VMs. Treat it as the common KVM CPU caps is a bit arguable.
>>>
>>>> I prefer not
>>>> to add it to the list to save a few lines of code, which probably is dead code,
>>> I don't think it's dead code. It shows that these features are
>>> virtualizable to TDs from the POV. of TDX.
>> It depends on whether KVM allows userspace to set features for TDs that are not support
>> for non-TDX VMs (,except for a few exceptions).
>>
>> In this version, TDX_CFG_F() already check against kvm_cpu_caps[], if these features
>> are not in kvm_cpu_caps[], it will not be exposed to userspace anyway.
>>
> 
> I still think the reasoning that we omit them because they are not
> contained in kvm_cpu_caps[] sounds not right. 

TBH,I omitted these bits for simplicity.
It's not just adding a TDX_CFG_F(XXX) for a feature, but also need to
add new X86_FEATURE_XXX definitions sometimes.
E.g. CPUID.7.0.ECX[0] (PREFETCHWT1), which is directly configurable and not
supported by KVM. It has no definition in <asm/cpufeatures.h>.

I am not sure that's worth it.

> Based on it, so when we are
> going to add a new feature for TDX, we need to first manually check the KVM
> code to see if that feature is contained in kvm_cpu_caps[] already. If not,
> we just don't add it to TDX's list. Then why need to cap the result
> kvm_cpu_caps[] for TDX_CFG_F() again? 

This is due to "generally speaking, KVM shouldn't allow features that KVM doesn't
support for non-TDX VMs".

I'm hoping Sean can weigh in on whether KVM should restrict TDX's CPU capabilities
in this way.

> Just for safety in case human make
> mistake and misread the code of kvm_cpu_caps[]?
> 
> I think they are two independent steps:
> 1. list the CPUID features that KVM can support for TDs.
> 2. apply additional restrictions, e.g., if a feature is not allowed for
> non-TDX VMs, it cannot be allowed for TDs.
> 
>>> In the end, they might be disallowed to be configured to TDs because KVM
>>> doesn't allow them for VMX VMs. This is also the point I want to discuss.
>>> Do we really want to make such restriction that KVM cannot enable/allow a
>>> feature for TDs unless KVM first enables/allows it for VMX VMs? What's
>>> reason behind it?
>> Sean mentioned it that "generally speaking, KVM shouldn't allow features
>> that KVM doesn't support for non-TDX VMs" in
>> https://lore.kernel.org/kvm/aj1fi_0SBxMK5WOB@google.com/
> 
> For existing features, it might make some sense. But for new features, I
> don't think so. It defines the enabling order for new features that we must
> enable a feature for non-TDX VMs first and then TDs. And people might want
> to bypass this rule by abusing the TDX_CFG_EXTRA_F() when only one line of
> TDX_CFG_EXTRA_F() is enough to enable a feature for TDs but more effort
> required to enable it for non-TDX VMs.

Oh, you just remind me that I should add comment for TDX_CFG_EXTRA_F() that
it must be used with a strong justification.

> 
> Maybe I miss somthing. I would like to see stronger reasons for such decision.


^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2026-09-03  8:58 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-27  3:18 [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Binbin Wu
2026-08-27  3:18 ` [PATCH v3 1/4] KVM: TDX: Track configurable CPUID bits allowed by KVM Binbin Wu
2026-09-01  6:29   ` Tony Lindgren
2026-09-01  8:23     ` Binbin Wu
2026-09-01  8:27       ` Tony Lindgren
2026-09-01 14:35   ` Xiaoyao Li
2026-09-02  0:33     ` Binbin Wu
2026-09-02 15:09       ` Xiaoyao Li
2026-09-02 16:19         ` Binbin Wu
2026-09-02 16:22           ` Edgecombe, Rick P
2026-09-02 16:25             ` Binbin Wu
2026-09-03  7:28           ` Xiaoyao Li
2026-09-03  8:57             ` Binbin Wu
2026-08-27  3:18 ` [PATCH v3 2/4] KVM: TDX: Report CORE_CAPABILITIES as configurable Binbin Wu
2026-09-01  6:45   ` Tony Lindgren
2026-09-02 17:43   ` Kishen Maloor
     [not found]     ` <d47c8cc6-242b-4ebf-89f2-0909abdaadd5@linux.intel.com>
2026-09-03  6:10       ` Kishen Maloor
2026-09-03  8:12         ` Binbin Wu
2026-08-27  3:18 ` [PATCH v3 3/4] KVM: TDX: Filter configurable CPUID bits Binbin Wu
2026-09-01  6:44   ` Tony Lindgren
2026-09-01  8:42     ` Binbin Wu
2026-09-01  9:09       ` Tony Lindgren
2026-09-03  8:04   ` Xiaoyao Li
2026-09-03  8:23     ` Binbin Wu
2026-08-27  3:18 ` [PATCH v3 4/4] KVM: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
2026-08-27  3:24   ` sashiko-bot
2026-08-27  7:25     ` Binbin Wu
2026-09-01  6:47   ` Tony Lindgren
2026-08-27 19:33 ` [PATCH v3 0/4] KVM: TDX: Validate directly configurable CPUID bits Edgecombe, Rick P
2026-08-28  3:19   ` Binbin Wu
2026-08-28 16:58     ` Edgecombe, Rick P
2026-08-31  5:01       ` Binbin Wu
2026-09-01  9:42         ` Xiaoyao Li
2026-09-01 10:21           ` Xiaoyao Li
2026-09-02 16:09           ` Edgecombe, Rick P
2026-09-02 16:21             ` Binbin Wu
2026-09-01  9:38     ` Xiaoyao Li
2026-09-01 17:41       ` Edgecombe, Rick P
2026-09-02 10:29         ` Xiaoyao Li
2026-09-02 13:13           ` Edgecombe, Rick P
2026-09-02 13:39             ` Xiaoyao Li
2026-09-02 13:53               ` Edgecombe, Rick P
2026-09-02 14:21                 ` Xiaoyao Li
2026-09-02 16:26             ` Binbin Wu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox