On 11/4/2024 3:10 PM, Dongli Zhang wrote:
> Since perfmon-v2, the AMD PMU supports additional registers. This update
> includes get/put functionality for these extra registers.
>
> Similar to the implementation in KVM:
>
> - MSR_CORE_PERF_GLOBAL_STATUS and MSR_AMD64_PERF_CNTR_GLOBAL_STATUS both
> use env->msr_global_status.
> - MSR_CORE_PERF_GLOBAL_CTRL and MSR_AMD64_PERF_CNTR_GLOBAL_CTL both use
> env->msr_global_ctrl.
> - MSR_CORE_PERF_GLOBAL_OVF_CTRL and MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR
> both use env->msr_global_ovf_ctrl.
>
> No changes are needed for vmstate_msr_architectural_pmu or
> pmu_enable_needed().
>
> Signed-off-by: Dongli Zhang <[email protected]>
> ---
> target/i386/cpu.h | 4 ++++
> target/i386/kvm/kvm.c | 47 ++++++++++++++++++++++++++++++++++---------
> 2 files changed, 42 insertions(+), 9 deletions(-)
>
> diff --git a/target/i386/cpu.h b/target/i386/cpu.h
> index 0505eb3b08..68ed798808 100644
> --- a/target/i386/cpu.h
> +++ b/target/i386/cpu.h
> @@ -488,6 +488,10 @@ typedef enum X86Seg {
> #define MSR_CORE_PERF_GLOBAL_CTRL 0x38f
> #define MSR_CORE_PERF_GLOBAL_OVF_CTRL 0x390
>
> +#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS 0xc0000300
> +#define MSR_AMD64_PERF_CNTR_GLOBAL_CTL 0xc0000301
> +#define MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR 0xc0000302
> +
> #define MSR_K7_EVNTSEL0 0xc0010000
> #define MSR_K7_PERFCTR0 0xc0010004
> #define MSR_F15H_PERF_CTL0 0xc0010200
> diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
> index 83ec85a9b9..918dcb61fe 100644
> --- a/target/i386/kvm/kvm.c
> +++ b/target/i386/kvm/kvm.c
> @@ -2074,6 +2074,8 @@ static void kvm_init_pmu_info_intel(CPUX86State *env)
>
> static void kvm_init_pmu_info_amd(CPUX86State *env)
> {
> + uint32_t eax, ebx;
> + uint32_t unused;
> int64_t family;
>
> has_pmu_version = 0;
> @@ -2102,6 +2104,13 @@ static void kvm_init_pmu_info_amd(CPUX86State *env)
> }
>
> num_pmu_gp_counters = AMD64_NUM_COUNTERS_CORE;
> +
> + cpu_x86_cpuid(env, 0x80000022, 0, &eax, &ebx, &unused, &unused);
> +
> + if (eax & CPUID_8000_0022_EAX_PERFMON_V2) {
> + has_pmu_version = 2;
> + num_pmu_gp_counters = ebx & 0xf;
> + }
> }
>
> static bool is_same_vendor(CPUX86State *env)
> @@ -4144,13 +4153,14 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
> uint32_t step = 1;
>
> /*
> - * When PERFCORE is enabled, AMD PMU uses a separate set of
> - * addresses for the selector and counter registers.
> - * Additionally, the address of the next selector or counter
> - * register is determined by incrementing the address of the
> - * current register by two.
> + * When PERFCORE or PerfMonV2 is enabled, AMD PMU uses a
> + * separate set of addresses for the selector and counter
> + * registers. Additionally, the address of the next selector or
> + * counter register is determined by incrementing the address
> + * of the current register by two.
> */
> - if (num_pmu_gp_counters == AMD64_NUM_COUNTERS_CORE) {
> + if (num_pmu_gp_counters == AMD64_NUM_COUNTERS_CORE ||
> + has_pmu_version == 2) {
Future PMU versions are expected to be backwards compatible. So it may be
better to look for has_pmu_version > 1.
> sel_base = MSR_F15H_PERF_CTL0;
> ctr_base = MSR_F15H_PERF_CTR0;
> step = 2;
> @@ -4162,6 +4172,15 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
> kvm_msr_entry_add(cpu, sel_base + i * step,
> env->msr_gp_evtsel[i]);
> }
> +
> + if (has_pmu_version == 2) {
> + kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS,
> + env->msr_global_status);
> + kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
> + env->msr_global_ovf_ctrl);
> + kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
> + env->msr_global_ctrl);
> + }
> }
>
> /*
> @@ -4637,13 +4656,14 @@ static int kvm_get_msrs(X86CPU *cpu)
> uint32_t step = 1;
>
> /*
> - * When PERFCORE is enabled, AMD PMU uses a separate set of
> - * addresses for the selector and counter registers.
> + * When PERFCORE or PerfMonV2 is enabled, AMD PMU uses a separate
> + * set of addresses for the selector and counter registers.
> * Additionally, the address of the next selector or counter
> * register is determined by incrementing the address of the
> * current register by two.
> */
> - if (num_pmu_gp_counters == AMD64_NUM_COUNTERS_CORE) {
> + if (num_pmu_gp_counters == AMD64_NUM_COUNTERS_CORE ||
> + has_pmu_version == 2) {
> sel_base = MSR_F15H_PERF_CTL0;
> ctr_base = MSR_F15H_PERF_CTR0;
> step = 2;
> @@ -4653,6 +4673,12 @@ static int kvm_get_msrs(X86CPU *cpu)
> kvm_msr_entry_add(cpu, ctr_base + i * step, 0);
> kvm_msr_entry_add(cpu, sel_base + i * step, 0);
> }
> +
> + if (has_pmu_version == 2) {
> + kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_CTL, 0);
> + kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS, 0);
> + kvm_msr_entry_add(cpu, MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR, 0);
> + }
> }
>
> if (env->mcg_cap) {
> @@ -4949,12 +4975,15 @@ static int kvm_get_msrs(X86CPU *cpu)
> env->msr_fixed_ctr_ctrl = msrs[i].data;
> break;
> case MSR_CORE_PERF_GLOBAL_CTRL:
> + case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
> env->msr_global_ctrl = msrs[i].data;
> break;
> case MSR_CORE_PERF_GLOBAL_STATUS:
> + case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
> env->msr_global_status = msrs[i].data;
> break;
> case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
> + case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
> env->msr_global_ovf_ctrl = msrs[i].data;
> break;
> case MSR_CORE_PERF_FIXED_CTR0 ... MSR_CORE_PERF_FIXED_CTR0 +
> MAX_FIXED_COUNTERS - 1: