Skip to content

Commit 4a27718

Browse files
Like Xusean-jc
authored andcommitted
KVM: x86/svm/pmu: Add AMD PerfMonV2 support
If AMD Performance Monitoring Version 2 (PerfMonV2) is detected by the guest, it can use a new scheme to manage the Core PMCs using the new global control and status registers. In addition to benefiting from the PerfMonV2 functionality in the same way as the host (higher precision), the guest also can reduce the number of vm-exits by lowering the total number of MSRs accesses. In terms of implementation details, amd_is_valid_msr() is resurrected since three newly added MSRs could not be mapped to one vPMC. The possibility of emulating PerfMonV2 on the mainframe has also been eliminated for reasons of precision. Co-developed-by: Sandipan Das <sandipan.das@amd.com> Signed-off-by: Sandipan Das <sandipan.das@amd.com> Signed-off-by: Like Xu <likexu@tencent.com> [sean: drop "Based on the observed HW." comments] Link: https://lore.kernel.org/r/20230603011058.1038821-12-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent fe8d76c commit 4a27718

File tree

3 files changed

+72
-11
lines changed

3 files changed

+72
-11
lines changed

arch/x86/kvm/pmu.c

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,11 +585,14 @@ int kvm_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
585585

586586
switch (msr) {
587587
case MSR_CORE_PERF_GLOBAL_STATUS:
588+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
588589
msr_info->data = pmu->global_status;
589590
break;
591+
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
590592
case MSR_CORE_PERF_GLOBAL_CTRL:
591593
msr_info->data = pmu->global_ctrl;
592594
break;
595+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
593596
case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
594597
msr_info->data = 0;
595598
break;
@@ -607,16 +610,28 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
607610
u64 data = msr_info->data;
608611
u64 diff;
609612

613+
/*
614+
* Note, AMD ignores writes to reserved bits and read-only PMU MSRs,
615+
* whereas Intel generates #GP on attempts to write reserved/RO MSRs.
616+
*/
610617
switch (msr) {
611618
case MSR_CORE_PERF_GLOBAL_STATUS:
612619
if (!msr_info->host_initiated)
613620
return 1; /* RO MSR */
621+
fallthrough;
622+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
623+
/* Per PPR, Read-only MSR. Writes are ignored. */
624+
if (!msr_info->host_initiated)
625+
break;
614626

615627
if (data & pmu->global_status_mask)
616628
return 1;
617629

618630
pmu->global_status = data;
619631
break;
632+
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
633+
data &= ~pmu->global_ctrl_mask;
634+
fallthrough;
620635
case MSR_CORE_PERF_GLOBAL_CTRL:
621636
if (!kvm_valid_perf_global_ctrl(pmu, data))
622637
return 1;
@@ -634,7 +649,8 @@ int kvm_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
634649
*/
635650
if (data & pmu->global_status_mask)
636651
return 1;
637-
652+
fallthrough;
653+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
638654
if (!msr_info->host_initiated)
639655
pmu->global_status &= ~data;
640656
break;

arch/x86/kvm/svm/pmu.c

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ static struct kvm_pmc *amd_rdpmc_ecx_to_pmc(struct kvm_vcpu *vcpu,
9494
return amd_pmc_idx_to_pmc(vcpu_to_pmu(vcpu), idx & ~(3u << 30));
9595
}
9696

97-
static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
98-
{
99-
/* All MSRs refer to exactly one PMC, so msr_idx_to_pmc is enough. */
100-
return false;
101-
}
102-
10397
static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
10498
{
10599
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -111,6 +105,29 @@ static struct kvm_pmc *amd_msr_idx_to_pmc(struct kvm_vcpu *vcpu, u32 msr)
111105
return pmc;
112106
}
113107

108+
static bool amd_is_valid_msr(struct kvm_vcpu *vcpu, u32 msr)
109+
{
110+
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
111+
112+
switch (msr) {
113+
case MSR_K7_EVNTSEL0 ... MSR_K7_PERFCTR3:
114+
return pmu->version > 0;
115+
case MSR_F15H_PERF_CTL0 ... MSR_F15H_PERF_CTR5:
116+
return guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE);
117+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
118+
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
119+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
120+
return pmu->version > 1;
121+
default:
122+
if (msr > MSR_F15H_PERF_CTR5 &&
123+
msr < MSR_F15H_PERF_CTL0 + 2 * pmu->nr_arch_gp_counters)
124+
return pmu->version > 1;
125+
break;
126+
}
127+
128+
return amd_msr_idx_to_pmc(vcpu, msr);
129+
}
130+
114131
static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
115132
{
116133
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -164,23 +181,39 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
164181
static void amd_pmu_refresh(struct kvm_vcpu *vcpu)
165182
{
166183
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
184+
union cpuid_0x80000022_ebx ebx;
167185

168-
if (guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE))
186+
pmu->version = 1;
187+
if (guest_cpuid_has(vcpu, X86_FEATURE_PERFMON_V2)) {
188+
pmu->version = 2;
189+
/*
190+
* Note, PERFMON_V2 is also in 0x80000022.0x0, i.e. the guest
191+
* CPUID entry is guaranteed to be non-NULL.
192+
*/
193+
BUILD_BUG_ON(x86_feature_cpuid(X86_FEATURE_PERFMON_V2).function != 0x80000022 ||
194+
x86_feature_cpuid(X86_FEATURE_PERFMON_V2).index);
195+
ebx.full = kvm_find_cpuid_entry_index(vcpu, 0x80000022, 0)->ebx;
196+
pmu->nr_arch_gp_counters = ebx.split.num_core_pmc;
197+
} else if (guest_cpuid_has(vcpu, X86_FEATURE_PERFCTR_CORE)) {
169198
pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS_CORE;
170-
else
199+
} else {
171200
pmu->nr_arch_gp_counters = AMD64_NUM_COUNTERS;
201+
}
172202

173203
pmu->nr_arch_gp_counters = min_t(unsigned int, pmu->nr_arch_gp_counters,
174204
kvm_pmu_cap.num_counters_gp);
175205

206+
if (pmu->version > 1) {
207+
pmu->global_ctrl_mask = ~((1ull << pmu->nr_arch_gp_counters) - 1);
208+
pmu->global_status_mask = pmu->global_ctrl_mask;
209+
}
210+
176211
pmu->counter_bitmask[KVM_PMC_GP] = ((u64)1 << 48) - 1;
177212
pmu->reserved_bits = 0xfffffff000280000ull;
178213
pmu->raw_event_mask = AMD64_RAW_EVENT_MASK;
179-
pmu->version = 1;
180214
/* not applicable to AMD; but clean them to prevent any fall out */
181215
pmu->counter_bitmask[KVM_PMC_FIXED] = 0;
182216
pmu->nr_arch_fixed_counters = 0;
183-
pmu->global_status = 0;
184217
bitmap_set(pmu->all_valid_pmc_idx, 0, pmu->nr_arch_gp_counters);
185218
}
186219

@@ -211,6 +244,8 @@ static void amd_pmu_reset(struct kvm_vcpu *vcpu)
211244
pmc_stop_counter(pmc);
212245
pmc->counter = pmc->prev_counter = pmc->eventsel = 0;
213246
}
247+
248+
pmu->global_ctrl = pmu->global_status = 0;
214249
}
215250

