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
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox