[PATCH 3/8] KVM: arm64: Refuse illegal KVM_ARM_VCPU_PMU_V3 at reset time

Alexandru Elisei alexandru.elisei at arm.com
Thu Nov 26 10:49:37 EST 2020


Hi Marc,

On 11/26/20 3:25 PM, Marc Zyngier wrote:
> Hi Alex,
>
> On 2020-11-26 14:59, Alexandru Elisei wrote:
>> Hi Marc,
>>
>> On 11/13/20 6:25 PM, Marc Zyngier wrote:
>>> We accept to configure a PMU when a vcpu is created, even if the
>>> HW (or the host) doesn't support it. This results in failures
>>> when attributes get set, which is a bit odd as we should have
>>> failed the vcpu creation the first place.
>>>
>>> Move the check to the point where we check the vcpu feature set,
>>> and fail early if we cannot support a PMU. This further simplifies
>>> the attribute handling.
>>>
>>> Signed-off-by: Marc Zyngier <maz at kernel.org>
>>> ---
>>>  arch/arm64/kvm/pmu-emul.c | 4 ++--
>>>  arch/arm64/kvm/reset.c    | 4 ++++
>>>  2 files changed, 6 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/kvm/pmu-emul.c b/arch/arm64/kvm/pmu-emul.c
>>> index e7e3b4629864..200f2a0d8d17 100644
>>> --- a/arch/arm64/kvm/pmu-emul.c
>>> +++ b/arch/arm64/kvm/pmu-emul.c
>>> @@ -913,7 +913,7 @@ static bool pmu_irq_is_valid(struct kvm *kvm, int irq)
>>>
>>>  int kvm_arm_pmu_v3_set_attr(struct kvm_vcpu *vcpu, struct kvm_device_attr *attr)
>>>  {
>>> -    if (!kvm_arm_support_pmu_v3() || !kvm_vcpu_has_pmu(vcpu))
>>> +    if (!kvm_vcpu_has_pmu(vcpu))
>>>          return -ENODEV;
>>>
>>>      if (vcpu->arch.pmu.created)
>>> @@ -1034,7 +1034,7 @@ int kvm_arm_pmu_v3_has_attr(struct kvm_vcpu *vcpu,
>>> struct kvm_device_attr *attr)
>>>      case KVM_ARM_VCPU_PMU_V3_IRQ:
>>>      case KVM_ARM_VCPU_PMU_V3_INIT:
>>>      case KVM_ARM_VCPU_PMU_V3_FILTER:
>>> -        if (kvm_arm_support_pmu_v3() && kvm_vcpu_has_pmu(vcpu))
>>> +        if (kvm_vcpu_has_pmu(vcpu))
>>>              return 0;
>>>      }
>>>
>>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>>> index 74ce92a4988c..3e772ea4e066 100644
>>> --- a/arch/arm64/kvm/reset.c
>>> +++ b/arch/arm64/kvm/reset.c
>>> @@ -285,6 +285,10 @@ int kvm_reset_vcpu(struct kvm_vcpu *vcpu)
>>>              pstate = VCPU_RESET_PSTATE_EL1;
>>>          }
>>>
>>> +        if (kvm_vcpu_has_pmu(vcpu) && !kvm_arm_support_pmu_v3()) {
>>> +            ret = -EINVAL;
>>> +            goto out;
>>> +        }
>>
>> This looks correct, but right at the beginning of the function, before this
>> non-preemptible section, we do kvm_pmu_vcpu_reset(), which is wrong for several
>> reasons:
>>
>> - we don't check if the feature flag is set
>> - we don't check if the hardware supports a PMU
>> - kvm_pmu_vcpu_reset() relies on __vcpu_sys_reg(vcpu, PMCR_EL0), which is set in
>> kvm_reset_sys_regs() below when the VCPU is initialized.
>
> I'm not sure it actually matters. Here's my rational:
>
> - PMU support not compiled in: no problem!
> - PMU support compiled in, but no HW PMU: we just reset some state to 0, no harm
> done
> - HW PMU, but no KVM PMU for this vcpu: same thing
> - HW PMU, and KVM PMU: we do the right thing!
>
> Am I missing anything?

I don't think so, it also looks harmless to me. When it's called on the VCPU init
path, there will be no perf_events, so that part will be skipped. On the reset
path, PMCR_EL0.N will have been initialized so we end up with the correct number
of counters. In both cases vcpu->arch.pmu.chained will be zero'ed

But I find it strange to reset the PMU before doing any checks and before setting
the VCPU register value it reads.

I am thinking that even though at the moment it's harmless, in the future the
function might change and I don't think whoever modifies it will expect the
function to be called like this. But I guess if we're vigilant enough we can
prevent that hypothetical situation from happening.

Thanks,
Alex



More information about the linux-arm-kernel mailing list