[PATCH 3/6] KVM: x86/pmu: Track enabled AMD PMCs with Host-Only xor Guest-Only bits set

Jim Mattson posted 6 patches 2 weeks, 4 days ago
[PATCH 3/6] KVM: x86/pmu: Track enabled AMD PMCs with Host-Only xor Guest-Only bits set
Posted by Jim Mattson 2 weeks, 4 days ago
Add pmc_hostonly and pmc_guestonly bitmaps to struct kvm_pmu to track which
guest-enabled performance counters have just one of the Host-Only and
Guest-Only event selector bits set. PMCs that are disabled, have neither
HG_ONLY bit set, or have both HG_ONLY bits set are not tracked, because
they don't require special handling at vCPU state transitions.

Update the bitmaps when the guest writes to an event selector MSR.

Signed-off-by: Jim Mattson <jmattson@google.com>
---
 arch/x86/include/asm/kvm_host.h |  4 ++++
 arch/x86/kvm/pmu.c              |  2 ++
 arch/x86/kvm/svm/pmu.c          | 28 ++++++++++++++++++++++++++++
 3 files changed, 34 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index ecd4019b84b7..92050f76f84b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -593,6 +593,10 @@ struct kvm_pmu {
 	DECLARE_BITMAP(pmc_counting_instructions, X86_PMC_IDX_MAX);
 	DECLARE_BITMAP(pmc_counting_branches, X86_PMC_IDX_MAX);
 
+	/* AMD only: track PMCs with Host-Only or Guest-Only bits set */
+	DECLARE_BITMAP(pmc_hostonly, X86_PMC_IDX_MAX);
+	DECLARE_BITMAP(pmc_guestonly, X86_PMC_IDX_MAX);
+
 	u64 ds_area;
 	u64 pebs_enable;
 	u64 pebs_enable_rsvd;
diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index bd6b785cf261..833ee2ecd43f 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -921,6 +921,8 @@ static void kvm_pmu_reset(struct kvm_vcpu *vcpu)
 	pmu->need_cleanup = false;
 
 	bitmap_zero(pmu->reprogram_pmi, X86_PMC_IDX_MAX);
+	bitmap_zero(pmu->pmc_hostonly, X86_PMC_IDX_MAX);
+	bitmap_zero(pmu->pmc_guestonly, X86_PMC_IDX_MAX);
 
 	kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx) {
 		pmc_stop_counter(pmc);
diff --git a/arch/x86/kvm/svm/pmu.c b/arch/x86/kvm/svm/pmu.c
index f619417557f9..c06013e2b4b1 100644
--- a/arch/x86/kvm/svm/pmu.c
+++ b/arch/x86/kvm/svm/pmu.c
@@ -147,6 +147,33 @@ static int amd_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 	return 1;
 }
 
+static void amd_pmu_update_hg_bitmaps(struct kvm_pmc *pmc)
+{
+	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
+	u64 eventsel = pmc->eventsel;
+
+	if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) {
+		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
+		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
+		return;
+	}
+
+	switch (eventsel & AMD64_EVENTSEL_HG_ONLY) {
+	case AMD64_EVENTSEL_HOSTONLY:
+		bitmap_set(pmu->pmc_hostonly, pmc->idx, 1);
+		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
+		break;
+	case AMD64_EVENTSEL_GUESTONLY:
+		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
+		bitmap_set(pmu->pmc_guestonly, pmc->idx, 1);
+		break;
+	default:
+		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
+		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
+		break;
+	}
+}
+
 static bool amd_pmu_dormant_hg_event(struct kvm_pmc *pmc)
 {
 	u64 hg_only = pmc->eventsel & AMD64_EVENTSEL_HG_ONLY;
@@ -196,6 +223,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
 		if (data != pmc->eventsel) {
 			pmc->eventsel = data;
 			amd_pmu_set_eventsel_hw(pmc);
+			amd_pmu_update_hg_bitmaps(pmc);
 			kvm_pmu_request_counter_reprogram(pmc);
 		}
 		return 0;
-- 
2.52.0.457.g6b5491de43-goog
Re: [PATCH 3/6] KVM: x86/pmu: Track enabled AMD PMCs with Host-Only xor Guest-Only bits set
Posted by Sean Christopherson 2 weeks, 3 days ago
On Wed, Jan 21, 2026, Jim Mattson wrote:
> Add pmc_hostonly and pmc_guestonly bitmaps to struct kvm_pmu to track which
> guest-enabled performance counters have just one of the Host-Only and
> Guest-Only event selector bits set. PMCs that are disabled, have neither
> HG_ONLY bit set, or have both HG_ONLY bits set are not tracked, because
> they don't require special handling at vCPU state transitions.

Why bother with bitmaps?  The bitmaps are basically just eliding the checks in
amd_pmc_is_active() (my name), and those checks are super fast compared to
emulating transitions between L1 and L2.

Can't we simply do:

  void amd_pmu_refresh_host_guest_eventsels(struct kvm_vcpu *vcpu)
  {
	struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
	struct kvm_pmc *pmc;
	int i;

	kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx)
		amd_pmu_set_eventsel_hw(pmc);

  }

And then call that helper on all transitions?

> +static void amd_pmu_update_hg_bitmaps(struct kvm_pmc *pmc)
> +{
> +	struct kvm_pmu *pmu = pmc_to_pmu(pmc);
> +	u64 eventsel = pmc->eventsel;
> +
> +	if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) {
> +		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
> +		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
> +		return;
> +	}
> +
> +	switch (eventsel & AMD64_EVENTSEL_HG_ONLY) {
> +	case AMD64_EVENTSEL_HOSTONLY:
> +		bitmap_set(pmu->pmc_hostonly, pmc->idx, 1);
> +		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
> +		break;
> +	case AMD64_EVENTSEL_GUESTONLY:
> +		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
> +		bitmap_set(pmu->pmc_guestonly, pmc->idx, 1);
> +		break;
> +	default:
> +		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
> +		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
> +		break;
> +	}
> +}
> +
>  static bool amd_pmu_dormant_hg_event(struct kvm_pmc *pmc)
>  {
>  	u64 hg_only = pmc->eventsel & AMD64_EVENTSEL_HG_ONLY;
> @@ -196,6 +223,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
>  		if (data != pmc->eventsel) {
>  			pmc->eventsel = data;
>  			amd_pmu_set_eventsel_hw(pmc);
> +			amd_pmu_update_hg_bitmaps(pmc);

If we're going to bother adding amd_pmu_set_eventsel_hw(), and not reuse it as
suggested above, then it amd_pmu_set_eventsel_hw() should be renamed to just
amd_pmu_set_eventsel() and it should be the one configuring the bitmaps.  Because
KVM should never write to an eventsel without updating the bitmaps.  That would
also better capture the relationship between the bitmaps and eventsel_hw, e.g.

	pmc->eventsel_hw = (pmc->eventsel & ~AMD64_EVENTSEL_HOSTONLY) |
			   AMD64_EVENTSEL_GUESTONLY;

	if (!amd_pmc_is_active(pmc))
		pmc->eventsel_hw &= ~ARCH_PERFMON_EVENTSEL_ENABLE;

	/*
	 * Update the host/guest bitmaps used to reconfigure eventsel_hw on
	 * transitions to/from an L2 guest, so that KVM can quickly refresh
	 * the event selectors programmed into hardware, e.g. without having
	 * to 
	 */
	if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) {
		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
		return;
	}

	switch (eventsel & AMD64_EVENTSEL_HG_ONLY) {
	case AMD64_EVENTSEL_HOSTONLY:
		bitmap_set(pmu->pmc_hostonly, pmc->idx, 1);
		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
		break;
	case AMD64_EVENTSEL_GUESTONLY:
		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
		bitmap_set(pmu->pmc_guestonly, pmc->idx, 1);
		break;
	default:
		bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
		bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
		break;
	}

But I still don't see any point in the bitmaps.

>  			kvm_pmu_request_counter_reprogram(pmc);
>  		}
>  		return 0;
> -- 
> 2.52.0.457.g6b5491de43-goog
>
Re: [PATCH 3/6] KVM: x86/pmu: Track enabled AMD PMCs with Host-Only xor Guest-Only bits set
Posted by Jim Mattson 2 weeks, 1 day ago
On Thu, Jan 22, 2026 at 8:49 AM Sean Christopherson <seanjc@google.com> wrote:
>
> On Wed, Jan 21, 2026, Jim Mattson wrote:
> > Add pmc_hostonly and pmc_guestonly bitmaps to struct kvm_pmu to track which
> > guest-enabled performance counters have just one of the Host-Only and
> > Guest-Only event selector bits set. PMCs that are disabled, have neither
> > HG_ONLY bit set, or have both HG_ONLY bits set are not tracked, because
> > they don't require special handling at vCPU state transitions.
>
> Why bother with bitmaps?  The bitmaps are basically just eliding the checks in
> amd_pmc_is_active() (my name), and those checks are super fast compared to
> emulating transitions between L1 and L2.
>
> Can't we simply do:
>
>   void amd_pmu_refresh_host_guest_eventsels(struct kvm_vcpu *vcpu)
>   {
>         struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
>         struct kvm_pmc *pmc;
>         int i;
>
>         kvm_for_each_pmc(pmu, pmc, i, pmu->all_valid_pmc_idx)
>                 amd_pmu_set_eventsel_hw(pmc);
>
>   }
>
> And then call that helper on all transitions?
>
> > +static void amd_pmu_update_hg_bitmaps(struct kvm_pmc *pmc)
> > +{
> > +     struct kvm_pmu *pmu = pmc_to_pmu(pmc);
> > +     u64 eventsel = pmc->eventsel;
> > +
> > +     if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) {
> > +             bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
> > +             bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
> > +             return;
> > +     }
> > +
> > +     switch (eventsel & AMD64_EVENTSEL_HG_ONLY) {
> > +     case AMD64_EVENTSEL_HOSTONLY:
> > +             bitmap_set(pmu->pmc_hostonly, pmc->idx, 1);
> > +             bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
> > +             break;
> > +     case AMD64_EVENTSEL_GUESTONLY:
> > +             bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
> > +             bitmap_set(pmu->pmc_guestonly, pmc->idx, 1);
> > +             break;
> > +     default:
> > +             bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
> > +             bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
> > +             break;
> > +     }
> > +}
> > +
> >  static bool amd_pmu_dormant_hg_event(struct kvm_pmc *pmc)
> >  {
> >       u64 hg_only = pmc->eventsel & AMD64_EVENTSEL_HG_ONLY;
> > @@ -196,6 +223,7 @@ static int amd_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
> >               if (data != pmc->eventsel) {
> >                       pmc->eventsel = data;
> >                       amd_pmu_set_eventsel_hw(pmc);
> > +                     amd_pmu_update_hg_bitmaps(pmc);
>
> If we're going to bother adding amd_pmu_set_eventsel_hw(), and not reuse it as
> suggested above, then it amd_pmu_set_eventsel_hw() should be renamed to just
> amd_pmu_set_eventsel() and it should be the one configuring the bitmaps.  Because
> KVM should never write to an eventsel without updating the bitmaps.  That would
> also better capture the relationship between the bitmaps and eventsel_hw, e.g.
>
>         pmc->eventsel_hw = (pmc->eventsel & ~AMD64_EVENTSEL_HOSTONLY) |
>                            AMD64_EVENTSEL_GUESTONLY;
>
>         if (!amd_pmc_is_active(pmc))
>                 pmc->eventsel_hw &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
>
>         /*
>          * Update the host/guest bitmaps used to reconfigure eventsel_hw on
>          * transitions to/from an L2 guest, so that KVM can quickly refresh
>          * the event selectors programmed into hardware, e.g. without having
>          * to
>          */
>         if (!(eventsel & ARCH_PERFMON_EVENTSEL_ENABLE)) {
>                 bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
>                 bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
>                 return;
>         }
>
>         switch (eventsel & AMD64_EVENTSEL_HG_ONLY) {
>         case AMD64_EVENTSEL_HOSTONLY:
>                 bitmap_set(pmu->pmc_hostonly, pmc->idx, 1);
>                 bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
>                 break;
>         case AMD64_EVENTSEL_GUESTONLY:
>                 bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
>                 bitmap_set(pmu->pmc_guestonly, pmc->idx, 1);
>                 break;
>         default:
>                 bitmap_clear(pmu->pmc_hostonly, pmc->idx, 1);
>                 bitmap_clear(pmu->pmc_guestonly, pmc->idx, 1);
>                 break;
>         }
>
> But I still don't see any point in the bitmaps.

No problem. I will drop them in the next version.