On 8/1/2024 12:58 PM, Mingwei Zhang wrote: > Allow writing to fixed counter selector if counter is exposed. If this > fixed counter is filtered out, this counter won't be enabled on HW. > > Passthrough PMU implements the context switch at VM Enter/Exit boundary the > guest value cannot be directly written to HW since the HW PMU is owned by > the host. Introduce a new field fixed_ctr_ctrl_hw in kvm_pmu to cache the > guest value. which will be assigne to HW at PMU context restore. > > Since passthrough PMU intercept writes to fixed counter selector, there is > no need to read the value at pmu context save, but still clear the fix > counter ctrl MSR and counters when switching out to host PMU. > > Signed-off-by: Mingwei Zhang <mizhang@xxxxxxxxxx> > Signed-off-by: Dapeng Mi <dapeng1.mi@xxxxxxxxxxxxxxx> > Tested-by: Yongwei Ma <yongwei.ma@xxxxxxxxx> > --- > arch/x86/include/asm/kvm_host.h | 1 + > arch/x86/kvm/vmx/pmu_intel.c | 28 ++++++++++++++++++++++++---- > 2 files changed, 25 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index e5c288d4264f..93c17da8271d 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -549,6 +549,7 @@ struct kvm_pmu { > unsigned nr_arch_fixed_counters; > unsigned available_event_types; > u64 fixed_ctr_ctrl; > + u64 fixed_ctr_ctrl_hw; > u64 fixed_ctr_ctrl_mask; > u64 global_ctrl; > u64 global_status; > diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c > index 0cd38c5632ee..c61936266cbd 100644 > --- a/arch/x86/kvm/vmx/pmu_intel.c > +++ b/arch/x86/kvm/vmx/pmu_intel.c > @@ -34,6 +34,25 @@ > > #define MSR_PMC_FULL_WIDTH_BIT (MSR_IA32_PMC0 - MSR_IA32_PERFCTR0) > > +static void reprogram_fixed_counters_in_passthrough_pmu(struct kvm_pmu *pmu, u64 data) > +{ > + struct kvm_pmc *pmc; > + u64 new_data = 0; > + int i; > + > + for (i = 0; i < pmu->nr_arch_fixed_counters; i++) { > + pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); > + if (check_pmu_event_filter(pmc)) { > + pmc->current_config = fixed_ctrl_field(data, i); > + new_data |= (pmc->current_config << (i * 4)); Since we already have macro intel_fixed_bits_by_idx() to manipulate fixed_cntr_ctrl, we 'd better to use it. diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 3dbeb41b85ab..0aa58bffb99d 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -44,7 +44,7 @@ static void reprogram_fixed_counters_in_passthrough_pmu(struct kvm_pmu *pmu, u64 pmc = get_fixed_pmc(pmu, MSR_CORE_PERF_FIXED_CTR0 + i); if (check_pmu_event_filter(pmc)) { pmc->current_config = fixed_ctrl_field(data, i); - new_data |= (pmc->current_config << (i * 4)); + new_data |= intel_fixed_bits_by_idx(i, pmc->current_config); } else { pmc->counter = 0; } > + } else { > + pmc->counter = 0; > + } > + } > + pmu->fixed_ctr_ctrl_hw = new_data; > + pmu->fixed_ctr_ctrl = data; > +} > + > static void reprogram_fixed_counters(struct kvm_pmu *pmu, u64 data) > { > struct kvm_pmc *pmc; > @@ -351,7 +370,9 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) > if (data & pmu->fixed_ctr_ctrl_mask) > return 1; > > - if (pmu->fixed_ctr_ctrl != data) > + if (is_passthrough_pmu_enabled(vcpu)) > + reprogram_fixed_counters_in_passthrough_pmu(pmu, data); > + else if (pmu->fixed_ctr_ctrl != data) > reprogram_fixed_counters(pmu, data); > break; > case MSR_IA32_PEBS_ENABLE: > @@ -820,13 +841,12 @@ static void intel_save_guest_pmu_context(struct kvm_vcpu *vcpu) > if (pmu->global_status) > wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, pmu->global_status); > > - rdmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl); > /* > * Clear hardware FIXED_CTR_CTRL MSR to avoid information leakage and > * also avoid these guest fixed counters get accidentially enabled > * during host running when host enable global ctrl. > */ > - if (pmu->fixed_ctr_ctrl) > + if (pmu->fixed_ctr_ctrl_hw) > wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, 0); > } > > @@ -844,7 +864,7 @@ static void intel_restore_guest_pmu_context(struct kvm_vcpu *vcpu) > if (pmu->global_status & toggle) > wrmsrl(MSR_CORE_PERF_GLOBAL_STATUS_SET, pmu->global_status & toggle); > > - wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl); > + wrmsrl(MSR_CORE_PERF_FIXED_CTR_CTRL, pmu->fixed_ctr_ctrl_hw); > } > > struct kvm_pmu_ops intel_pmu_ops __initdata = {