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
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:
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
© 2016 - 2024 Red Hat, Inc.