[PATCH 7/9] KVM: arm64: PMU: Allow ID_AA64DFR0_EL1.PMUver to be set from userspace

Marc Zyngier maz at kernel.org
Wed Aug 10 02:27:27 PDT 2022


On Wed, 10 Aug 2022 08:08:06 +0100,
Oliver Upton <oliver.upton at linux.dev> wrote:
> 
> Hi Marc,
> 
> On Fri, Aug 05, 2022 at 02:58:11PM +0100, Marc Zyngier wrote:
> > Allow userspace to write ID_AA64DFR0_EL1, on the condition that only
> > the PMUver field can be altered and be at most the one that was
> > initially computed for the guest.
> 
> As DFR0_EL1 is exposed to userspace, isn't a ->set_user() hook required
> for it as well?

Hmm. Yes, absolutely. Which is really annoying. It also pushed me to
have a look at what PMUv3p5 means for AArch32, and it is utter
nonsense...

Here's what the spec says about PMEVCNTR<n>:

<quote>
If FEAT_PMUv3p5 is implemented, the event counter is 64 bits and only
the least-significant part of the event counter is accessible in
AArch32 state:
- Reads from PMEVCNTR<n> return bits [31:0] of the counter.
- Writes to PMEVCNTR<n> update bits [31:0] and leave bits [63:32] unchanged.
- There is no means to access bits [63:32] directly from AArch32 state
</quote>

But PMCR.LP does exist! You just can't make any reasonable use of it.
Yet another reason to want AArch32 dead.

> 
> > Signed-off-by: Marc Zyngier <maz at kernel.org>
> > ---
> >  arch/arm64/kvm/sys_regs.c | 35 ++++++++++++++++++++++++++++++++++-
> >  1 file changed, 34 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> > index 55451f49017c..c0595f31dab8 100644
> > --- a/arch/arm64/kvm/sys_regs.c
> > +++ b/arch/arm64/kvm/sys_regs.c
> > @@ -1236,6 +1236,38 @@ static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
> >  	return 0;
> >  }
> >  
> > +static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
> > +			       const struct sys_reg_desc *rd,
> > +			       u64 val)
> > +{
> > +	u8 pmuver, host_pmuver;
> > +
> > +	host_pmuver = kvm_arm_pmu_get_host_pmuver();
> > +
> > +	/*
> > +	 * Allow AA64DFR0_EL1.PMUver to be set from userspace as long
> > +	 * as it doesn't promise more than what the HW gives us. We
> > +	 * don't allow an IMPDEF PMU though.
> > +	 */
> > +	pmuver = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64DFR0_PMUVER), val);
> > +	if (pmuver == ID_AA64DFR0_PMUVER_IMP_DEF || pmuver > host_pmuver)
> > +		return -EINVAL;
> > +
> > +	/* We already have a PMU, don't try to disable it... */
> > +	if (kvm_vcpu_has_pmu(vcpu) && pmuver == 0)
> > +		return -EINVAL;
> > +
> > +	/* We can only differ with PMUver, and anything else is an error */
> > +	val ^= read_id_reg(vcpu, rd, false);
> > +	val &= ~(0xFUL << ID_AA64DFR0_PMUVER_SHIFT);
> 
> nit: ~ARM64_FEATURE_MASK(ID_AA64DFR0_PMUVER)

Good point.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.



More information about the linux-arm-kernel mailing list