All of lore.kernel.org
 help / color / mirror / Atom feed
From: Binbin Wu <binbin.wu@linux.intel.com>
To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: seanjc@google.com, pbonzini@redhat.com,
	rick.p.edgecombe@intel.com, xiaoyao.li@intel.com,
	chao.gao@intel.com, kai.huang@intel.com,
	binbin.wu@linux.intel.com
Subject: [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported configurable CPUID bits
Date: Thu,  4 Jun 2026 10:33:11 +0800	[thread overview]
Message-ID: <20260604023314.3907511-2-binbin.wu@linux.intel.com> (raw)
In-Reply-To: <20260604023314.3907511-1-binbin.wu@linux.intel.com>

Build an allowlist for TDX directly configurable CPUID bits that are
supported by KVM.

The TDX module reports a set of CPUID bits that the VMM can directly
configure for a TD, but KVM cannot blindly trust and expose all
module-supported bits to userspace. Certain features imply additional
architectural state (such as one or more host state clobbering MSRs)
that KVM must explicitly manage across host/guest transitions to
prevent host state corruption.

To safely manage this, track the specific subset of configurable CPUID
bits that KVM supports by initializing multi-bit fields statically and
populating individual feature bits dynamically during TDX hardware
setup.

For better readability and maintainability, define a macro
tdx_cpu_cfg_cap_init() to initialize the feature bits.

Subsequent patches will use this allowlist to consistently filter
KVM_TDX_CAPABILITIES and reject unsupported userspace input through
KVM_TDX_INIT_VM. This ensures that any newly introduced TDX configurable
CPUID bits remain hidden from userspace until KVM explicitly implements
the required virtualization support.

Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
 arch/x86/kvm/vmx/tdx.c | 174 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 174 insertions(+)

diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index ffe9d0db58c5..e0567088ebf5 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -52,6 +52,178 @@
 	__TDX_BUG_ON(__err, #__fn, __kvm, ", " #a1 " 0x%llx, " #a2 ", 0x%llx, " #a3 " 0x%llx", \
 		     a1, a2, a3)
 
+#define TDX_CPUID_IGNORE_INDEX	BIT(0)
+struct tdx_supported_cpuid_reg {
+	u32 function;
+	u32 index;
+	u8 flags;
+	u8 reg;
+	u32 mask;
+};
+
+/*
+ * Multi-bit fields are statically initialized, feature bits are initialized
+ * in tdx_initialize_cpu_cfg_caps().
+ */
+static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after_init = {
+	{ 0x1, 0, 0, CPUID_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0) },
+	{ 0x1, 0, 0, CPUID_EBX, GENMASK_U32(23, 16) },
+	{ 0x1, 0, 0, CPUID_ECX, 0 },
+	{ 0x1, 0, 0, CPUID_EDX, 0 },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, ~GENMASK_U32(13, 10) },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(31, 12) },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(31, 0) },
+	{ 0x4, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(2, 0) },
+	{ 0x7, 0, 0, CPUID_EBX, 0 },
+	{ 0x7, 0, 0, CPUID_ECX, 0 },
+	{ 0x7, 0, 0, CPUID_EDX, 0 },
+	{ 0x7, 1, 0, CPUID_EAX, 0 },
+	{ 0x7, 1, 0, CPUID_EDX, 0 },
+	{ 0x7, 2, 0, CPUID_EDX, 0 },
+	{ 0x18, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EDX, GENMASK_U32(25, 14) },
+	{ 0x1E, 1, 0, CPUID_EAX, 0 },
+	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EAX, GENMASK_U32(4, 0) },
+	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_EBX, GENMASK_U32(15, 0) },
+	{ 0x1F, 0, TDX_CPUID_IGNORE_INDEX, CPUID_ECX, GENMASK_U32(15, 0) },
+	/* See comments in td_init_cpuid_entry2() for CPUID 0x80000008 EAX[23:16]. */
+	{ 0x80000008, 0, 0, CPUID_EAX, GENMASK_U32(23, 16) | GENMASK_U32(7, 0) },
+	{ 0x80000008, 0, 0, CPUID_EBX, 0 },
+};
+
+#define TDX_F(name)					\
+({							\
+	tdx_cpu_cfg_caps |= feature_bit(name);		\
+})
+
+#define tdx_cpu_cfg_cap_init(_func, _index, _reg, feature_initializers...)		\
+do {											\
+	u32 tdx_cpu_cfg_caps = 0;							\
+											\
+	for (int i = 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) {			\
+		struct tdx_supported_cpuid_reg *r = &tdx_kvm_supported_cpuid[i];	\
+											\
+		if (r->function == _func && r->index == _index && r->reg == _reg) {	\
+			feature_initializers						\
+			r->mask |= tdx_cpu_cfg_caps;					\
+			break;								\
+		}									\
+	}										\
+											\
+	WARN_ON_ONCE(!tdx_cpu_cfg_caps); 						\
+} while (0)
+
+/* Only for TDX directly configurable CPUID feature bits */
+static void __init tdx_initialize_cpu_cfg_caps(void)
+{
+	tdx_cpu_cfg_cap_init(0x1, 0, CPUID_ECX,
+		TDX_F(MWAIT),
+		TDX_F(TSC_DEADLINE_TIMER),
+		TDX_F(AVX),
+		TDX_F(F16C),
+	);
+
+	tdx_cpu_cfg_cap_init(0x1, 0, CPUID_EDX,
+		TDX_F(MCE),
+		TDX_F(MTRR),
+		TDX_F(MCA),
+		TDX_F(SELFSNOOP),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 0, CPUID_EBX,
+		TDX_F(BMI1),
+		/* HLE */
+		TDX_F(BMI2),
+		TDX_F(ERMS),
+		/* RTM */
+		/* CQM */
+		/* RDT-A */
+		TDX_F(AVX512F),
+		TDX_F(AVX512DQ),
+		TDX_F(ADX),
+		TDX_F(AVX512IFMA),
+		TDX_F(AVX512PF),
+		TDX_F(AVX512ER),
+		TDX_F(AVX512CD),
+		TDX_F(AVX512BW),
+		TDX_F(AVX512VL),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 0, CPUID_ECX,
+		/* PREFETCHWT1 */
+		TDX_F(UMIP),
+		/* WAITPKG */
+		TDX_F(AVX512_VBMI2),
+		TDX_F(GFNI),
+		TDX_F(VAES),
+		TDX_F(VPCLMULQDQ),
+		TDX_F(AVX512_VNNI),
+		TDX_F(AVX512_BITALG),
+		/* TME */
+		TDX_F(AVX512_VPOPCNTDQ),
+		TDX_F(LA57),
+		TDX_F(RDPID),
+		TDX_F(CLDEMOTE),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 0, CPUID_EDX,
+		TDX_F(AVX512_4VNNIW),
+		TDX_F(AVX512_4FMAPS),
+		TDX_F(FSRM),
+		TDX_F(AVX512_VP2INTERSECT),
+		TDX_F(SERIALIZE),
+		TDX_F(TSXLDTRK),
+		/* PCONFIG */
+		/* IA32_CORE_CAPABILITIES */
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 1, CPUID_EAX,
+		TDX_F(SHA512),
+		TDX_F(SM3),
+		TDX_F(SM4),
+		/* RAO_INT */
+		TDX_F(AVX_VNNI),
+		TDX_F(AVX512_BF16),
+		TDX_F(CMPCCXADD),
+		/* PERFMON */
+		TDX_F(FZRM),
+		TDX_F(FSRS),
+		TDX_F(FSRC),
+		/* FRED */
+		TDX_F(LKGS),
+		TDX_F(WRMSRNS),
+		TDX_F(AMX_FP16),
+		TDX_F(AVX_IFMA),
+		TDX_F(LAM),
+		TDX_F(MOVRS),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 1, CPUID_EDX,
+		TDX_F(AVX_VNNI_INT8),
+		TDX_F(AVX_NE_CONVERT),
+		TDX_F(AVX_VNNI_INT16),
+		TDX_F(PREFETCHITI),
+		/* UMSR */
+		/* UIRET loads UIF */
+		TDX_F(AVX10),
+	);
+
+	tdx_cpu_cfg_cap_init(0x7, 2, CPUID_EDX,
+		TDX_F(DDPD_U),
+		TDX_F(MCDT_NO),
+	);
+
+	tdx_cpu_cfg_cap_init(0x1E, 1, CPUID_EAX,
+		TDX_F(AMX_FP8),
+		/* AMX-TRANSPOSE */
+		TDX_F(AMX_TF32),
+		TDX_F(AMX_AVX512),
+		TDX_F(AMX_MOVRS),
+	);
+
+	tdx_cpu_cfg_cap_init(0x80000008, 0, CPUID_EBX,
+		TDX_F(WBNOINVD),
+	);
+}
 
 bool enable_tdx __ro_after_init;
 module_param_named(tdx, enable_tdx, bool, 0444);
