From nobody Mon Jun 8 09:48:10 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 435C333C183; Thu, 4 Jun 2026 02:29:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540187; cv=none; b=hSN8C5NV44iEG5uga0aIkPNE3BiOk2hbwjbr2LRuTVJExiRyC4B561tbv7YbqRZxBuWFK/V0QTiAbN/aKXetZhuxEeC46+rrXfrOGIuKc+6FxfqF602myMpX8Be2sRwLMck/PjNkKRCNY57zT6askMKqJm7u2uwmO3TqiSeA/6Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540187; c=relaxed/simple; bh=P0FQ6WFdA7o8rBHTD3kg5sOtx8g75kGcjIE4dhaHyvY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=OCm9GHlZhI5MYz0kDARxlGfvVKCP8XJfV6fwIKcF4w2/Owr/IvS2fKqICC4dY39L/NGdijQzxIlxtehA/azJXMwryMIwGpsbsvrbX/V5BUWv7YVl2SoNRMc8xKU/jwq5vMqfc9mndpEonC7kYjOToExLgCzzwred479ZSvx5x0A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=LwJyh6ns; arc=none smtp.client-ip=192.198.163.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="LwJyh6ns" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1780540186; x=1812076186; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=P0FQ6WFdA7o8rBHTD3kg5sOtx8g75kGcjIE4dhaHyvY=; b=LwJyh6ns8G6EuaL9+qleKnePvDBThwOgAOXzJDqPkloGLw0o+M3DG3yL rfpRtG4SIS7GbvWnRVhJlaxMRI2h7nQYQH5vfavfIFRSWRwYf0g8KzuYS kh5CmjpURjjV39W60IvBezE32UxQc3gQbH6wabkk5LuuSAhKqf+b+UztQ Za3vWYBnOrpXAWWYQm4Nlq0WJRmfuy75O+1r/Il9/58vmSCmN9XyoeYqG osC7bC8zMo4m6Pomd2G1PaCH8H9d+EfG+WupX2LwyBkBYbe6fc1DmKQvl qwPUw/h3C4ywNMSc4Ij6jS3TAmrNncs0xMHStdcRraiZSF7ctVZtrGgPm A==; X-CSE-ConnectionGUID: c32aV1fiRE2DBX3IaBjOfA== X-CSE-MsgGUID: 90NnRnqHTD6KZEKw5S4Txg== X-IronPort-AV: E=McAfee;i="6800,10657,11806"; a="92045241" X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="92045241" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by fmvoesa103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:46 -0700 X-CSE-ConnectionGUID: RyYaxhUfRqa8w+23+xZmQA== X-CSE-MsgGUID: 4icEnwJ1T624mO5SKqBO+g== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="239940487" Received: from litbin-desktop.sh.intel.com ([10.239.159.60]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:43 -0700 From: Binbin Wu 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 Message-ID: <20260604023314.3907511-2-binbin.wu@linux.intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20260604023314.3907511-1-binbin.wu@linux.intel.com> References: <20260604023314.3907511-1-binbin.wu@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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) =20 +#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 initializ= ed + * in tdx_initialize_cpu_cfg_caps(). + */ +static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after= _init =3D { + { 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 |=3D feature_bit(name); \ +}) + +#define tdx_cpu_cfg_cap_init(_func, _index, _reg, feature_initializers...)= \ +do { \ + u32 tdx_cpu_cfg_caps =3D 0; \ + \ + for (int i =3D 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) { \ + struct tdx_supported_cpuid_reg *r =3D &tdx_kvm_supported_cpuid[i]; \ + \ + if (r->function =3D=3D _func && r->index =3D=3D _index && r->reg =3D=3D = _reg) { \ + feature_initializers \ + r->mask |=3D 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), + ); +} =20 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; } =20 + tdx_initialize_cpu_cfg_caps(); + KVM_SANITY_CHECK_VM_STRUCT_SIZE(kvm_tdx); =20 vt_x86_ops.vm_size =3D max_t(unsigned int, vt_x86_ops.vm_size, sizeof(str= uct kvm_tdx)); --=20 2.46.0 From nobody Mon Jun 8 09:48:10 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8D3D938886D; Thu, 4 Jun 2026 02:29:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540189; cv=none; b=OlPc80GLgvAnx5qzqcr4lLQyWA3PJDZIe4ZmIqAGt0OktufnHmEycAadgEihCGHQVG4axP+TkAZB7zoVccv+iVeWSS/RflzYFIgd0IOS+wks2xfIw8Ump0mqJBmWf/ySvnLX/jPDjE58SrXVC1HLodq4IYNi4+uMzQccofsVfbc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540189; c=relaxed/simple; bh=xwK68B92/UflQqs5aToPfmv//wqYugSBt/mfmPvl6mE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pjNDwCsyXdiGqsaVKfiJ9F6ku5JiFZCoM/OZxRyARU9UtbyDPyBymvehvE7WtT0td4vrYRuhIQsymTP42eLwvzicUDbRl6W+mtoNFb9RtKNxnzO3iHziOx82u2xQ+c6MyRd6P5+MdPyCGjKC19Q5wv89q/PzFIhDL0phP7FTySs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=ixEHIjUd; arc=none smtp.client-ip=192.198.163.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ixEHIjUd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1780540189; x=1812076189; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=xwK68B92/UflQqs5aToPfmv//wqYugSBt/mfmPvl6mE=; b=ixEHIjUdNvxdNd3BfMcCwzwrENpAMy3xTl868oybD22LCn0/4tpdpZoX e0/P6na+JXcC0pEAxXkY2zq/5psE77jetIsm9t4iRCe6BCBZP2pZv5lMW 8FEubfQHLkAYerRu2OzjTfWmtACZ/iqZcZ1U/mAiYYTZkDFmCjV0turf+ 5pBJPzl7SaiY4HJlYnrkGMXAuaAcKBDLpV64nJEQLpFGXxe3qbpbW/DjQ S7V+5wivD+zB1S0v9nKJr9ZwPvvg8s7ql2uwUm7QB8PgcSAOZIL0HKbb4 NSHuDPb35QWlWcoz9dQ+S+iAnj4TAcuW0UYsaio490RrydGUvgdUld9Xs Q==; X-CSE-ConnectionGUID: NZcQ7cvsSryeiNDj38oWCg== X-CSE-MsgGUID: z4Zo8pkYSCWDWXJ6ZrQ9Zg== X-IronPort-AV: E=McAfee;i="6800,10657,11806"; a="92045246" X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="92045246" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by fmvoesa103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:48 -0700 X-CSE-ConnectionGUID: o9Wkyo8vSFKf8Bamzdmmgg== X-CSE-MsgGUID: ePxGMzYTRa6m2/QGV7P+rw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="239940494" Received: from litbin-desktop.sh.intel.com ([10.239.159.60]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:46 -0700 From: Binbin Wu 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 2/4] KVM: x86: TDX: Hide unsupported configurable CPUID bits Date: Thu, 4 Jun 2026 10:33:12 +0800 Message-ID: <20260604023314.3907511-3-binbin.wu@linux.intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20260604023314.3907511-1-binbin.wu@linux.intel.com> References: <20260604023314.3907511-1-binbin.wu@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Filter the CPUID capabilities reported by KVM_TDX_CAPABILITIES through KVM's supported TDX configurable CPUID allowlist. The TDX module reports all configurable CPUID bits it supports for a TD, but KVM must not expose bits to userspace that it doesn't support. Blindly exposing unsupported features could lead to host state corruption. Add a helper get_supported_cfg_cpuid() to retrieve KVM's supported TDX configurable CPUID bit mask for a given leaf, subleaf, and register. Additionally, add a comment explicitly noting that the allowlist array must remain sorted by CPUID function. This allows the helper's linear search to safely terminate early once it iterates past the target leaf, optimizing the lookup process. Replace the existing hardcoded denylist with a secure-by-default approach. By using the get_supported_cfg_cpuid() helper, KVM now strictly reports only the configurable CPUID bits it explicitly supports. This ensures any newly introduced configurable CPUID bits are automatically hidden from userspace until KVM specifically opts in. Signed-off-by: Binbin Wu --- arch/x86/kvm/vmx/tdx.c | 45 +++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index e0567088ebf5..e6bfec87a484 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -64,6 +64,8 @@ struct tdx_supported_cpuid_reg { /* * Multi-bit fields are statically initialized, feature bits are initializ= ed * in tdx_initialize_cpu_cfg_caps(). + * + * Keep the list sorted by CPUID function. */ static struct tdx_supported_cpuid_reg tdx_kvm_supported_cpuid[] __ro_after= _init =3D { { 0x1, 0, 0, CPUID_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0) }, @@ -300,34 +302,31 @@ static bool has_tsx(const struct kvm_cpuid_entry2 *en= try) (entry->ebx & TDX_FEATURE_TSX); } =20 -static void clear_tsx(struct kvm_cpuid_entry2 *entry) -{ - entry->ebx &=3D ~TDX_FEATURE_TSX; -} - static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry) { return entry->function =3D=3D 7 && entry->index =3D=3D 0 && (entry->ecx & __feature_bit(X86_FEATURE_WAITPKG)); } =20 -static void clear_waitpkg(struct kvm_cpuid_entry2 *entry) +static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry) { - entry->ecx &=3D ~__feature_bit(X86_FEATURE_WAITPKG); + return has_tsx(entry) || has_waitpkg(entry); } =20 -static void tdx_clear_unsupported_cpuid(struct kvm_cpuid_entry2 *entry) +static u32 get_supported_cfg_cpuid(u32 function, u32 index, u8 reg) { - if (has_tsx(entry)) - clear_tsx(entry); + for (int i =3D 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) { + struct tdx_supported_cpuid_reg *r =3D &tdx_kvm_supported_cpuid[i]; =20 - if (has_waitpkg(entry)) - clear_waitpkg(entry); -} + if (r->function > function) + break; =20 -static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *entry) -{ - return has_tsx(entry) || has_waitpkg(entry); + if (r->function =3D=3D function && r->reg =3D=3D reg && + (r->index =3D=3D index || (r->flags & TDX_CPUID_IGNORE_INDEX))) + return r->mask; + } + + return 0; } =20 #define KVM_TDX_CPUID_NO_SUBLEAF ((__u32)-1) @@ -353,8 +352,6 @@ static void td_init_cpuid_entry2(struct kvm_cpuid_entry= 2 *entry, unsigned char i */ if (entry->function =3D=3D 0x80000008) entry->eax =3D tdx_set_guest_phys_addr_bits(entry->eax, 0xff); - - tdx_clear_unsupported_cpuid(entry); } =20 #define TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT BIT(1) @@ -377,8 +374,16 @@ static int init_kvm_tdx_caps(const struct tdx_sys_info= _td_conf *td_conf, caps->user_tdvmcallinfo_1_r11 =3D TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT; =20 - for (i =3D 0; i < td_conf->num_cpuid_config; i++) - td_init_cpuid_entry2(&caps->cpuid.entries[i], i); + for (i =3D 0; i < td_conf->num_cpuid_config; i++) { + struct kvm_cpuid_entry2 *e =3D &caps->cpuid.entries[i]; + + td_init_cpuid_entry2(e, i); + /* Only report the configurable bits supported by KVM. */ + e->eax &=3D get_supported_cfg_cpuid(e->function, e->index, CPUID_EAX); + e->ebx &=3D get_supported_cfg_cpuid(e->function, e->index, CPUID_EBX); + e->ecx &=3D get_supported_cfg_cpuid(e->function, e->index, CPUID_ECX); + e->edx &=3D get_supported_cfg_cpuid(e->function, e->index, CPUID_EDX); + } =20 return 0; } --=20 2.46.0 From nobody Mon Jun 8 09:48:10 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6EC7F38C2DB; Thu, 4 Jun 2026 02:29:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540191; cv=none; b=e7IeQlKbxQWmmohpfyNH9M9660LuRR/dPEqRz0cVzAw1qiMGMuI6jbGqbTJSuM304DK+o8pCDlbkRoFGKkNvFvlEBCOkDdeUWSKXHr0YggrGFBt3Z5vLOreIIktXnEap1rc7coR4Exaqc/VLiUweSPu3rn711s6x+O58GtkyeBs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540191; c=relaxed/simple; bh=64YjlntfLLkE9KZvhKTh5VtVwDl+Pva8cUIUnqi30Ew=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=k4T0VleLtXHx61IOjawbLx/oWXtmx2De2tRi3HX4YZ7oW0CMQnpqfy3KgZCeB7/W8QlLwma0KkqnzQnPq5pgURWbVc8LhhhoAzi+/8Dt9xEgsvdLoCreyI1U/OnocaI/VgVWppAEdZ2V52PCyIDzsP7h2lgo+cEXJ7mR9gTzGqo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=DId0EZx1; arc=none smtp.client-ip=192.198.163.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="DId0EZx1" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1780540191; x=1812076191; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=64YjlntfLLkE9KZvhKTh5VtVwDl+Pva8cUIUnqi30Ew=; b=DId0EZx1sccNlcRcraWNBTD+0ZQ74BEtubqp2g28wHm4DPJkXRYuY5uC Iwdyt61Bhd4PobPLyvP6Cznb4Vgr6Tabi2HJ0Px6E/jwXLEPIWcGbSx8u WVK8+unnteCz+J0VYjXAdDJdBTMSwjxL2dxJArL+rJlb3V8LIgeeNH0oG TmiZYXee1qPQFJzeXedxV3EA9lftIer2FEtr5UaI03KeMa16edmEYUsgg /HDvm3VVbOGxeZAA6Ye6G+7v6BBWRPFBc6XSXhoO1eUMKKkYlPjbJgcMF DmLr0sL9XZqT/kW4mM/Pyrz1ZI+ZvaScRPWq0DEoYyo2YZii+LYSRcGcE w==; X-CSE-ConnectionGUID: aVtYjn22SpKMaBtOTcof3A== X-CSE-MsgGUID: zE3veM3rQzaKlYRkgFvOmg== X-IronPort-AV: E=McAfee;i="6800,10657,11806"; a="92045252" X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="92045252" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by fmvoesa103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:50 -0700 X-CSE-ConnectionGUID: usI6NYpmToe35ZiTJc7jqg== X-CSE-MsgGUID: 1eJeIqaCRWGZnHihpYExSg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="239940503" Received: from litbin-desktop.sh.intel.com ([10.239.159.60]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:48 -0700 From: Binbin Wu 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 3/4] KVM: x86: TDX: Validate userspace CPUID input for KVM_TDX_INIT_VM Date: Thu, 4 Jun 2026 10:33:13 +0800 Message-ID: <20260604023314.3907511-4-binbin.wu@linux.intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20260604023314.3907511-1-binbin.wu@linux.intel.com> References: <20260604023314.3907511-1-binbin.wu@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Reject unsupported TDX configurable CPUID bits provided by userspace during KVM_TDX_INIT_VM. While the TDX module allows the VMM to configure certain CPUID features for a TD during initialization, KVM must strictly govern which features are actually enabled. Allowing userspace to blindly enable features that KVM does not yet support=E2=80=94particularly those involving host state clobbering MSRs=E2=80=94could lead to host state corruption, as KVM is not prepared to manage the associated architectural state across host/guest transitions. Replace the hardcoded denylist with a robust validation mechanism. By leveraging the get_supported_cfg_cpuid() helper, KVM now explicitly rejects the input if userspace attempts to set any TDX configurable bit that is not present in KVM's allowlist. Signed-off-by: Binbin Wu --- arch/x86/kvm/vmx/tdx.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index e6bfec87a484..e44a862c6219 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -294,25 +294,6 @@ static u32 tdx_set_guest_phys_addr_bits(const u32 eax,= int addr_bits) return (eax & ~GENMASK(23, 16)) | (addr_bits & 0xff) << 16; } =20 -#define TDX_FEATURE_TSX (__feature_bit(X86_FEATURE_HLE) | __feature_bit(X8= 6_FEATURE_RTM)) - -static bool has_tsx(const struct kvm_cpuid_entry2 *entry) -{ - return entry->function =3D=3D 7 && entry->index =3D=3D 0 && - (entry->ebx & TDX_FEATURE_TSX); -} - -static bool has_waitpkg(const struct kvm_cpuid_entry2 *entry) -{ - return entry->function =3D=3D 7 && entry->index =3D=3D 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); -} - static u32 get_supported_cfg_cpuid(u32 function, u32 index, u8 reg) { for (int i =3D 0; i < ARRAY_SIZE(tdx_kvm_supported_cpuid); i++) { @@ -2526,6 +2507,15 @@ static int setup_tdparams_eptp_controls(struct kvm_c= puid2 *cpuid, return 0; } =20 +static bool tdx_unsupported_cpuid(const struct kvm_cpuid_entry2 *e, + const struct kvm_cpuid_entry2 *mask) +{ + return ((e->eax & mask->eax & (~get_supported_cfg_cpuid(e->function, e->i= ndex, CPUID_EAX))) || + (e->ebx & mask->ebx & (~get_supported_cfg_cpuid(e->function, e->index, C= PUID_EBX))) || + (e->ecx & mask->ecx & (~get_supported_cfg_cpuid(e->function, e->index, C= PUID_ECX))) || + (e->edx & mask->edx & (~get_supported_cfg_cpuid(e->function, e->index, C= PUID_EDX)))); +} + static int setup_tdparams_cpuids(struct kvm_cpuid2 *cpuid, struct td_params *td_params) { @@ -2549,7 +2539,7 @@ static int setup_tdparams_cpuids(struct kvm_cpuid2 *c= puid, if (!entry) continue; =20 - if (tdx_unsupported_cpuid(entry)) + if (tdx_unsupported_cpuid(entry, &tmp)) return -EINVAL; =20 copy_cnt++; --=20 2.46.0 From nobody Mon Jun 8 09:48:10 2026 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.9]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B36E93905EB; Thu, 4 Jun 2026 02:29:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.9 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540194; cv=none; b=OK+rp1DwJgswKHQe/1ijiGR69OxcW9dgZZesA2kGHvEhqOR95qVKbXjOqSMhgpew141xcmq3NIsjTgz2E6FYbDWzUvNWgImeVXoc6SffFsbpPW99bCkAEqmiacppH8r/H6mL6FSKxkNY0omNbbc3U6FAEegh5EloSyF4yEwU3CA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780540194; c=relaxed/simple; bh=pYl6liv+2TMJ+8mh4MCfBv7ITSiH+H9Y0E6l4W2nMww=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kfevAGPz8Cn4v+dI38DwUZtXSHIipa/6sAXgeKMuug4WrQALEywZWPBLvyVDw9RUN1+UwfHgkxRdtscKXA8SbyPDW62xXSYdsJy3DY0dj4Sk9012LqiBQVI3JPX18IgNH7i+6P2VHnfoxUFt1snGfy19kmDxTEe0kgbfhzGlN9A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=G7xcTr1V; arc=none smtp.client-ip=192.198.163.9 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="G7xcTr1V" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1780540193; x=1812076193; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=pYl6liv+2TMJ+8mh4MCfBv7ITSiH+H9Y0E6l4W2nMww=; b=G7xcTr1VunZyOSi6kj+1BeoBDTeIsEoz3J81b18ZDt/KffccWnOCLfB4 tF7HrxgLQLnz4ZI9j5gZgwi0pHsxTkftrrryPMhwmMw+wpI8t6xL8+/wK RexAV3B0+KidWYgis28mu64/dZXXnQgHp7Wg5wXeotehuw/RfjYklT4xe yWxpvirKbohj7Z7+l4Y2BUODAMYii7koUY+3mAIBFHkbP6zgWMsVYSoel 0KTQU30Ndn0gPgNNZZqO/x1E4b7biwRlLlCs5kTVczLrwSLARqgaXxcPT Nlgo+p20dgt/1z5+aPEnjj6ITcVWUdAmNrb7nW7c7w+PKNj6W+cCMSVGN A==; X-CSE-ConnectionGUID: OAJYiaRISPKcWYVjvn6dRQ== X-CSE-MsgGUID: B9q47kFkQ8GTABRmgnvJpw== X-IronPort-AV: E=McAfee;i="6800,10657,11806"; a="92045256" X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="92045256" Received: from fmviesa006.fm.intel.com ([10.60.135.146]) by fmvoesa103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:53 -0700 X-CSE-ConnectionGUID: hP8yUHYXQy6HJ5ViOVE0uw== X-CSE-MsgGUID: LmwZ6O+OSpWo/XTYXSMdoQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.24,186,1774335600"; d="scan'208";a="239940510" Received: from litbin-desktop.sh.intel.com ([10.239.159.60]) by fmviesa006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jun 2026 19:29:50 -0700 From: Binbin Wu 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 4/4] KVM: x86: TDX: Report CORE_CAPABILITIES as supported Date: Thu, 4 Jun 2026 10:33:14 +0800 Message-ID: <20260604023314.3907511-5-binbin.wu@linux.intel.com> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20260604023314.3907511-1-binbin.wu@linux.intel.com> References: <20260604023314.3907511-1-binbin.wu@linux.intel.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add CORE_CAPABILITIES (CPUID.0x7.0.EDX[30]) to the TDX configurable CPUID allowlist to accommodate legacy TDX module behavior. KVM doesn't support MSR_IA32_CORE_CAPS, however, some older TDX specs define CORE_CAPABILITIES CPUID bit as fixed-1. As a result, userspace may expect this bit to be enabled in the TDX module for TDs. When the CPUID bit becomes a directly configurable without reporting to the userspace, it can not be enabled. To avoid confusing userspace, report CORE_CAPABILITIES to userspace via KVM_TDX_CAPABILITIES. Although KVM could determine the real CPUID setting by reading the metadata via SEAMCALL after KVM_TDX_INIT_VM, doing so is overkill to cover such a corner case. If CORE_CAPABILITIES is exposed to a TDX guest, and the guest reads it, simply return 0. Signed-off-by: Binbin Wu --- arch/x86/kvm/vmx/tdx.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index e44a862c6219..58647bb70708 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -175,7 +175,7 @@ static void __init tdx_initialize_cpu_cfg_caps(void) TDX_F(SERIALIZE), TDX_F(TSXLDTRK), /* PCONFIG */ - /* IA32_CORE_CAPABILITIES */ + TDX_F(CORE_CAPABILITIES), ); =20 tdx_cpu_cfg_cap_init(0x7, 1, CPUID_EAX, @@ -2401,6 +2401,14 @@ int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_da= ta *msr) return 1; msr->data =3D vcpu->arch.mcg_ext_ctl; return 0; + case MSR_IA32_CORE_CAPS: + /* + * KVM doesn't support MSR_IA32_CORE_CAPS, however, in some old + * TDX modules, CPUID.0x7.0.EDX[30] is fixed-1. As a workaround, + * just return 0 for this MSR. + */ + msr->data =3D 0; + return 0; default: if (!tdx_has_emulated_msr(msr->index)) return 1; --=20 2.46.0