[PATCH 6/7] target/i386/kvm: support perfmon-v2 for reset

Dongli Zhang posted 7 patches 2 weeks, 5 days ago
[PATCH 6/7] target/i386/kvm: support perfmon-v2 for reset
Posted by Dongli Zhang 2 weeks, 5 days ago
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 <dongli.zhang@oracle.com>
---
 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) {
                 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:
-- 
2.39.3
Re: [PATCH 6/7] target/i386/kvm: support perfmon-v2 for reset
Posted by Sandipan Das 2 weeks, 1 day ago
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 <dongli.zhang@oracle.com>
> ---
>  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:
Re: [PATCH 6/7] target/i386/kvm: support perfmon-v2 for reset
Posted by dongli.zhang@oracle.com 2 weeks, 1 day ago
Hi Sandipan,

On 11/8/24 5:09 AM, Sandipan Das wrote:
> On 11/4/2024 3:10 PM, Dongli Zhang wrote:

[snip]

>> +             * 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.
> 

Sure. I will change that in v2. Thank you very much!

Dongli Zhang