216251
struct kvm_pmu_ops amd_pmu_ops __initdata = {

arch/x86/kvm/x86.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,10 @@ static const u32 msrs_to_save_pmu[] = {
14831483
MSR_F15H_PERF_CTL3, MSR_F15H_PERF_CTL4, MSR_F15H_PERF_CTL5,
14841484
MSR_F15H_PERF_CTR0, MSR_F15H_PERF_CTR1, MSR_F15H_PERF_CTR2,
14851485
MSR_F15H_PERF_CTR3, MSR_F15H_PERF_CTR4, MSR_F15H_PERF_CTR5,
1486+
1487+
MSR_AMD64_PERF_CNTR_GLOBAL_CTL,
1488+
MSR_AMD64_PERF_CNTR_GLOBAL_STATUS,
1489+
MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR,
14861490
};
14871491

14881492
static u32 msrs_to_save[ARRAY_SIZE(msrs_to_save_base) +
@@ -7150,6 +7154,12 @@ static void kvm_probe_msr_to_save(u32 msr_index)
71507154
kvm_pmu_cap.num_counters_fixed)
71517155
return;
71527156
break;
7157+
case MSR_AMD64_PERF_CNTR_GLOBAL_CTL:
7158+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS:
7159+
case MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR:
7160+
if (!kvm_cpu_cap_has(X86_FEATURE_PERFMON_V2))
7161+
return;
7162+
break;
71537163
case MSR_IA32_XFD:
71547164
case MSR_IA32_XFD_ERR:
71557165
if (!kvm_cpu_cap_has(X86_FEATURE_XFD))

0 commit comments

Comments
 (0)