@@ -3493,6 +3665,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


  reply	other threads:[~2026-06-04  2:29 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-04  2:33 [RFC PATCH v2 0/4] KVM: x86: TDX: Validate directly configurable CPUID bits Binbin Wu
2026-06-04  2:33 ` Binbin Wu [this message]
2026-06-04  2:44   ` [RFC PATCH v2 1/4] KVM: x86: TDX: Track supported " sashiko-bot
2026-06-04  5:37     ` Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 2/4] KVM: x86: TDX: Hide unsupported " Binbin Wu
2026-06-04  2:47   ` sashiko-bot
2026-06-04  2:54     ` Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 3/4] KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Binbin Wu
2026-06-04  2:49   ` sashiko-bot
2026-06-04  3:13     ` Binbin Wu
2026-06-04  2:33 ` [RFC PATCH v2 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported Binbin Wu
2026-06-04  2:51   ` sashiko-bot
2026-06-04  5:32     ` Binbin Wu
2026-06-04  5:40       ` Binbin Wu
2026-06-04  6:53   ` Xiaoyao Li
2026-06-04  7:20     ` Binbin Wu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260604023314.3907511-2-binbin.wu@linux.intel.com \
    --to=binbin.wu@linux.intel.com \
    --cc=chao.gao@intel.com \
    --cc=kai.huang@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=seanjc@google.com \
    --cc=xiaoyao.li@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.