From: Dapeng Mi <dapeng1.mi@linux.intel.com>
If IA32_PERF_CAPABILITIES.FW_WRITE (bit 13) is set, each general-
purpose counter IA32_PMCi (starting at 0xc1) is accompanied by a
corresponding 64-bit alias MSR starting at 0x4c1 (IA32_A_PMC0).
The legacy IA32_PMCi MSRs are not full-width and their effective width
is determined by CPUID.0AH:EAX[23:16].
Since these MSRs are architectural aliases, when IA32_A_PMCi is
supported, these alias MSRs can safely be used for save/restore
instead of the legacy IA32_PMCi MSRs
Full-width write is a user-visible feature and can be disabled
individually.
Signed-off-by: Dapeng Mi <dapeng1.mi@linux.intel.com>
Signed-off-by: Zide Chen <zide.chen@intel.com>
---
V3:
- Move the MAX_GP_COUNTERS change and migrate version ID code to
[patch v3 4/13] to avoid bumping version IDs twice in one patch
series.
V2:
- Slightly improve the commit message wording.
- Update the comment for MSR_IA32_PMC0 definition.
---
target/i386/cpu.h | 3 +++
target/i386/kvm/kvm.c | 18 ++++++++++++++++--
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 23d4ee13abfa..7c241a20420c 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_FULL_WRITE (1U << 13)
#define MSR_IA32_TSX_CTRL 0x122
#define MSR_IA32_TSCDEADLINE 0x6e0
@@ -448,6 +449,8 @@ typedef enum X86Seg {
#define MSR_IA32_SGXLEPUBKEYHASH3 0x8f
#define MSR_P6_PERFCTR0 0xc1
+/* Alias MSR range for full-width general-purpose performance counters */
+#define MSR_IA32_PMC0 0x4c1
#define MSR_IA32_SMBASE 0x9e
#define MSR_SMI_COUNT 0x34
diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c
index 144585df5ba6..39a67c58ac22 100644
--- a/target/i386/kvm/kvm.c
+++ b/target/i386/kvm/kvm.c
@@ -4187,6 +4187,12 @@ static int kvm_put_msrs(X86CPU *cpu, KvmPutState level)
}
if ((IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env)) && pmu_version > 0) {
+ uint32_t perf_cntr_base = MSR_P6_PERFCTR0;
+
+ if (env->features[FEAT_PERF_CAPABILITIES] & PERF_CAP_FULL_WRITE) {
+ perf_cntr_base = MSR_IA32_PMC0;
+ }
+
if (pmu_version > 1) {
/* Stop the counter. */
kvm_msr_entry_add(cpu, MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
@@ -4199,7 +4205,7 @@ static int kvm_put_msrs(X86CPU *cpu, KvmPutState level)
env->msr_fixed_counters[i]);
}
for (i = 0; i < num_pmu_gp_counters; i++) {
- kvm_msr_entry_add(cpu, MSR_P6_PERFCTR0 + i,
+ kvm_msr_entry_add(cpu, perf_cntr_base + i,
env->msr_gp_counters[i]);
kvm_msr_entry_add(cpu, MSR_P6_EVNTSEL0 + i,
env->msr_gp_evtsel[i]);
@@ -4761,6 +4767,11 @@ static int kvm_get_msrs(X86CPU *cpu)
}
if ((IS_INTEL_CPU(env) || IS_ZHAOXIN_CPU(env)) && pmu_version > 0) {
+ uint32_t perf_cntr_base = MSR_P6_PERFCTR0;
+
+ if (env->features[FEAT_PERF_CAPABILITIES] & PERF_CAP_FULL_WRITE) {
+ perf_cntr_base = MSR_IA32_PMC0;
+ }
if (pmu_version > 1) {
kvm_msr_entry_add(cpu, MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
kvm_msr_entry_add(cpu, MSR_CORE_PERF_GLOBAL_CTRL, 0);
@@ -4770,7 +4781,7 @@ static int kvm_get_msrs(X86CPU *cpu)
kvm_msr_entry_add(cpu, MSR_CORE_PERF_FIXED_CTR0 + i, 0);
}
for (i = 0; i < num_pmu_gp_counters; i++) {
- kvm_msr_entry_add(cpu, MSR_P6_PERFCTR0 + i, 0);
+ kvm_msr_entry_add(cpu, perf_cntr_base + i, 0);
kvm_msr_entry_add(cpu, MSR_P6_EVNTSEL0 + i, 0);
}
}
@@ -5135,6 +5146,9 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR0 + MAX_GP_COUNTERS - 1:
env->msr_gp_counters[index - MSR_P6_PERFCTR0] = msrs[i].data;
break;
+ case MSR_IA32_PMC0 ... MSR_IA32_PMC0 + MAX_GP_COUNTERS - 1:
+ env->msr_gp_counters[index - MSR_IA32_PMC0] = msrs[i].data;
+ break;
case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL0 + MAX_GP_COUNTERS - 1:
env->msr_gp_evtsel[index - MSR_P6_EVNTSEL0] = msrs[i].data;
break;
--
2.53.0