[PATCH v8 6/7] KVM: arm64: PMU: Introduce FIXED_COUNTERS_ONLY
Akihiko Odaki
odaki at rsg.ci.i.u-tokyo.ac.jp
Tue Jul 7 04:36:32 PDT 2026
On 2026/07/07 2:58, Oliver Upton wrote:
> On Mon, Jul 06, 2026 at 07:03:29PM +0900, Akihiko Odaki wrote:
>> +1.6 ATTRIBUTE: KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY
>> +------------------------------------------------------
>> +
>> +:Parameters: no additional parameter in kvm_device_attr.addr
>> +
>> +:Returns:
>> +
>> + ======= ==================================================
>> + -EBUSY PMUv3 already initialized, a VCPU has already run,
>> + an event filter has already been set or
>> + a hardware PMU has already been specified
>> + -ENXIO Attempted to get before setting
>> + -ENODEV Attempted to set while PMUv3 not supported
>> + ======= ==================================================
>> +
>> +If set, KVM emulates PMUv3 without programmable event counters. Only fixed
>> +counters are exposed to the guest: the cycle counter today, and the instruction
>> +counter if support for FEAT_PMUv3_ICNTR is added.
>
> Drop the mention of cycle counter and FEAT_PMUv3_ICNTR, I want to avoid
> the argument later down the line when ICNTR support is added to this
> mode.
>
> The expectation is that the VMM discovers the feature set using the ID
> registers just like every other CPU feature. KVM documentation doesn't
> need to describe the architecture.
I'll drop it with the next version.
>
>> +With programmable counters disabled, the VCPU can run on any physical CPU.
>> +This is particularly useful on heterogeneous systems where different hardware
>> +PMUs cover different physical CPUs. All VCPUs in a VM share this attribute.
>
> When this attribute is enabled, the vCPU can run on any physical CPU
> that has a PMU, regardless of the underlying implementation. This
> attribute is VM-scoped.
>
> The documentation is focused on unambiguously representing the UAPI, not
> providing application recommendations.
I agree. I'll use your wording for the next version.
>
>> 2. GROUP: KVM_ARM_VCPU_TIMER_CTRL
>> =================================
>>
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 1c13bfa2d38a..39a1a1e412e6 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -437,6 +437,7 @@ enum {
>> #define KVM_ARM_VCPU_PMU_V3_FILTER 2
>> #define KVM_ARM_VCPU_PMU_V3_SET_PMU 3
>> #define KVM_ARM_VCPU_PMU_V3_SET_NR_COUNTERS 4
>> +#define KVM_ARM_VCPU_PMU_V3_FIXED_COUNTERS_ONLY 5
>> #define KVM_ARM_VCPU_TIMER_CTRL 1
>> #define KVM_ARM_VCPU_TIMER_IRQ_VTIMER 0
>> #define KVM_ARM_VCPU_TIMER_IRQ_PTIMER 1
>> diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
>> index 40cad183376c..ad9ff4d0d89c 100644
>> --- a/arch/arm64/kvm/pmu-emul.c
>> +++ b/arch/arm64/kvm/pmu-emul.c
>> @@ -1149,11 +1149,13 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
>> arm_pmu = entry->arm_pmu;
>> if (arm_pmu->pmu.type == pmu_id) {
>> if (kvm_vm_has_ran_once(kvm) ||
>> + kvm_pmu_fixed_counters_only(kvm) ||
>> (kvm->arch.pmu_filter && kvm->arch.arm_pmu != arm_pmu)) {
>> ret = -EBUSY;
>> break;
>> }
>>
>> + set_bit(KVM_ARCH_FLAG_PMU_V3_EXPLICIT, &kvm->arch.flags);
>
> Why is this flag necessary? kvm->arch.arm_pmu is NULL if no PMU
> implementation was selected by userspace.
The explicit flag is there because kvm->arch.arm_pmu is also populated
by KVM_ARM_VCPU_INIT through kvm_arm_set_default_pmu(). I wanted to keep
allowing userspace to enable FIXED_COUNTERS_ONLY after that default PMU
selection, as long as PMUv3 has not been initialized and the VM has not
run, while still rejecting it after an explicit SET_PMU.
>
>> kvm_arm_set_pmu(kvm, arm_pmu);
>> cpumask_copy(kvm->arch.supported_cpus, &arm_pmu->supported_cpus);
>> ret = 0;
>> @@ -1164,6 +1166,22 @@ static int kvm_arm_pmu_v3_set_pmu(struct kvm_vcpu *vcpu, int pmu_id)
>> return ret;
>> }
>>
>> +static int kvm_arm_pmu_v3_set_pmu_fixed_counters_only(struct kvm_vcpu *vcpu)
>> +{
>> + struct kvm *kvm = vcpu->kvm;
>> +
>> + lockdep_assert_held(&kvm->arch.config_lock);
>> +
>> + if (kvm_vm_has_ran_once(kvm) || kvm->arch.pmu_filter ||
>> + test_bit(KVM_ARCH_FLAG_PMU_V3_EXPLICIT, &kvm->arch.flags))
>> + return -EBUSY;
>> +
>> + set_bit(KVM_ARCH_FLAG_PMU_V3_FIXED_COUNTERS_ONLY, &kvm->arch.flags);
>> + kvm_arm_set_nr_counters(kvm, 0);
>> +
>> + return 0;
>> +}
>> +
>> static int kvm_arm_pmu_v3_set_nr_counters(struct kvm_vcpu *vcpu, unsigned int n)
>> {
>> struct kvm *kvm = vcpu->kvm;
>> @@ -1238,7 +1256,7 @@ int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>> filter.action != KVM_PMU_EVENT_DENY))
>> return -EINVAL;
>>
>> - if (kvm_vm_has_ran_once(kvm))
>> + if (kvm_vm_has_ran_once(kvm) || kvm_pmu_fixed_counters_only(kvm))
>
> There's no reason for doing this, just let userspace create an event
> filter. Even with the current PMU implementation it's possible that the
> fixed cycle counter gets filtered.
This check was added as the consequence of the discussion in the
following thread:
https://lore.kernel.org/all/327f74e4-78b8-4629-a418-d1d3ba78859f@rsg.ci.i.u-tokyo.ac.jp/
Regards,
Akihiko Odaki
More information about the linux-arm-kernel
mailing list