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 19/27] KVM: x86: Track KVM PV CPUID features for paranoid mode
Date: Fri, 17 Apr 2026 15:36:02 +0800 [thread overview]
Message-ID: <20260417073610.3246316-20-binbin.wu@linux.intel.com> (raw)
In-Reply-To: <20260417073610.3246316-1-binbin.wu@linux.intel.com>
Track KVM's PV CPUID features to the kvm_cpu_caps so that they can be
covered by paranoid CPUID verification.
Define KVM_PV_FEATURE_* constants in reverse_cpuid.h, mirroring the UAPI
KVM_FEATURE_* bit positions, and add a new PV_F() macro to initialize PV
features within kvm_cpu_cap_init() for the new added CPUID_4000_0001_EAX.
PV_F() marks it as emulated, since PV features are entirely software
defined. Also, teach raw_cpuid_get() to return 0 for the
KVM_CPUID_SIGNATURE base without WARNing, as PV features have no hardware
backing and querying raw CPUID for them is expected to be a no-op.
Note KVM PV CPUID base could be relocated to resolve the conflict with
other virtualization enhancements (e.g., HyperV is also enabled by
userspace), the KVM PV CPUID verification in CPUID paranoid mode will be
skipped in this case in a future patch.
Ignore EAX and EBX of leaf 0x40000010 (tsc_khz and apic_bus_freq), which
are allowed multi-bit fields.
Signed-off-by: Binbin Wu <binbin.wu@linux.intel.com>
---
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/cpuid.c | 41 +++++++++++++++++++++++++++++++++
arch/x86/kvm/cpuid.h | 3 ++-
arch/x86/kvm/reverse_cpuid.h | 22 ++++++++++++++++++
4 files changed, 66 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 2ec4d92e3e79..f6d79e8496c3 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -850,6 +850,7 @@ enum kvm_only_cpuid_leafs {
CPUID_8000_001F_EBX,
CPUID_8000_0021_EBX,
CPUID_8000_0022_EBX,
+ CPUID_4000_0001_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 c75e7859cc2c..789ec9eb7aaf 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -887,6 +887,18 @@ do { \
KVM_VALIDATE_CPU_CAP_USAGE(name); \
})
+#define PV_F(name, overlay_mask) \
+({ \
+ BUILD_BUG_ON(__feature_leaf(KVM_PV_FEATURE_##name) != CPUID_4000_0001_EAX); \
+ BUILD_BUG_ON(kvm_cpu_cap_init_in_progress != CPUID_4000_0001_EAX); \
+ \
+ kvm_cpu_cap_emulated |= pv_feature_bit(name); \
+ for (int i = 0; i < NR_CPUID_OL; i++) { \
+ if ((overlay_mask) & BIT(i)) \
+ kvm_cpu_caps[i][CPUID_4000_0001_EAX] |= pv_feature_bit(name); \
+ } \
+})
+
/*
* Undefine the MSR bit macro to avoid token concatenation issues when
* processing X86_FEATURE_SPEC_CTRL_SSBD.
@@ -1586,6 +1598,35 @@ void kvm_initialize_cpu_caps(void)
kvm_cpu_cap_clear(X86_FEATURE_RDTSCP, F_CPUID_DEFAULT);
kvm_cpu_cap_clear(X86_FEATURE_RDPID, F_CPUID_DEFAULT);
}
+
+ kvm_cpu_cap_ignore(KVM_CPUID_SIGNATURE, 0, 0,
+ BIT(CPUID_EAX) | BIT(CPUID_EBX) | BIT(CPUID_ECX) | BIT(CPUID_EDX),
+ F_CPUID_DEFAULT | F_CPUID_TDX);
+
+ kvm_cpu_cap_init(CPUID_4000_0001_EAX,
+ PV_F(CLOCKSOURCE, F_CPUID_DEFAULT),
+ PV_F(NOP_IO_DELAY, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(CLOCKSOURCE2, F_CPUID_DEFAULT),
+ PV_F(ASYNC_PF, F_CPUID_DEFAULT),
+ PV_F(PV_EOI, F_CPUID_DEFAULT),
+ PV_F(PV_UNHALT, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(PV_TLB_FLUSH, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(ASYNC_PF_VMEXIT, F_CPUID_DEFAULT),
+ PV_F(PV_SEND_IPI, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(POLL_CONTROL, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(PV_SCHED_YIELD, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(ASYNC_PF_INT, F_CPUID_DEFAULT),
+ PV_F(MSI_EXT_DEST_ID, F_CPUID_DEFAULT | F_CPUID_TDX),
+ PV_F(HC_MAP_GPA_RANGE, F_CPUID_DEFAULT),
+ PV_F(MIGRATION_CONTROL, F_CPUID_DEFAULT),
+ PV_F(CLOCKSOURCE_STABLE_BIT, F_CPUID_DEFAULT),
+ );
+
+ if (sched_info_on())
+ kvm_cpu_cap_set(KVM_PV_FEATURE_STEAL_TIME, F_CPUID_DEFAULT);
+
+ kvm_cpu_cap_ignore(KVM_CPUID_SIGNATURE | 0x10, 0, 0,
+ BIT(CPUID_EAX) | BIT(CPUID_EBX), F_CPUID_DEFAULT | F_CPUID_TDX);
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_initialize_cpu_caps);
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 0b90344a8b98..535377e519b5 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -270,7 +270,8 @@ static __always_inline u32 raw_cpuid_get(struct cpuid_reg cpuid)
* defined, as this and other code would need to be updated.
*/
base = cpuid.function & 0xffff0000;
- if (WARN_ON_ONCE(base && base != 0x80000000 && base != 0xc0000000))
+ if (base == KVM_CPUID_SIGNATURE ||
+ WARN_ON_ONCE(base && base != 0x80000000 && base != 0xc0000000))
return 0;
if (cpuid_eax(base) < cpuid.function)
diff --git a/arch/x86/kvm/reverse_cpuid.h b/arch/x86/kvm/reverse_cpuid.h
index 1bdb05aaa852..03a88ab3585d 100644
--- a/arch/x86/kvm/reverse_cpuid.h
+++ b/arch/x86/kvm/reverse_cpuid.h
@@ -79,6 +79,26 @@
/* CPUID level 0x6 (ECX) */
#define KVM_X86_FEATURE_APERFMPERF KVM_X86_FEATURE(CPUID_6_ECX, 0)
+/* CPUID level 0x40000001 (EAX) */
+#define KVM_PV_FEATURE_CLOCKSOURCE KVM_X86_FEATURE(CPUID_4000_0001_EAX, 0)
+#define KVM_PV_FEATURE_NOP_IO_DELAY KVM_X86_FEATURE(CPUID_4000_0001_EAX, 1)
+#define KVM_PV_FEATURE_MMU_OP KVM_X86_FEATURE(CPUID_4000_0001_EAX, 2)
+#define KVM_PV_FEATURE_CLOCKSOURCE2 KVM_X86_FEATURE(CPUID_4000_0001_EAX, 3)
+#define KVM_PV_FEATURE_ASYNC_PF KVM_X86_FEATURE(CPUID_4000_0001_EAX, 4)
+#define KVM_PV_FEATURE_STEAL_TIME KVM_X86_FEATURE(CPUID_4000_0001_EAX, 5)
+#define KVM_PV_FEATURE_PV_EOI KVM_X86_FEATURE(CPUID_4000_0001_EAX, 6)
+#define KVM_PV_FEATURE_PV_UNHALT KVM_X86_FEATURE(CPUID_4000_0001_EAX, 7)
+#define KVM_PV_FEATURE_PV_TLB_FLUSH KVM_X86_FEATURE(CPUID_4000_0001_EAX, 9)
+#define KVM_PV_FEATURE_ASYNC_PF_VMEXIT KVM_X86_FEATURE(CPUID_4000_0001_EAX, 10)
+#define KVM_PV_FEATURE_PV_SEND_IPI KVM_X86_FEATURE(CPUID_4000_0001_EAX, 11)
+#define KVM_PV_FEATURE_POLL_CONTROL KVM_X86_FEATURE(CPUID_4000_0001_EAX, 12)
+#define KVM_PV_FEATURE_PV_SCHED_YIELD KVM_X86_FEATURE(CPUID_4000_0001_EAX, 13)
+#define KVM_PV_FEATURE_ASYNC_PF_INT KVM_X86_FEATURE(CPUID_4000_0001_EAX, 14)
+#define KVM_PV_FEATURE_MSI_EXT_DEST_ID KVM_X86_FEATURE(CPUID_4000_0001_EAX, 15)
+#define KVM_PV_FEATURE_HC_MAP_GPA_RANGE KVM_X86_FEATURE(CPUID_4000_0001_EAX, 16)
+#define KVM_PV_FEATURE_MIGRATION_CONTROL KVM_X86_FEATURE(CPUID_4000_0001_EAX, 17)
+#define KVM_PV_FEATURE_CLOCKSOURCE_STABLE_BIT KVM_X86_FEATURE(CPUID_4000_0001_EAX, 24)
+
struct cpuid_reg {
u32 function;
u32 index;
@@ -168,6 +188,7 @@ static const struct cpuid_reg reverse_cpuid[] = {
[CPUID_8000_001F_EBX] = {0x8000001f, 0, CPUID_EBX},
[CPUID_8000_0021_EBX] = {0x80000021, 0, CPUID_EBX},
[CPUID_8000_0022_EBX] = {0x80000022, 0, CPUID_EBX},
+ [CPUID_4000_0001_EAX] = {0x40000001, 0, CPUID_EAX},
};
/*
@@ -239,6 +260,7 @@ static __always_inline u32 __feature_bit(int x86_feature)
}
#define feature_bit(name) __feature_bit(X86_FEATURE_##name)
+#define pv_feature_bit(name) __feature_bit(KVM_PV_FEATURE_##name)
static __always_inline struct cpuid_reg x86_feature_cpuid(unsigned int x86_feature)
{
--
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 ` [RFC PATCH 16/27] KVM: x86: Init allowed masks for basic CPUID range " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 17/27] KVM: x86: Init allowed masks for extended " Binbin Wu
2026-04-17 7:36 ` [RFC PATCH 18/27] KVM: x86: Handle Centaur CPUID leafs " Binbin Wu
2026-04-17 7:36 ` Binbin Wu [this message]
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-20-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