Reviewed-by: Dapeng Mi <[email protected]>

On 3/5/2026 2:07 AM, Zide Chen wrote:
> From: Dapeng Mi <[email protected]>
>
> The legacy DS-based PEBS relies on IA32_DS_AREA and IA32_PEBS_ENABLE
> to take snapshots of a subset of the machine registers into the Intel
> Debug-Store.
>
> Adaptive PEBS introduces MSR_PEBS_DATA_CFG to be able to capture only
> the data of interest, which is enumerated via bit 14 (PEBS_BASELINE)
> of IA32_PERF_CAPABILITIES.
>
> QEMU must save, restore and migrate these MSRs when legacy PEBS is
> enabled.  Though the availability of these MSRs may not be the same,
> it's still valid to put them in the same vmstate subsection for
> implementation simplicity.
>
> Originally-by: Luwei Kang <[email protected]>
> Signed-off-by: Dapeng Mi <[email protected]>
> Co-developed-by: Zide Chen <[email protected]>
> Signed-off-by: Zide Chen <[email protected]>
> ---
> V3:
> - Add the missing Originally-by tag to credit Luwei.
> - Fix the vmstate name of msr_ds_pebs.
> - Fix the criteria for determining availability of IA32_PEBS_ENABLE
>   and MSR_PEBS_DATA_CFG.
> - Change title to cover all aspects of what this patch does.
> - Re-work the commit messages.
> ---
>  target/i386/cpu.h     | 10 ++++++++++
>  target/i386/kvm/kvm.c | 29 +++++++++++++++++++++++++++++
>  target/i386/machine.c | 27 ++++++++++++++++++++++++++-
>  3 files changed, 65 insertions(+), 1 deletion(-)
>
> diff --git a/target/i386/cpu.h b/target/i386/cpu.h
> index 7c241a20420c..3a10f3242329 100644
> --- a/target/i386/cpu.h
> +++ b/target/i386/cpu.h
> @@ -422,6 +422,7 @@ typedef enum X86Seg {
>  #define MSR_IA32_PERF_CAPABILITIES      0x345
>  #define PERF_CAP_LBR_FMT                0x3f
>  #define PERF_CAP_FULL_WRITE             (1U << 13)
> +#define PERF_CAP_PEBS_BASELINE          (1U << 14)
>  
>  #define MSR_IA32_TSX_CTRL            0x122
>  #define MSR_IA32_TSCDEADLINE            0x6e0
> @@ -479,6 +480,7 @@ typedef enum X86Seg {
>  /* Indicates good rep/movs microcode on some processors: */
>  #define MSR_IA32_MISC_ENABLE_FASTSTRING    (1ULL << 0)
>  #define MSR_IA32_MISC_ENABLE_BTS_UNAVAIL   (1ULL << 11)
> +#define MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL  (1ULL << 12)
>  #define MSR_IA32_MISC_ENABLE_MWAIT      (1ULL << 18)
>  #define MSR_IA32_MISC_ENABLE_DEFAULT    (MSR_IA32_MISC_ENABLE_FASTSTRING     
> | \
>                                           MSR_IA32_MISC_ENABLE_BTS_UNAVAIL)
> @@ -514,6 +516,11 @@ typedef enum X86Seg {
>  #define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS       0xc0000300
>  #define MSR_AMD64_PERF_CNTR_GLOBAL_CTL          0xc0000301
>  
> +/* Legacy DS based PEBS MSRs */
> +#define MSR_IA32_PEBS_ENABLE            0x3f1
> +#define MSR_PEBS_DATA_CFG               0x3f2
> +#define MSR_IA32_DS_AREA                0x600
> +
>  #define MSR_K7_EVNTSEL0                 0xc0010000
>  #define MSR_K7_PERFCTR0                 0xc0010004
>  #define MSR_F15H_PERF_CTL0              0xc0010200
> @@ -2099,6 +2106,9 @@ typedef struct CPUArchState {
>      uint64_t msr_fixed_ctr_ctrl;
>      uint64_t msr_global_ctrl;
>      uint64_t msr_global_status;
> +    uint64_t msr_ds_area;
> +    uint64_t msr_pebs_data_cfg;
> +    uint64_t msr_pebs_enable;
>      uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS];
>      uint64_t msr_gp_counters[MAX_GP_COUNTERS];
>      uint64_t msr_gp_evtsel[MAX_GP_COUNTERS];
> diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
> index 4ba54151320f..8c4564bcbb9e 100644
> --- a/target/i386/kvm/kvm.c
> +++ b/target/i386/kvm/kvm.c
> @@ -4280,6 +4280,16 @@ static int kvm_put_msrs(X86CPU *cpu, KvmPutState level)
>                  kvm_msr_entry_add(cpu, MSR_CORE_PERF_GLOBAL_CTRL, 0);
>              }
>  
> +            if (env->features[FEAT_1_EDX] & CPUID_DTS) {
> +                kvm_msr_entry_add(cpu, MSR_IA32_DS_AREA, env->msr_ds_area);
> +            }
> +            if (!(env->msr_ia32_misc_enable & 
> MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL)) {
> +                kvm_msr_entry_add(cpu, MSR_IA32_PEBS_ENABLE, 
> env->msr_pebs_enable);
> +            }
> +            if (env->features[FEAT_PERF_CAPABILITIES] & 
> PERF_CAP_PEBS_BASELINE) {
> +                kvm_msr_entry_add(cpu, MSR_PEBS_DATA_CFG, 
> env->msr_pebs_data_cfg);
> +            }
> +
>              /* Set the counter values.  */
>              for (i = 0; i < num_pmu_fixed_counters; i++) {
>                  kvm_msr_entry_add(cpu, MSR_CORE_PERF_FIXED_CTR0 + i,
> @@ -4900,6 +4910,16 @@ static int kvm_get_msrs(X86CPU *cpu)
>              kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_CTL, 0);
>              kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, 0);
>          }
> +
> +        if (env->features[FEAT_1_EDX] & CPUID_DTS) {
> +            kvm_msr_entry_add(cpu, MSR_IA32_DS_AREA, 0);
> +        }
> +        if (!(env->msr_ia32_misc_enable & 
> MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL)) {
> +            kvm_msr_entry_add(cpu, MSR_IA32_PEBS_ENABLE, 0);
> +        }
> +        if (env->features[FEAT_PERF_CAPABILITIES] & PERF_CAP_PEBS_BASELINE) {
> +            kvm_msr_entry_add(cpu, MSR_PEBS_DATA_CFG, 0);
> +        }
>      }
>  
>      if (env->mcg_cap) {
> @@ -5241,6 +5261,15 @@ static int kvm_get_msrs(X86CPU *cpu)
>                  env->msr_gp_evtsel[index] = msrs[i].data;
>              }
>              break;
> +        case MSR_IA32_DS_AREA:
> +            env->msr_ds_area = msrs[i].data;
> +            break;
> +        case MSR_PEBS_DATA_CFG:
> +            env->msr_pebs_data_cfg = msrs[i].data;
> +            break;
> +        case MSR_IA32_PEBS_ENABLE:
> +            env->msr_pebs_enable = msrs[i].data;
> +            break;
>          case HV_X64_MSR_HYPERCALL:
>              env->msr_hv_hypercall = msrs[i].data;
>              break;
> diff --git a/target/i386/machine.c b/target/i386/machine.c
> index 7d08a05835fc..5cff5d5a9db5 100644
> --- a/target/i386/machine.c
> +++ b/target/i386/machine.c
> @@ -659,6 +659,27 @@ static const VMStateDescription 
> vmstate_msr_ia32_feature_control = {
>      }
>  };
>  
> +static bool ds_pebs_enabled(void *opaque)
> +{
> +    X86CPU *cpu = opaque;
> +    CPUX86State *env = &cpu->env;
> +
> +    return (env->msr_ds_area || env->msr_pebs_enable ||
> +            env->msr_pebs_data_cfg);
> +}
> +
> +static const VMStateDescription vmstate_msr_ds_pebs = {
> +    .name = "cpu/msr_architectural_pmu/msr_ds_pebs",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .needed = ds_pebs_enabled,
> +    .fields = (const VMStateField[]){
> +        VMSTATE_UINT64(env.msr_ds_area, X86CPU),
> +        VMSTATE_UINT64(env.msr_pebs_data_cfg, X86CPU),
> +        VMSTATE_UINT64(env.msr_pebs_enable, X86CPU),
> +        VMSTATE_END_OF_LIST()}
> +};
> +
>  static bool pmu_enable_needed(void *opaque)
>  {
>      X86CPU *cpu = opaque;
> @@ -697,7 +718,11 @@ static const VMStateDescription 
> vmstate_msr_architectural_pmu = {
>          VMSTATE_UINT64_ARRAY(env.msr_gp_counters, X86CPU, MAX_GP_COUNTERS),
>          VMSTATE_UINT64_ARRAY(env.msr_gp_evtsel, X86CPU, MAX_GP_COUNTERS),
>          VMSTATE_END_OF_LIST()
> -    }
> +    },
> +    .subsections = (const VMStateDescription * const []) {
> +        &vmstate_msr_ds_pebs,
> +        NULL,
> +    },
>  };
>  
>  static bool mpx_needed(void *opaque)

Reply via email to