kvm_pmu_implemented_counter_mask() derives the counter count from
kvm_vcpu_read_pmcr(). For a nested vCPU outside EL2, PMCR_EL0.N reflects
MDCR_EL2.HPMN instead of the VM-wide counter count.
Consequently, processing a PMU reload while the saved context is L2 can
clear and fail to recreate state for counters reserved for EL2.
Build the implemented counter mask from nr_pmu_counters instead. Keep
the EL-dependent HPMN restriction in
kvm_pmu_accessible_counter_mask(), where it controls guest access.
Fixes: 600f6fa5c90c ("KVM: arm64: Let kvm_vcpu_read_pmcr() return an
EL-dependent value for PMCR_EL0.N")
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Akihiko Odaki <[email protected]>
---
arch/arm64/kvm/pmu-emul.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
index b4b877f31097..5281d37634a0 100644
--- a/arch/arm64/kvm/pmu-emul.c
+++ b/arch/arm64/kvm/pmu-emul.c
@@ -317,12 +317,12 @@ u64 kvm_pmu_accessible_counter_mask(struct kvm_vcpu *vcpu)
u64 kvm_pmu_implemented_counter_mask(struct kvm_vcpu *vcpu)
{
- u64 val = FIELD_GET(ARMV8_PMU_PMCR_N, kvm_vcpu_read_pmcr(vcpu));
+ u64 n = vcpu->kvm->arch.nr_pmu_counters;
- if (val == 0)
+ if (n == 0)
return BIT(ARMV8_PMU_CYCLE_IDX);
else
- return GENMASK(val - 1, 0) | BIT(ARMV8_PMU_CYCLE_IDX);
+ return GENMASK(n - 1, 0) | BIT(ARMV8_PMU_CYCLE_IDX);
}
static void kvm_pmc_enable_perf_event(struct kvm_pmc *pmc)
--
2.55.0