From: sashiko-bot@kernel.org
To: "Colton Lewis" <coltonlewis@google.com>
Cc: kvm@vger.kernel.org, kvmarm@lists.linux.dev,
"Oliver Upton" <oupton@kernel.org>,
linux-perf-users@vger.kernel.org, "Marc Zyngier" <maz@kernel.org>
Subject: Re: [PATCH 09/21] KVM: arm64: Add Partitioned PMU register trap handlers
Date: Fri, 12 Jun 2026 19:51:21 +0000 [thread overview]
Message-ID: <20260612195122.0EC171F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260612192909.1153907-10-coltonlewis@google.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Writes to PMU control-plane system registers lack the architecturally mandated immediate `isb()` synchronization barrier.
- [High] Trapped accesses to `PMEVTYPER`, `PMCCFILTR_EL0`, and `PMOVSSET_EL0` fail to synchronize with the active hardware PMU state while the vCPU is running.
- [High] `kvm_pmu_direct_pmcr_read` bypasses Nested Virtualization (NV) counter limits, exposing incorrect `PMCR_EL0.N` to L2 guests.
- [High] Guest `PMSELR_EL0` and `PMUSERENR_EL0` state is irrevocably lost across vCPU context switches in partitioned PMU mode.
--
commit 62a57b5fbe8c480374618085132cc6e2e40657b1
Author: Colton Lewis <coltonlewis@google.com>
KVM: arm64: Add Partitioned PMU register trap handlers
We may want a partitioned PMU but not have FEAT_FGT to untrap the
specific registers that would normally be untrapped. Add handling for
those trapped register accesses that does the right thing if the PMU
is partitioned.
> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
> index 0135989667564..43f04c2f33d44 100644
> --- a/arch/arm64/kvm/pmu-direct.c
> +++ b/arch/arm64/kvm/pmu-direct.c
> @@ -56,3 +57,32 @@ bool kvm_pmu_is_partitioned(struct kvm *kvm)
> return pmu_is_partitioned(kvm->arch.arm_pmu) &&
> test_bit(KVM_ARCH_FLAG_PARTITION_PMU_ENABLED, &kvm->arch.flags);
> }
> +
> +void kvm_pmu_direct_pmcr_write(struct kvm_vcpu *vcpu, u64 val)
> +{
> + bool reset_p = val & ARMV8_PMU_PMCR_P;
> + unsigned long mask;
> + int i;
> +
> + val &= ~ARMV8_PMU_PMCR_P;
> +
> + write_sysreg(val, pmcr_el0);
> +
> + if (reset_p) {
[Severity: High]
Does this write to pmcr_el0 need an isb() barrier before we evaluate reset_p?
The ARM64 architecture requires updates to control-plane system registers
like pmcr_el0 to be followed immediately by an isb() instruction. Without
it, the pipeline might execute the subsequent instructions under an undefined
state.
> + mask = kvm_pmu_implemented_counter_mask(vcpu) & ~BIT(ARMV8_PMU_CYCLE_IDX);
> +
> + if (!vcpu_is_el2(vcpu))
> + mask &= ~kvm_pmu_hyp_counter_mask(vcpu);
> +
> + for_each_set_bit(i, &mask, ARMV8_PMU_MAX_GENERAL_COUNTERS)
> + write_pmevcntrn(i, 0);
> + }
> +}
> +
> +u64 kvm_pmu_direct_pmcr_read(struct kvm_vcpu *vcpu)
> +{
> + return u64_replace_bits(
> + read_sysreg(pmcr_el0),
> + vcpu->kvm->arch.nr_pmu_counters,
> + ARMV8_PMU_PMCR_N);
[Severity: High]
Can this bypass Nested Virtualization counter limits and expose an incorrect
PMCR_EL0.N value to L2 guests?
The existing kvm_vcpu_read_pmcr() function properly accounts for nested
virtualization by checking for nested guests and restricting PMCR_EL0.N based
on the L1 hypervisor's MDCR_EL2.HPMN limit. This direct read inserts the
full vcpu->kvm->arch.nr_pmu_counters, which means L2 guests under a
partitioned PMU might escape the L1 limit and observe the full count
provisioned to L1.
> +}
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index c52873a6f91ed..94572bc52c32a 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
[ ... ]
> +static void pmu_reg_write(struct kvm_vcpu *vcpu, enum vcpu_sysreg reg, u64 val, bool set)
> +{
> + unsigned long flags;
> + u64 mask;
> + int idx;
> +
> + switch (reg) {
[ ... ]
> + case PMSELR_EL0:
> + if (kvm_pmu_is_partitioned(vcpu->kvm))
> + write_sysreg(val, pmselr_el0);
[Severity: High]
Does this need an isb() after writing pmselr_el0? Like pmcr_el0, writes to
control-plane registers require an immediate synchronization barrier before
returning or executing further instructions.
Also, if we are untrapping or writing directly to the physical pmselr_el0
and pmuserenr_el0 registers, won't this state be irrevocably lost across
vCPU context switches?
When entering a guest, __activate_traps_common() in
arch/arm64/kvm/hyp/include/hyp/switch.h unconditionally clobbers the
physical pmselr_el0 to 0 and pmuserenr_el0 to ARMV8_PMU_USERENR_MASK.
Any state restored by kvm_pmu_load() or set here would be destroyed
before the guest actually executes.
[ ... ]
> + case PMEVTYPER0_EL0 ... PMCCFILTR_EL0:
> + idx = reg - PMEVTYPER0_EL0;
> +
> + if (kvm_pmu_is_partitioned(vcpu->kvm)) {
> + mask = kvm_pmu_evtyper_mask(vcpu->kvm);
> + __vcpu_assign_sys_reg(vcpu, reg, val & mask);
[Severity: High]
Since traps are processed synchronously while the vCPU is loaded, doesn't
updating only the virtual sysreg array leave the active hardware with stale
configurations?
Writing to the virtual array here without requesting a PMU reload
(KVM_REQ_RELOAD_PMU) or updating the hardware means that upon ERET back to
the guest, the physical PMU will continue executing with the old state.
[ ... ]
> + case PMCNTENSET_EL0:
> + if (kvm_pmu_is_partitioned(vcpu->kvm)) {
> + if (set)
> + write_sysreg(val, pmcntenset_el0);
> + else
> + write_sysreg(val, pmcntenclr_el0);
[Severity: High]
Does returning after this write without an isb() violate the architectural
requirements?
Writing to pmcntenset_el0 or pmcntenclr_el0 needs an immediate isb() to
ensure the state change is resolved before returning to the caller or
executing subsequent pipeline instructions.
[ ... ]
> + case PMUSERENR_EL0:
> + if (kvm_pmu_is_partitioned(vcpu->kvm))
> + write_sysreg(val, pmuserenr_el0);
[Severity: High]
Is an isb() barrier required here after writing pmuserenr_el0, similar to the
other control-plane registers?
[ ... ]
> +static u64 pmu_reg_read(struct kvm_vcpu *vcpu, enum vcpu_sysreg reg)
> +{
> + u64 val = 0;
> + int idx;
> +
> + switch (reg) {
[ ... ]
> + case PMOVSSET_EL0:
> + val = __vcpu_sys_reg(vcpu, reg);
[Severity: High]
Will this return an accurate value if there are unhandled physical hardware
overflows?
Because we only read the virtual array here, we could mask unhandled physical
hardware overflows from polling guests if the host hasn't yet processed the
IRQ and updated the virtual state.
> + break;
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260612192909.1153907-1-coltonlewis@google.com?part=9
next prev parent reply other threads:[~2026-06-12 19:51 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-12 19:28 [PATCH v8 00/21] ARM64 PMU Partitioning Colton Lewis
2026-06-12 19:28 ` [PATCH 01/21] arm64: cpufeature: Add cpucap for HPMN0 Colton Lewis
2026-06-12 19:28 ` [PATCH 02/21] KVM: arm64: Reorganize PMU includes Colton Lewis
2026-06-12 19:28 ` [PATCH 03/21] KVM: arm64: Reorganize PMU functions Colton Lewis
2026-06-12 19:56 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 04/21] perf: arm_pmuv3: Generalize counter bitmasks Colton Lewis
2026-06-12 19:28 ` [PATCH 05/21] perf: arm_pmuv3: Check cntr_mask before using pmccntr Colton Lewis
2026-06-12 19:42 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 06/21] perf: arm_pmuv3: Allocate counter indices from high to low Colton Lewis
2026-06-12 19:28 ` [PATCH 07/21] perf: arm_pmuv3: Add method to partition the PMU Colton Lewis
2026-06-12 19:28 ` [PATCH 08/21] KVM: arm64: Set up FGT for Partitioned PMU Colton Lewis
2026-06-12 19:45 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 09/21] KVM: arm64: Add Partitioned PMU register trap handlers Colton Lewis
2026-06-12 19:51 ` sashiko-bot [this message]
2026-06-12 19:28 ` [PATCH 10/21] KVM: arm64: Set up MDCR_EL2 to handle a Partitioned PMU Colton Lewis
2026-06-12 19:52 ` sashiko-bot
2026-06-12 19:28 ` [PATCH 11/21] KVM: arm64: Context swap Partitioned PMU guest registers Colton Lewis
2026-06-12 19:51 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 12/21] KVM: arm64: Enforce PMU event filter at vcpu_load() Colton Lewis
2026-06-12 19:53 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 13/21] perf: Add perf_pmu_resched_update() Colton Lewis
2026-06-12 19:29 ` [PATCH 14/21] KVM: arm64: Apply dynamic guest counter reservations Colton Lewis
2026-06-12 19:50 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 15/21] KVM: arm64: Implement lazy PMU context swaps Colton Lewis
2026-06-12 19:50 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 16/21] perf: arm_pmuv3: Handle IRQs for Partitioned PMU guest counters Colton Lewis
2026-06-12 19:57 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 17/21] KVM: arm64: Detect overflows for the Partitioned PMU Colton Lewis
2026-06-12 19:58 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 18/21] KVM: arm64: Add vCPU device attr to partition the PMU Colton Lewis
2026-06-12 19:54 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 19/21] KVM: selftests: Add find_bit to KVM library Colton Lewis
2026-06-12 20:01 ` sashiko-bot
2026-06-12 19:29 ` [PATCH 20/21] KVM: arm64: selftests: Add test case for Partitioned PMU Colton Lewis
2026-06-12 19:29 ` [PATCH 21/21] KVM: arm64: selftests: Relax testing for exceptions when partitioned Colton Lewis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260612195122.0EC171F000E9@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=coltonlewis@google.com \
--cc=kvm@vger.kernel.org \
--cc=kvmarm@lists.linux.dev \
--cc=linux-perf-users@vger.kernel.org \
--cc=maz@kernel.org \
--cc=oupton@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox