[PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
From: Shannon ZhaoThese kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER which is mapped to PMEVTYPERn or PMCCFILTR. The access handler translates all aarch32 register offsets to aarch64 ones and uses vcpu_sys_reg() to access their values to avoid taking care of big endian. When writing to these registers, create a perf_event for the selected event type. Signed-off-by: Shannon Zhao --- arch/arm64/kvm/sys_regs.c | 154 +- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index e043224..c52ff15 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p, return true; } +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx) +{ + u64 pmcr, val; + + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0); + val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK; + if (idx >= val && idx != ARMV8_CYCLE_IDX) + return false; + + return true; +} + +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *r) +{ + u64 idx, reg; + + if (r->CRn == 9) { + /* PMXEVTYPER_EL0 */ + reg = 0; + } else { + if (!p->is_aarch32) { + /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */ + reg = r->reg; + } else { + if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) { + reg = PMCCFILTR_EL0; + } else { + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7); + reg += PMEVTYPER0_EL0; + } + } + } + + switch (reg) { + case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0: + idx = reg - PMEVTYPER0_EL0; + break; + case PMCCFILTR_EL0: + idx = ARMV8_CYCLE_IDX; + break; + default: + /* PMXEVTYPER_EL0 */ + idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK; + if (!pmu_counter_idx_valid(vcpu, idx)) + return true; + + reg = (idx == ARMV8_CYCLE_IDX) ? PMCCFILTR_EL0 +: PMEVTYPER0_EL0 + idx; + break; + } + + if (p->is_write) { + kvm_pmu_set_counter_event_type(vcpu, p->regval, idx); + vcpu_sys_reg(vcpu, reg) = p->regval & ARMV8_EVTYPE_MASK; + } else { + p->regval = vcpu_sys_reg(vcpu, reg) & ARMV8_EVTYPE_MASK; + } + + return true; +} + /* Silly macro to expand the DBG{BCR,BVR,WVR,WCR}n_EL1 registers in one go */ #define DBG_BCR_BVR_WCR_WVR_EL1(n) \ /* DBGBVRn_EL1 */ \ @@ -519,6 +581,13 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p, { Op0(0b10), Op1(0b000), CRn(0b), CRm((n)), Op2(0b111), \ trap_wcr, reset_wcr, n, 0, get_wcr, set_wcr } +/* Macro to expand the PMEVTYPERn_EL0 register */ +#define PMU_PMEVTYPER_EL0(n) \ + /* PMEVTYPERn_EL0 */\ + { Op0(0b11), Op1(0b011), CRn(0b1110), \ + CRm((0b1100 | (((n) >> 3) & 0x3))), Op2(((n) & 0x7)), \ + access_pmu_evtyper, reset_unknown, (PMEVTYPER0_EL0 + n), } + /* * Architected system registers. * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2 @@ -715,7 +784,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { trap_raz_wi }, /* PMXEVTYPER_EL0 */ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b001), - trap_raz_wi }, + access_pmu_evtyper }, /* PMXEVCNTR_EL0 */ { Op0(0b11), Op1(0b011), CRn(0b1001), CRm(0b1101), Op2(0b010), trap_raz_wi }, @@ -733,6 +802,45 @@ static const struct sys_reg_desc sys_reg_descs[] = { { Op0(0b11), Op1(0b011), CRn(0b1101), CRm(0b), Op2(0b011), NULL, reset_unknown, TPIDRRO_EL0 }, + /* PMEVTYPERn_EL0 */ + PMU_PMEVTYPER_EL0(0), + PMU_PMEVTYPER_EL0(1), + PMU_PMEVTYPER_EL0(2), + PMU_PMEVTYPER_EL0(3), + PMU_PMEVTYPER_EL0(4), + PMU_PMEVTYPER_EL0(5), + PMU_PMEVTYPER_EL0(6), + PMU_PMEVTYPER_EL0(7), + PMU_PMEVTYPER_EL0(8), + PMU_PMEVTYPER_EL0(9), + PMU_PMEVTYPER_EL0(10), + PMU_PMEVTYPER_EL0(11), + PMU_PMEVTYPER_EL0(12), + PMU_PMEVTYPER_EL0(13), + PMU_PMEVTYPER_EL0(14), + PMU_PMEVTYPER_EL0(15), + PMU_PMEVTYPER_EL0(16),
Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
On 15/12/15 08:49, Shannon Zhao wrote: > From: Shannon Zhao> > These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER > which is mapped to PMEVTYPERn or PMCCFILTR. > > The access handler translates all aarch32 register offsets to aarch64 > ones and uses vcpu_sys_reg() to access their values to avoid taking care > of big endian. > > When writing to these registers, create a perf_event for the selected > event type. > > Signed-off-by: Shannon Zhao > --- > arch/arm64/kvm/sys_regs.c | 154 > +- > 1 file changed, 152 insertions(+), 2 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index e043224..c52ff15 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct > sys_reg_params *p, > return true; > } > > +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx) > +{ > + u64 pmcr, val; > + > + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0); > + val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK; > + if (idx >= val && idx != ARMV8_CYCLE_IDX) > + return false; > + > + return true; > +} > + > +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params > *p, > +const struct sys_reg_desc *r) > +{ > + u64 idx, reg; > + > + if (r->CRn == 9) { > + /* PMXEVTYPER_EL0 */ > + reg = 0; > + } else { > + if (!p->is_aarch32) { > + /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */ > + reg = r->reg; > + } else { > + if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) { > + reg = PMCCFILTR_EL0; > + } else { > + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7); Shouldn't that be "((r->CRm & 3) << 3) | (r->Op2 & 7)"? Otherwise reg is always 0. Thanks, M. -- Jazz is not dead. It just smells funny... -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v7 08/19] KVM: ARM64: Add access handler for event typer register
On 15/12/15 08:49, Shannon Zhao wrote: > From: Shannon Zhao> > These kind of registers include PMEVTYPERn, PMCCFILTR and PMXEVTYPER > which is mapped to PMEVTYPERn or PMCCFILTR. > > The access handler translates all aarch32 register offsets to aarch64 > ones and uses vcpu_sys_reg() to access their values to avoid taking care > of big endian. > > When writing to these registers, create a perf_event for the selected > event type. > > Signed-off-by: Shannon Zhao > --- > arch/arm64/kvm/sys_regs.c | 154 > +- > 1 file changed, 152 insertions(+), 2 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index e043224..c52ff15 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -504,6 +504,68 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct > sys_reg_params *p, > return true; > } > > +static inline bool pmu_counter_idx_valid(struct kvm_vcpu *vcpu, u64 idx) > +{ > + u64 pmcr, val; > + > + pmcr = vcpu_sys_reg(vcpu, PMCR_EL0); > + val = (pmcr >> ARMV8_PMCR_N_SHIFT) & ARMV8_PMCR_N_MASK; > + if (idx >= val && idx != ARMV8_CYCLE_IDX) > + return false; > + > + return true; > +} > + > +static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params > *p, > +const struct sys_reg_desc *r) > +{ > + u64 idx, reg; > + > + if (r->CRn == 9) { > + /* PMXEVTYPER_EL0 */ > + reg = 0; > + } else { > + if (!p->is_aarch32) { > + /* PMEVTYPERn_EL0 or PMCCFILTR_EL0 */ > + reg = r->reg; > + } else { > + if (r->CRn == 14 && r->CRm == 15 && r->Op2 == 7) { > + reg = PMCCFILTR_EL0; > + } else { > + reg = ((r->CRm & 3) << 3) & (r->Op2 & 7); > + reg += PMEVTYPER0_EL0; > + } > + } > + } > + > + switch (reg) { > + case PMEVTYPER0_EL0 ... PMEVTYPER30_EL0: > + idx = reg - PMEVTYPER0_EL0; > + break; > + case PMCCFILTR_EL0: > + idx = ARMV8_CYCLE_IDX; > + break; > + default: > + /* PMXEVTYPER_EL0 */ > + idx = vcpu_sys_reg(vcpu, PMSELR_EL0) & ARMV8_COUNTER_MASK; > + if (!pmu_counter_idx_valid(vcpu, idx)) > + return true; Shouldn't you check the validity of the index in the first case as well? Thanks, M. -- Jazz is not dead. It just smells funny... -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html