Subject: [PATCH v5 08/21] KVM: ARM64: Add reset and access handlers for PMXEVTYPER register

From: [email-masked] (Marc Zyngier)
Date: Mon, 07 Dec 2015 13:38:02 +0000

On 03/12/15 06:11, Shannon Zhao wrote:
> From: Shannon Zhao <[email-masked]>
> 
> Since the reset value of PMXEVTYPER is UNKNOWN, use reset_unknown or
> reset_unknown_cp15 for its reset handler. Add access handler which
> emulates writing and reading PMXEVTYPER register. When writing to
> PMXEVTYPER, call kvm_pmu_set_counter_event_type to create a perf_event
> for the selected event type.
> 
> Signed-off-by: Shannon Zhao <[email-masked]>
> ---
>  arch/arm64/kvm/sys_regs.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 42 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index b0a8d88..6967a49 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -473,6 +473,17 @@ static void reset_pmceid(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
>  	vcpu_sys_reg(vcpu, r->reg) = pmceid;
>  }
>  
> +static bool pmu_counter_idx_valid(u64 pmcr, u64 idx)
> +{
> +	u64 val;
> +
> +	val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK;
> +	if (idx >= val && idx != ARMV8_COUNTER_MASK)
> +		return false;
> +
> +	return true;
> +}
> +
>  /* PMU registers accessor. */
>  static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>  			    const struct sys_reg_params *p,
> @@ -482,6 +493,20 @@ static bool access_pmu_regs(struct kvm_vcpu *vcpu,
>  
>  	if (p->is_write) {
>  		switch (r->reg) {
> +		case PMXEVTYPER_EL0: {
> +			u64 idx = vcpu_sys_reg(vcpu, PMSELR_EL0)
> +				  & ARMV8_COUNTER_MASK;
> +
> +			if (!pmu_counter_idx_valid(vcpu_sys_reg(vcpu, PMCR_EL0),
> +						   idx))
> +				break;
> +
> +			val = *vcpu_reg(vcpu, p->Rt);
> +			kvm_pmu_set_counter_event_type(vcpu, val, idx);
> +			vcpu_sys_reg(vcpu, PMXEVTYPER_EL0) = val;
> +			vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + idx) = val;

I'm really confused by this. PMXEVTYPER is not really a register, but
level of indirection between PMEVTYPERn_EL0 and PMCCFILTER_EL0
(depending on PMSELR_EL0.SEL). On its own, it doesn't exist.

Here, you are making PMXEVTYPER_EL0 an actual register, storing the same
value twice (and not handling PMCCFILTER_EL0). It definitely feels
wrong. You should be able to trap it and propagate the access to the
right register, without duplicating the state.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...