On 1/18/2026 7:30 PM, Mi, Dapeng wrote:
>
> On 1/17/2026 9:10 AM, Zide Chen wrote:
>> Populate selected PEBS feature names in FEAT_PERF_CAPABILITIES to make
>> the corresponding bits user-visible CPU feature knobs, allowing them to
>> be explicitly enabled or disabled via -cpu +/-<feature>.
>>
>> Once named, these bits become part of the guest CPU configuration
>> contract. If a VM is configured with such a feature enabled, migration
>> to a destination that does not support the feature may fail, as the
>> destination cannot honor the guest-visible CPU model.
>>
>> The PEBS_FMT bits are intentionally not exposed. They are not meaningful
>> as user-visible features, and QEMU registers CPU features as boolean
>> QOM properties, which makes them unsuitable for representing and
>> checking numeric capabilities.
>
> Currently KVM supports user space sets PEBS_FMT (see vmx_set_msr()), but
> just requires the guest PEBS_FMT is identical with host PEBS_FMT.
My mistake — this is indeed problematic.
There are four possible ways to expose pebs_fmt to the guest when
cpu->migratable = true:
1. Add a pebs_fmt option similar to lbr_fmt.
This may work, but is not user-friendly and adds unnecessary complexity.
2. Set feat_names[8] = feat_names[9] = ... = "pebs-fmt".
This violates the implicit rule that feat_names[] entries should be
unique, and target/i386 does not support numeric features.
3. Use feat_names[8..11] = "pebs-fmt[1/2/3/4]".
This has two issues:
- It exposes pebs-fmt[1/2/3/4] as independent features, which is
semantically incorrect.
- Migration may fail incorrectly; e.g., migrating from pebs_fmt=2 to a
more capable host (pebs_fmt=4) would be reported as missing pebs-fmt2.
Given this, I propose the below changes. This may allow migration to a
less capable destination, which is not ideal, but it avoids false
“missing feature” bug and preserves the expectation that ensuring
destination compatibility is the responsibility of the management
application or the user.
BTW, I am not proposing a generic “x86 CPU numeric feature” mechanism at
this time, as it is unclear whether lbr_fmt and pebs_fmt alone justify
such a change.
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 015ba3fc9c7b..b6c95d5ceb31 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -1629,6 +1629,7 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
.msr = {
.index = MSR_IA32_PERF_CAPABILITIES,
},
+ .migratable_flags = PERF_CAP_PEBS_FMT,
},
[FEAT_VMX_PROCBASED_CTLS] = {
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 1666eff65300..de4074d6baa7 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -421,6 +421,7 @@ typedef enum X86Seg {
#define MSR_IA32_PERF_CAPABILITIES 0x345
#define PERF_CAP_LBR_FMT 0x3f
+#define PERF_CAP_PEBS_FMT 0xf00
#define PERF_CAP_FULL_WRITE (1U << 13)
#define PERF_CAP_PEBS_BASELINE (1U << 14)
> IIRC, many places in KVM judges whether guest PEBS is enabled by checking
> the guest PEBS_FMT. If we don't expose PEBS_FMT to user space, how does KVM
> get the guest PEBS_FMT?
>
>
>>
>> Co-developed-by: Dapeng Mi <[email protected]>
>> Signed-off-by: Dapeng Mi <[email protected]>
>> Signed-off-by: Zide Chen <[email protected]>
>> ---
>> target/i386/cpu.c | 6 +++---
>> 1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/target/i386/cpu.c b/target/i386/cpu.c
>> index f1ac98970d3e..fc6a64287415 100644
>> --- a/target/i386/cpu.c
>> +++ b/target/i386/cpu.c
>> @@ -1618,10 +1618,10 @@ FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
>> .type = MSR_FEATURE_WORD,
>> .feat_names = {
>> NULL, NULL, NULL, NULL,
>> + NULL, NULL, "pebs-trap", "pebs-arch-reg"
>> NULL, NULL, NULL, NULL,
>> - NULL, NULL, NULL, NULL,
>> - NULL, "full-width-write", NULL, NULL,
>> - NULL, NULL, NULL, NULL,
>> + NULL, "full-width-write", "pebs-baseline", NULL,
>> + NULL, "pebs-timing-info", NULL, NULL,
>> NULL, NULL, NULL, NULL,
>> NULL, NULL, NULL, NULL,
>> NULL, NULL, NULL, NULL,