Skip to content

Commit 75189d1

Browse files
Like Xubonzini
authored andcommitted
KVM: x86/pmu: Update AMD PMC sample period to fix guest NMI-watchdog
NMI-watchdog is one of the favorite features of kernel developers, but it does not work in AMD guest even with vPMU enabled and worse, the system misrepresents this capability via /proc. This is a PMC emulation error. KVM does not pass the latest valid value to perf_event in time when guest NMI-watchdog is running, thus the perf_event corresponding to the watchdog counter will enter the old state at some point after the first guest NMI injection, forcing the hardware register PMC0 to be constantly written to 0x800000000001. Meanwhile, the running counter should accurately reflect its new value based on the latest coordinated pmc->counter (from vPMC's point of view) rather than the value written directly by the guest. Fixes: 168d918 ("KVM: x86: Adjust counter sample period after a wrmsr") Reported-by: Dongli Cao <[email protected]> Signed-off-by: Like Xu <[email protected]> Reviewed-by: Yanan Wang <[email protected]> Tested-by: Yanan Wang <[email protected]> Reviewed-by: Jim Mattson <[email protected]> Message-Id: <[email protected]> Cc: [email protected] Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 0361bdf commit 75189d1

File tree

3 files changed

+12
-6
lines changed

3 files changed

+12
-6
lines changed

arch/x86/kvm/pmu.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ static inline u64 get_sample_period(struct kvm_pmc *pmc, u64 counter_value)
138138
return sample_period;
139139
}
140140

141+
static inline void pmc_update_sample_period(struct kvm_pmc *pmc)
142+
{
143+
if (!pmc->perf_event || pmc->is_paused)
144+
return;
145+
146+
perf_event_period(pmc->perf_event,
147+
get_sample_period(pmc, pmc->counter));
148+
}
149+
141150
void reprogram_gp_counter(struct kvm_pmc *pmc, u64 eventsel);
142151
void reprogram_fixed_counter(struct kvm_pmc *pmc, u8 ctrl, int fixed_idx);
143152
void reprogram_counter(struct kvm_pmu *pmu, int pmc_idx);

arch/x86/kvm/svm/pmu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
257257
pmc = get_gp_pmc_amd(pmu, msr, PMU_TYPE_COUNTER);
258258
if (pmc) {
259259
pmc->counter += data - pmc_read_counter(pmc);
260+
pmc_update_sample_period(pmc);
260261
return 0;
261262
}
262263
/* MSR_EVNTSELn */

arch/x86/kvm/vmx/pmu_intel.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -431,15 +431,11 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
431431
!(msr & MSR_PMC_FULL_WIDTH_BIT))
432432
data = (s64)(s32)data;
433433
pmc->counter += data - pmc_read_counter(pmc);
434-
if (pmc->perf_event && !pmc->is_paused)
435-
perf_event_period(pmc->perf_event,
436-
get_sample_period(pmc, data));
434+
pmc_update_sample_period(pmc);
437435
return 0;
438436
} else if ((pmc = get_fixed_pmc(pmu, msr))) {
439437
pmc->counter += data - pmc_read_counter(pmc);
440-
if (pmc->perf_event && !pmc->is_paused)
441-
perf_event_period(pmc->perf_event,
442-
get_sample_period(pmc, data));
438+
pmc_update_sample_period(pmc);
443439
return 0;
444440
} else if ((pmc = get_gp_pmc(pmu, msr, MSR_P6_EVNTSEL0))) {
445441
if (data == pmc->eventsel)

0 commit comments

Comments
 (0)