The number of PMU event counters is indicated in PMCR_EL0.N. For a vCPU with PMUv3 configured, its value will be the same as the host value by default. Userspace can set PMCR_EL0.N for the vCPU to a lower value than the host value using KVM_SET_ONE_REG. However, it is practically unsupported, as reset_pmcr() resets PMCR_EL0.N to the host value on vCPU reset. Change reset_pmcr() to preserve the vCPU's PMCR_EL0.N value on vCPU reset so that userspace can limit the number of the PMU event counter on the vCPU. Signed-off-by: Reiji Watanabe <reijiw@xxxxxxxxxx> --- arch/arm64/kvm/pmu-emul.c | 6 ++++++ arch/arm64/kvm/sys_regs.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c index 24908400e190..937a272b00a5 100644 --- a/arch/arm64/kvm/pmu-emul.c +++ b/arch/arm64/kvm/pmu-emul.c @@ -213,6 +213,12 @@ void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu) for (i = 0; i < ARMV8_PMU_MAX_COUNTERS; i++) pmu->pmc[i].idx = i; + + /* + * Initialize PMCR_EL0 for the vCPU with the host value so that + * the value is available at the very first vCPU reset. + */ + __vcpu_sys_reg(vcpu, PMCR_EL0) = read_sysreg(pmcr_el0); } /** diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4959658b502c..67c1bd39b478 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -637,8 +637,10 @@ static void reset_pmcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) if (!kvm_arm_support_pmu_v3()) return; + /* PMCR_EL0 for the vCPU is set to the host value at vCPU creation. */ + /* Only preserve PMCR_EL0.N, and reset the rest to 0 */ - pmcr = read_sysreg(pmcr_el0) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT); + pmcr = __vcpu_sys_reg(vcpu, r->reg) & (ARMV8_PMU_PMCR_N_MASK << ARMV8_PMU_PMCR_N_SHIFT); if (!kvm_supports_32bit_el0()) pmcr |= ARMV8_PMU_PMCR_LC; -- 2.39.0.314.g84b9a713c41-goog