From: Binbin Wu <binbin.wu@linux.intel.com>
To: kvm@vger.kernel.org
Cc: pbonzini@redhat.com, seanjc@google.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 16/27] KVM: x86: Init allowed masks for basic CPUID range in paranoid mode
Date: Fri, 17 Apr 2026 15:35:59 +0800 [thread overview]
Message-ID: <20260417073610.3246316-17-binbin.wu@linux.intel.com> (raw)
In-Reply-To: <20260417073610.3246316-1-binbin.wu@linux.intel.com>
Populate the CPUID paranoid mode validation data for the basic CPUID
range (0x0 through 0x24).
For each CPUID output register, the validation follows one of three
rules:
1. Ignored: the register is added to the ignored set and KVM skips
validation of the userspace-provided value.
2. Mask/value check: a new KVM-only CPUID leaf enum is defined with a
corresponding reverse_cpuid[] entry, and an allowed mask or fixed
value is initialized per-overlay.
3. Zero check: for reserved registers or registers where no bits are
supported, userspace input is checked against zero.
Add is_cpuid_subleaf_common_pattern() to map higher sub-leaf indices to
a representative sub-leaf for validation, avoiding duplicate mask
definitions for CPUID functions 4, 0xB, 0xD, 0x12, and 0x1F.
Add is_cpuid_reg_check_value() to flag registers where userspace input
must exactly match fixed values (CPUID 0x1D, 0x1E.0.EBX) rather than
being validated against a bitmask.
Notable leaf-specific handling:
- CPUID 0x1.EDX: HT is emulated to allow userspace to set it, but
masked when reporting supported CPUID to userspace.
- CPUID 0x6.EAX: ARAT initialized as emulated, replacing the hardcoded
value in __do_cpuid_func().
- CPUID 0x6.ECX: APERFMPERF allowed for VMX/SVM (userspace may enable
KVM_X86_DISABLE_EXITS_APERFMPERF and set it), fixed-0 for TDX.
- CPUID 0x7.0.EDX: CORE_CAPABILITIES set for TDX to accommodate old
TDX modules that report bit 30 as fixed-1; MSR_IA32_CORE_CAPS reads
return 0 inside a TD as a workaround.
- CPUID 0xD: XCR0-based masks for subleaf 0, XSS-based for subleaf 1;
size/offset fields are ignored
- CPUID 0x12: SGX sub-leaf masks initialized when SGX is supported,
replacing hardcoded masks in __do_cpuid_func().
- CPUID 0x14: PT masks initialized for VMX from intel pt_caps[].
Override CPUID.0x14.0.{EBX, ECX} when reporting capabilities to
userspace.
- CPUID 0x1D: fixed values from Intel SDM, exact-match required.
- CPUID 0x1E.0: EAX capped at 1 (max supported sub-leaf), EBX is a
fixed value from Intel SDM.
- CPUID 0x24: AVX10 version capped at 2, merged with vector-width bits.
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
arch/x86/include/asm/kvm_host.h | 45 +++++++-
arch/x86/kvm/cpuid.c | 186 +++++++++++++++++++++++++++++---
arch/x86/kvm/reverse_cpuid.h | 47 ++++++++
arch/x86/kvm/vmx/tdx.c | 10 +-
arch/x86/kvm/vmx/vmx.c | 14 +++
5 files changed, 288 insertions(+), 14 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 75895ab569fb..90514791f0fd 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -794,7 +794,50 @@ enum kvm_only_cpuid_leafs {
CPUID_24_1_ECX,
/* End of the leafs tracked by per-vcpu caps. */
NR_KVM_CPU_CAPS,
- NR_KVM_CPU_CAPS_PARANOID = NR_KVM_CPU_CAPS,
+ CPUID_1_EAX = NR_KVM_CPU_CAPS,
+ CPUID_2_EAX,
+ CPUID_4_0_EAX,
+ CPUID_4_0_EDX,
+ CPUID_5_EAX,
+ CPUID_5_EBX,
+ CPUID_5_ECX,
+ CPUID_6_ECX,
+ CPUID_A_EAX,
+ CPUID_A_EBX,
+ CPUID_A_ECX,
+ CPUID_A_EDX,
+ CPUID_B_0_EAX,
+ CPUID_B_0_EBX,
+ CPUID_B_0_ECX,
+ CPUID_D_0_EAX,
+ CPUID_D_0_EDX,
+ CPUID_D_1_ECX,
+ CPUID_D_2_ECX,
+ CPUID_12_0_EBX,
+ CPUID_12_0_EDX,
+ CPUID_12_1_EAX,
+ CPUID_12_1_ECX,
+ CPUID_12_1_EDX,
+ CPUID_12_2_EAX,
+ CPUID_12_2_EBX,
+ CPUID_12_2_ECX,
+ CPUID_12_2_EDX,
+ CPUID_14_0_EAX,
+ CPUID_14_0_EBX,
+ CPUID_14_0_ECX,
+ CPUID_14_1_EAX,
+ CPUID_14_1_EBX,
+ CPUID_1D_0_EAX,
+ CPUID_1D_1_EAX,
+ CPUID_1D_1_EBX,
+ CPUID_1D_1_ECX,
+ CPUID_1E_0_EAX,
+ CPUID_1E_0_EBX,
+ CPUID_1F_0_EAX,
+ CPUID_1F_0_EBX,
+ CPUID_1F_0_ECX,
+ CPUID_24_0_EAX,
+ NR_KVM_CPU_CAPS_PARANOID,
NKVMCAPINTS = NR_KVM_CPU_CAPS_PARANOID - NCAPINTS,
};
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index e633707277f9..59f0b3166eaa 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -392,8 +392,8 @@ static int cpuid_func_emulated(struct kvm *kvm, struct kvm_cpuid_entry2 *entry,
* - Use -1 as index_end to indicate open-ended index ranges starting from
* index_start.
*/
-static void __maybe_unused kvm_cpu_cap_ignore(u32 func, u32 index_start, u32 index_end,
- u32 reg_mask, u32 overlay_mask)
+static void kvm_cpu_cap_ignore(u32 func, u32 index_start, u32 index_end,
+ u32 reg_mask, u32 overlay_mask)
{
if (WARN_ON_ONCE(ignored_set.nr >= KVM_MAX_CPUID_ENTRIES))
return;
@@ -419,6 +419,35 @@ static bool __maybe_unused is_cpuid_paranoid_ignored(u32 func, u32 index, int re
return false;
}
+static bool __maybe_unused is_cpuid_reg_check_value(u32 func, u32 index, int reg)
+{
+ switch (func) {
+ case 0x1D: return true;
+ case 0x1E: return index == 0 && reg == CPUID_EBX;
+ default: return false;
+ }
+}
+
+static bool __maybe_unused is_cpuid_subleaf_common_pattern(u32 func, u32 *index)
+{
+ switch (func) {
+ case 4:
+ case 0xB:
+ case 0x1F:
+ *index = 0;
+ return true;
+ case 0xD:
+ case 0x12:
+ if (*index >= 2) {
+ *index = 2;
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
{
u8 cpuid_overlay = get_cpuid_overlay(vcpu->kvm);
@@ -876,6 +905,14 @@ void kvm_initialize_cpu_caps(void)
BUILD_BUG_ON(sizeof(kvm_cpu_caps)/NR_CPUID_OL - (NKVMCAPINTS * sizeof(**kvm_cpu_caps)) >
sizeof(boot_cpu_data.x86_capability));
+ kvm_cpu_cap_ignore(0, 0, 0,
+ BIT(CPUID_EAX) | BIT(CPUID_EBX) | BIT(CPUID_ECX) | BIT(CPUID_EDX),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+
+ kvm_cpu_cap_init_mf(CPUID_1_EAX, GENMASK_U32(27, 16) | GENMASK_U32(13, 0),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(1, 0, 0, BIT(CPUID_EBX), F_CPUID_DEFAULT | F_CPUID_TDX);
+
kvm_cpu_cap_init(CPUID_1_ECX,
F(XMM3, F_CPUID_DEFAULT | F_CPUID_TDX),
F(PCLMULQDQ, F_CPUID_DEFAULT | F_CPUID_TDX),
@@ -946,9 +983,40 @@ void kvm_initialize_cpu_caps(void)
F(XMM, F_CPUID_DEFAULT | F_CPUID_TDX),
F(XMM2, F_CPUID_DEFAULT | F_CPUID_TDX),
F(SELFSNOOP, F_CPUID_DEFAULT | F_CPUID_TDX),
- /* HTT, TM, Reserved, PBE */
+ /* Allow userspace to set HT regardless of underlying hardware. */
+ EMULATED_F(HT, F_CPUID_DEFAULT | F_CPUID_TDX),
+ /* TM, Reserved, PBE */
+ );
+
+ /* EAX[7:0] are reserved with value 1. */
+ kvm_cpu_cap_init_mf(CPUID_2_EAX, GENMASK_U32(31, 8) | 0x01, F_CPUID_VMX | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(2, 0, 0, BIT(CPUID_EBX) | BIT(CPUID_ECX) | BIT(CPUID_EDX),
+ F_CPUID_VMX | F_CPUID_TDX);
+
+ kvm_cpu_cap_init_mf(CPUID_4_0_EAX, ~GENMASK_U32(13, 10), F_CPUID_VMX | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_4_0_EDX, GENMASK_U32(2, 0), F_CPUID_VMX | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(4, 0, -1, BIT(CPUID_EBX) | BIT(CPUID_ECX), F_CPUID_VMX | F_CPUID_TDX);
+
+ kvm_cpu_cap_init_mf(CPUID_5_EAX, GENMASK_U32(15, 0), F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_5_EBX, GENMASK_U32(15, 0), F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_5_ECX, GENMASK_U32(1, 0), F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(5, 0, 0, BIT(CPUID_EDX), F_CPUID_VMX | F_CPUID_TDX);
+
+ kvm_cpu_cap_init(CPUID_6_EAX,
+ EMULATED_F(ARAT, F_CPUID_DEFAULT | F_CPUID_TDX),
+ );
+
+ /*
+ * KVM allows userspace to set APERFMPERF after enabling
+ * KVM_X86_DISABLE_EXITS_APERFMPERF.
+ * Fixed-0 for TDX.
+ */
+ kvm_cpu_cap_init(CPUID_6_ECX,
+ F(APERFMPERF, F_CPUID_DEFAULT),
);
+ kvm_cpu_cap_ignore(7, 0, 0, BIT(CPUID_EAX), F_CPUID_DEFAULT | F_CPUID_TDX);
+
kvm_cpu_cap_init(CPUID_7_0_EBX,
F(FSGSBASE, F_CPUID_DEFAULT | F_CPUID_TDX),
EMULATED_F(TSC_ADJUST, F_CPUID_DEFAULT | F_CPUID_TDX),
@@ -1056,7 +1124,7 @@ void kvm_initialize_cpu_caps(void)
F(INTEL_STIBP, F_CPUID_DEFAULT | F_CPUID_TDX),
F(FLUSH_L1D, F_CPUID_DEFAULT | F_CPUID_TDX),
EMULATED_F(ARCH_CAPABILITIES, F_CPUID_DEFAULT | F_CPUID_TDX),
- /* CORE_CAPABILITIES */
+ F(CORE_CAPABILITIES, F_CPUID_TDX),
F(SPEC_CTRL_SSBD, F_CPUID_DEFAULT | F_CPUID_TDX),
);
@@ -1120,6 +1188,30 @@ void kvm_initialize_cpu_caps(void)
F(MCDT_NO, F_CPUID_DEFAULT | F_CPUID_TDX),
);
+ if (enable_pmu) {
+ /* KVM doesn't support PERFMON for TDX yet. */
+ kvm_cpu_cap_init_mf(CPUID_A_EAX, GENMASK_U32(31, 0), F_CPUID_VMX);
+ kvm_cpu_cap_init_mf(CPUID_A_EBX, GENMASK_U32(12, 10) | GENMASK_U32(7, 0),
+ F_CPUID_VMX);
+ kvm_cpu_cap_init_mf(CPUID_A_ECX, GENMASK_U32(31, 0), F_CPUID_VMX);
+ kvm_cpu_cap_init_mf(CPUID_A_EDX, GENMASK_U32(19, 15) | GENMASK_U32(12, 0),
+ F_CPUID_VMX);
+ }
+
+ /* CPUID 0xB is derived from CPUID.0x1F for TDX, but allow userspace to set it. */
+ kvm_cpu_cap_init_mf(CPUID_B_0_EAX, GENMASK_U32(4, 0), F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_B_0_EBX, GENMASK_U32(15, 0), F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_B_0_ECX, GENMASK_U32(15, 0), F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(0xB, 0, -1, BIT(CPUID_EDX), F_CPUID_DEFAULT | F_CPUID_TDX);
+
+
+ kvm_cpu_cap_init_mf(CPUID_D_0_EAX, (u32)kvm_caps.supported_xcr0,
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(0xD, 0, 0, BIT(CPUID_EBX) | BIT(CPUID_ECX),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_D_0_EDX, (u32)(kvm_caps.supported_xcr0 >> 32),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+
kvm_cpu_cap_init(CPUID_D_1_EAX,
F(XSAVEOPT, F_CPUID_DEFAULT | F_CPUID_TDX),
F(XSAVEC, F_CPUID_DEFAULT | F_CPUID_TDX),
@@ -1128,6 +1220,19 @@ void kvm_initialize_cpu_caps(void)
X86_64_F(XFD, F_CPUID_DEFAULT | F_CPUID_TDX),
);
+ kvm_cpu_cap_ignore(0xD, 1, 1, BIT(CPUID_EBX), F_CPUID_DEFAULT | F_CPUID_TDX);
+
+ /* No bits are defined in CPUID.D.1.EDX (i.e., the upper 32 bits of XSS) yet. */
+ kvm_cpu_cap_init_mf(CPUID_D_1_ECX, (u32)kvm_caps.supported_xss,
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+
+ if ((kvm_caps.supported_xss | kvm_caps.supported_xcr0) & GENMASK_U64(62, 2)) {
+ kvm_cpu_cap_ignore(0xD, 2, 62, BIT(CPUID_EAX) | BIT(CPUID_EBX),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_D_2_ECX, GENMASK_U32(2, 0),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+ }
+
/* SGX related features are fixed-0 for TDX */
kvm_cpu_cap_init(CPUID_12_EAX,
SCATTERED_F(SGX1, F_CPUID_DEFAULT),
@@ -1135,6 +1240,40 @@ void kvm_initialize_cpu_caps(void)
SCATTERED_F(SGX_EDECCSSA, F_CPUID_DEFAULT),
);
+ if (kvm_cpu_cap_has(NULL, X86_FEATURE_SGX)) {
+ kvm_cpu_cap_check_and_init_mf(CPUID_12_0_EBX, SGX_MISC_EXINFO, F_CPUID_DEFAULT);
+ kvm_cpu_cap_init_mf(CPUID_12_0_EDX, GENMASK_U32(15, 0), F_CPUID_DEFAULT);
+
+ kvm_cpu_cap_check_and_init_mf(CPUID_12_1_EAX,
+ SGX_ATTR_PRIV_MASK | SGX_ATTR_UNPRIV_MASK,
+ F_CPUID_DEFAULT);
+ kvm_cpu_cap_init_mf(CPUID_12_1_ECX, (u32)kvm_caps.supported_xcr0, F_CPUID_DEFAULT);
+ kvm_cpu_cap_init_mf(CPUID_12_1_EDX, (u32)(kvm_caps.supported_xcr0 >> 32),
+ F_CPUID_DEFAULT);
+
+ /*
+ * SUB_LEAF_TYPE (EAX[3:0]) is valid only when it is 1. The
+ * masks are initialized according to type 1.
+ */
+ kvm_cpu_cap_init_mf(CPUID_12_2_EAX, GENMASK_U32(31, 12) | 0x1, F_CPUID_DEFAULT);
+ kvm_cpu_cap_init_mf(CPUID_12_2_EBX, GENMASK_U32(19, 0), F_CPUID_DEFAULT);
+ kvm_cpu_cap_init_mf(CPUID_12_2_ECX, ~GENMASK_U32(11, 4), F_CPUID_DEFAULT);
+ kvm_cpu_cap_init_mf(CPUID_12_2_EDX, GENMASK_U32(19, 0), F_CPUID_DEFAULT);
+ }
+
+ /* Hardcoded with fixed values in Intel SDM. */
+ if (kvm_cpu_cap_has(NULL, X86_FEATURE_AMX_TILE)) {
+ kvm_cpu_cap_init_mf(CPUID_1D_0_EAX, 0x00000001, F_CPUID_DEFAULT | F_CPUID_TDX);
+
+ kvm_cpu_cap_init_mf(CPUID_1D_1_EAX, 0x04002000, F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_1D_1_EBX, 0x00080040, F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_1D_1_ECX, 0x00000010, F_CPUID_DEFAULT | F_CPUID_TDX);
+
+ /* KVM limits the subleaf up to 1. */
+ kvm_cpu_cap_init_mf(CPUID_1E_0_EAX, 0x00000001, F_CPUID_DEFAULT | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_1E_0_EBX, 0x00004010, F_CPUID_DEFAULT | F_CPUID_TDX);
+ }
+
kvm_cpu_cap_init(CPUID_1E_1_EAX,
F(AMX_INT8_ALIAS, F_CPUID_DEFAULT | F_CPUID_TDX),
F(AMX_BF16_ALIAS, F_CPUID_DEFAULT | F_CPUID_TDX),
@@ -1146,11 +1285,25 @@ void kvm_initialize_cpu_caps(void)
F(AMX_MOVRS, F_CPUID_DEFAULT | F_CPUID_TDX),
);
- kvm_cpu_cap_init(CPUID_24_0_EBX,
- F(AVX10_128, F_CPUID_DEFAULT | F_CPUID_TDX),
- F(AVX10_256, F_CPUID_DEFAULT | F_CPUID_TDX),
- F(AVX10_512, F_CPUID_DEFAULT | F_CPUID_TDX),
- );
+ kvm_cpu_cap_init_mf(CPUID_1F_0_EAX, GENMASK_U32(4, 0), F_CPUID_VMX | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_1F_0_EBX, GENMASK_U32(15, 0), F_CPUID_VMX | F_CPUID_TDX);
+ kvm_cpu_cap_init_mf(CPUID_1F_0_ECX, GENMASK_U32(15, 0), F_CPUID_VMX | F_CPUID_TDX);
+ kvm_cpu_cap_ignore(0x1F, 0, -1, BIT(CPUID_EDX), F_CPUID_VMX | F_CPUID_TDX);
+
+ if (kvm_cpu_cap_has(NULL, X86_FEATURE_AVX10)) {
+ /* KVM supports up to subleaf 1 */
+ kvm_cpu_cap_init_mf(CPUID_24_0_EAX, 0x00000001, F_CPUID_DEFAULT | F_CPUID_TDX);
+ /*
+ * The allowed value for AVX10 version is 1 or 2. The version is
+ * guaranteed to be >=1 if AVX10 is supported, and KVM supports
+ * up to version 2. For simplicity, just allow lower 2 bits to
+ * be set by userspace.
+ * EBX[18:16] is reserved at 111b for all vector widths, i.e.,
+ * AVX10_128, AVX10_256, and AVX10_512.
+ */
+ kvm_cpu_cap_init_mf(CPUID_24_0_EBX, GENMASK_U32(18, 16) | GENMASK_U32(1, 0),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+ }
kvm_cpu_cap_init(CPUID_24_1_ECX,
/* AVX10_VNNI_INT is reserved in TDX spec */
@@ -1501,6 +1654,11 @@ static inline int __do_cpuid_func(struct kvm *kvm, struct kvm_cpuid_array *array
break;
case 1:
cpuid_entry_override(kvm, entry, CPUID_1_EDX);
+ /*
+ * Clear HT when reporting to userspace since it's not emulated
+ * by KVM.
+ */
+ entry->edx &= ~feature_bit(HT);
cpuid_entry_override(kvm, entry, CPUID_1_ECX);
break;
case 2:
@@ -1535,7 +1693,7 @@ static inline int __do_cpuid_func(struct kvm *kvm, struct kvm_cpuid_array *array
}
break;
case 6: /* Thermal management */
- entry->eax = 0x4; /* allow ARAT */
+ cpuid_entry_override(kvm, entry, CPUID_6_EAX);
entry->ebx = 0;
entry->ecx = 0;
entry->edx = 0;
@@ -1674,7 +1832,7 @@ static inline int __do_cpuid_func(struct kvm *kvm, struct kvm_cpuid_array *array
* feature flags), while enclave size is unrestricted.
*/
cpuid_entry_override(kvm, entry, CPUID_12_EAX);
- entry->ebx &= SGX_MISC_EXINFO;
+ cpuid_entry_override(kvm, entry, CPUID_12_0_EBX);
entry = do_host_cpuid(array, function, 1);
if (!entry)
@@ -1687,7 +1845,7 @@ static inline int __do_cpuid_func(struct kvm *kvm, struct kvm_cpuid_array *array
* userspace. ATTRIBUTES.XFRM is not adjusted as userspace is
* expected to derive it from supported XCR0.
*/
- entry->eax &= SGX_ATTR_PRIV_MASK | SGX_ATTR_UNPRIV_MASK;
+ cpuid_entry_override(kvm, entry, CPUID_12_1_EAX);
entry->ebx &= 0;
break;
/* Intel PT */
@@ -1697,6 +1855,9 @@ static inline int __do_cpuid_func(struct kvm *kvm, struct kvm_cpuid_array *array
break;
}
+ cpuid_entry_override(kvm, entry, CPUID_14_0_EBX);
+ cpuid_entry_override(kvm, entry, CPUID_14_0_ECX);
+
for (i = 1, max_idx = entry->eax; i <= max_idx; ++i) {
if (!do_host_cpuid(array, function, i))
goto out;
@@ -1750,6 +1911,7 @@ static inline int __do_cpuid_func(struct kvm *kvm, struct kvm_cpuid_array *array
*/
avx10_version = min_t(u8, entry->ebx & 0xff, 2);
cpuid_entry_override(kvm, entry, CPUID_24_0_EBX);
+ entry->ebx &= ~GENMASK_U32(7, 0);
entry->ebx |= avx10_version;
entry->ecx = 0;
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index 657f5f743ed9..5c7c0fbb0fec 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -76,6 +76,9 @@
#define KVM_X86_FEATURE_TSA_SQ_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 1)
#define KVM_X86_FEATURE_TSA_L1_NO KVM_X86_FEATURE(CPUID_8000_0021_ECX, 2)
+/* CPUID level 0x6 (ECX) */
+#define KVM_X86_FEATURE_APERFMPERF KVM_X86_FEATURE(CPUID_6_ECX, 0)
+
struct cpuid_reg {
u32 function;
u32 index;
@@ -109,6 +112,49 @@ static const struct cpuid_reg reverse_cpuid[] = {
[CPUID_7_1_ECX] = { 7, 1, CPUID_ECX},
[CPUID_1E_1_EAX] = { 0x1e, 1, CPUID_EAX},
[CPUID_24_1_ECX] = { 0x24, 1, CPUID_ECX},
+ [CPUID_1_EAX] = { 1, 0, CPUID_EAX},
+ [CPUID_2_EAX] = { 2, 0, CPUID_EAX},
+ [CPUID_4_0_EAX] = { 4, 0, CPUID_EAX},
+ [CPUID_4_0_EDX] = { 4, 0, CPUID_EDX},
+ [CPUID_5_EAX] = { 5, 0, CPUID_EAX},
+ [CPUID_5_EBX] = { 5, 0, CPUID_EBX},
+ [CPUID_5_ECX] = { 5, 0, CPUID_ECX},
+ [CPUID_6_ECX] = { 6, 0, CPUID_ECX},
+ [CPUID_A_EAX] = { 0xa, 0, CPUID_EAX},
+ [CPUID_A_EBX] = { 0xa, 0, CPUID_EBX},
+ [CPUID_A_ECX] = { 0xa, 0, CPUID_ECX},
+ [CPUID_A_EDX] = { 0xa, 0, CPUID_EDX},
+ [CPUID_B_0_EAX] = { 0xb, 0, CPUID_EAX},
+ [CPUID_B_0_EBX] = { 0xb, 0, CPUID_EBX},
+ [CPUID_B_0_ECX] = { 0xb, 0, CPUID_ECX},
+ [CPUID_D_0_EAX] = { 0xd, 0, CPUID_EAX},
+ [CPUID_D_0_EDX] = { 0xd, 0, CPUID_EDX},
+ [CPUID_D_1_ECX] = { 0xd, 1, CPUID_ECX},
+ [CPUID_D_2_ECX] = { 0xd, 2, CPUID_ECX},
+ [CPUID_12_0_EBX] = { 0x12, 0, CPUID_EBX},
+ [CPUID_12_0_EDX] = { 0x12, 0, CPUID_EDX},
+ [CPUID_12_1_EAX] = { 0x12, 1, CPUID_EAX},
+ [CPUID_12_1_ECX] = { 0x12, 1, CPUID_ECX},
+ [CPUID_12_1_EDX] = { 0x12, 1, CPUID_EDX},
+ [CPUID_12_2_EAX] = { 0x12, 2, CPUID_EAX},
+ [CPUID_12_2_EBX] = { 0x12, 2, CPUID_EBX},
+ [CPUID_12_2_ECX] = { 0x12, 2, CPUID_ECX},
+ [CPUID_12_2_EDX] = { 0x12, 2, CPUID_EDX},
+ [CPUID_14_0_EAX] = { 0x14, 0, CPUID_EAX},
+ [CPUID_14_0_EBX] = { 0x14, 0, CPUID_EBX},
+ [CPUID_14_0_ECX] = { 0x14, 0, CPUID_ECX},
+ [CPUID_14_1_EAX] = { 0x14, 1, CPUID_EAX},
+ [CPUID_14_1_EBX] = { 0x14, 1, CPUID_EBX},
+ [CPUID_1D_0_EAX] = { 0x1d, 0, CPUID_EAX},
+ [CPUID_1D_1_EAX] = { 0x1d, 1, CPUID_EAX},
+ [CPUID_1D_1_EBX] = { 0x1d, 1, CPUID_EBX},
+ [CPUID_1D_1_ECX] = { 0x1d, 1, CPUID_ECX},
+ [CPUID_1E_0_EAX] = { 0x1e, 0, CPUID_EAX},
+ [CPUID_1E_0_EBX] = { 0x1e, 0, CPUID_EBX},
+ [CPUID_1F_0_EAX] = { 0x1f, 0, CPUID_EAX},
+ [CPUID_1F_0_EBX] = { 0x1f, 0, CPUID_EBX},
+ [CPUID_1F_0_ECX] = { 0x1f, 0, CPUID_ECX},
+ [CPUID_24_0_EAX] = { 0x24, 0, CPUID_EAX},
};
/*
@@ -151,6 +197,7 @@ static __always_inline u32 __feature_translate(int x86_feature)
KVM_X86_TRANSLATE_FEATURE(TSA_SQ_NO);
KVM_X86_TRANSLATE_FEATURE(TSA_L1_NO);
KVM_X86_TRANSLATE_FEATURE(MSR_IMM);
+ KVM_X86_TRANSLATE_FEATURE(APERFMPERF);
default:
return x86_feature;
}
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 1e47c194af53..a1df89d66a84 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -2141,7 +2141,7 @@ bool tdx_has_emulated_msr(u32 index)
static bool tdx_is_read_only_msr(u32 index)
{
return index == MSR_IA32_APICBASE || index == MSR_EFER ||
- index == MSR_IA32_FEAT_CTL;
+ index == MSR_IA32_FEAT_CTL || index == MSR_IA32_CORE_CAPS;
}
int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
@@ -2161,6 +2161,14 @@ int tdx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
return 1;
msr->data = 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 = 0;
+ return 0;
default:
if (!tdx_has_emulated_msr(msr->index))
return 1;
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index f772558758f7..17c9048c87f3 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -8099,6 +8099,20 @@ static __init void vmx_set_cpu_caps(void)
if (vmx_pt_mode_is_host_guest())
kvm_cpu_cap_check_and_set(X86_FEATURE_INTEL_PT, F_CPUID_VMX);
+ if (kvm_cpu_cap_has(NULL, X86_FEATURE_INTEL_PT)) {
+ kvm_cpu_cap_init_mf(CPUID_14_0_EAX, GENMASK_U32(31, 0), F_CPUID_VMX);
+ /* Lower 9 bits are defined, however, bit 6 is not supported in intel pt_caps[] */
+ kvm_cpu_cap_check_and_init_mf(CPUID_14_0_EBX,
+ GENMASK_U32(8, 7) | GENMASK_U32(5, 0),
+ F_CPUID_VMX);
+ kvm_cpu_cap_check_and_init_mf(CPUID_14_0_ECX,
+ BIT(31) | GENMASK_U32(3, 0),
+ F_CPUID_VMX);
+
+ kvm_cpu_cap_init_mf(CPUID_14_1_EAX, ~GENMASK_U32(15, 3), F_CPUID_VMX);
+ kvm_cpu_cap_init_mf(CPUID_14_1_EBX, GENMASK_U32(31, 0), F_CPUID_VMX);
+ }
+
/* DS and DTES64 are fixed-1 for TDX */
enable_mask = vmx_pebs_supported() ? F_CPUID_TDX | F_CPUID_VMX : F_CPUID_TDX;
kvm_cpu_cap_check_and_set(X86_FEATURE_DS, enable_mask);
--
2.46.0
next prev parent reply other threads:[~2026-04-17 7:32 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-17 7:35 [RFC PATCH 00/27] KVM: x86: Add a paranoid mode for CPUID verification Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 01/27] KVM: x86: Fix emulated CPUID features being applied to wrong sub-leaf Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 02/27] KVM: x86: Reorder the features for CPUID 7 Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 03/27] KVM: x86: Add definitions for CPUID overlays Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 04/27] KVM: x86: Extend F() and its variants " Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 05/27] KVM: x86: Extend kvm_cpu_cap_{set/clear}() to configure overlays Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 06/27] KVM: x86: Populate TDX CPUID overlay with supported feature bits Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 07/27] KVM: x86: Support KVM_GET_{SUPPORTED,EMULATED}_CPUID as VM scope ioctls Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 08/27] KVM: x86: Thread @kvm to KVM CPU capability helpers Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 09/27] KVM: x86: Use overlays of KVM CPU capabilities Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 10/27] KVM: x86: Use vendor-specific overlay flags instead of F_CPUID_DEFAULT Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 11/27] KVM: SVM: Drop unnecessary clears of unsupported common x86 features Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 12/27] KVM: x86: Split KVM CPU cap leafs into two parts Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 13/27] KVM: x86: Add a helper to initialize CPUID multi-bit fields Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 14/27] KVM: x86: Add a helper to init multiple feature bits based on raw CPUID Binbin Wu
2026-04-17 7:35 ` [RFC PATCH 15/27] KVM: x86: Add infrastructure to track CPUID entries ignored in paranoid mode Binbin Wu
2026-04-17 7:35 ` Binbin Wu [this message]
2026-04-17 7:36 ` [RFC PATCH 17/27] KVM: x86: Init allowed masks for extended CPUID range " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 18/27] KVM: x86: Handle Centaur CPUID leafs " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 19/27] KVM: x86: Track KVM PV CPUID features for " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 20/27] KVM: x86: Add per-VM flag to track CPUID " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 21/27] KVM: x86: Make kvm_vcpu_after_set_cpuid() return an error code Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 22/27] KVM: x86: Verify userspace CPUID inputs in paranoid mode Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 23/27] KVM: x86: Account for runtime CPUID features " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 24/27] KVM: x86: Skip paranoid CPUID check for KVM PV leafs when base is relocated Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 25/27] KVM: x86: Add new KVM_CAP_X86_CPUID_PARANOID Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 26/27] KVM: x86: Add a helper to query the allowed CPUID mask Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 27/27] KVM: TDX: Replace hardcoded CPUID filtering with the allowed mask 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=20260417073610.3246316-17-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=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