Re: [PATCH v3 1/3] arm64: cpufeature: Extract capped fields
On 02/01/2020 12:39, Andrew Murray wrote: When emulating ID registers there is often a need to cap the version bits of a feature such that the guest will not use features that do not yet exist. Let's add a helper that extracts a field and caps the version to a given value. Signed-off-by: Andrew Murray Reviewed-by: Suzuki K Poulose ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Re: [PATCH v2 02/18] arm64: KVM: reset E2PB correctly in MDCR_EL2 when exiting the guest(VHE)
On Tue, Dec 24, 2019 at 10:29:50AM +, Andrew Murray wrote: > On Sat, Dec 21, 2019 at 01:12:14PM +, Marc Zyngier wrote: > > On Fri, 20 Dec 2019 14:30:09 + > > Andrew Murray wrote: > > > > > From: Sudeep Holla > > > > > > On VHE systems, the reset value for MDCR_EL2.E2PB=b00 which defaults > > > to profiling buffer using the EL2 stage 1 translations. > > > > Does the reset value actually matter here? I don't see it being > > specific to VHE systems, and all we're trying to achieve is to restore > > the SPE configuration to a state where it can be used by the host. > > > > > However if the > > > guest are allowed to use profiling buffers changing E2PB settings, we > > > > How can the guest be allowed to change E2PB settings? Or do you mean > > here that allowing the guest to use SPE will mandate changes of the > > E2PB settings, and that we'd better restore the hypervisor state once > > we exit? > > > > > need to ensure we resume back MDCR_EL2.E2PB=b00. Currently we just > > > do bitwise '&' with MDCR_EL2_E2PB_MASK which will retain the value. > > > > > > So fix it by clearing all the bits in E2PB. > > > > > > Signed-off-by: Sudeep Holla > > > Signed-off-by: Andrew Murray > > > --- > > > arch/arm64/kvm/hyp/switch.c | 4 +--- > > > 1 file changed, 1 insertion(+), 3 deletions(-) > > > > > > diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c > > > index 72fbbd86eb5e..250f13910882 100644 > > > --- a/arch/arm64/kvm/hyp/switch.c > > > +++ b/arch/arm64/kvm/hyp/switch.c > > > @@ -228,9 +228,7 @@ void deactivate_traps_vhe_put(void) > > > { > > > u64 mdcr_el2 = read_sysreg(mdcr_el2); > > > > > > - mdcr_el2 &= MDCR_EL2_HPMN_MASK | > > > - MDCR_EL2_E2PB_MASK << MDCR_EL2_E2PB_SHIFT | > > > - MDCR_EL2_TPMS; > > > + mdcr_el2 &= MDCR_EL2_HPMN_MASK | MDCR_EL2_TPMS; > > > > > > write_sysreg(mdcr_el2, mdcr_el2); > > > > > > > I'm OK with this change, but I believe the commit message could use > > some tidying up. > > No problem, I'll update the commit message. This is my new description: arm64: KVM: reset E2PB correctly in MDCR_EL2 when exiting the guest (VHE) Upon leaving the guest on VHE systems we currently preserve the value of MDCR_EL2.E2PB. This register determines if the SPE profiling buffer controls are trapped and which translation regime they use. In order to permit guest access to SPE we may use a different translation regime whilst the vCPU is scheduled - therefore let's ensure that upon leaving the guest we set E2PB back to the value expected by the host (b00). For nVHE systems we already explictly set E2PB back to the expected value of 0b11 in __deactivate_traps_nvhe. Thanks, Andrew Murray > > Thanks, > > Andrew Murray > > > > > Thanks, > > > > M. > > -- > > Jazz is not dead. It just smells funny... > ___ > kvmarm mailing list > kvmarm@lists.cs.columbia.edu > https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v3 0/3] arm64: perf: Add support for ARMv8.5-PMU 64-bit counters
At present ARMv8 event counters are limited to 32-bits, though by using the CHAIN event it's possible to combine adjacent counters to achieve 64-bits. The perf config1:0 bit can be set to use such a configuration. With the introduction of ARMv8.5-PMU support, all event counters can now be used as 64-bit counters. Let's add support for 64-bit event counters. As KVM doesn't yet support 64-bit event counters, we also trap and emulate the Debug Feature Registers to limit the PMU version a guest sees to PMUv3 for ARMv8.4. Tested by running the following perf command on both guest and host and ensuring that the figures are very similar: perf stat -e armv8_pmuv3/inst_retired,long=1/ \ -e armv8_pmuv3/inst_retired,long=0/ -e cycles Changes since v2: - Rebased onto v5.5-rc4 - Mask 'cap' value to 'width' in cpuid_feature_cap_signed_field_width Changes since v1: - Rebased onto v5.5-rc1 Andrew Murray (3): arm64: cpufeature: Extract capped fields KVM: arm64: limit PMU version to ARMv8.4 arm64: perf: Add support for ARMv8.5-PMU 64-bit counters arch/arm64/include/asm/cpufeature.h | 16 ++ arch/arm64/include/asm/perf_event.h | 3 +- arch/arm64/include/asm/sysreg.h | 4 ++ arch/arm64/kernel/perf_event.c | 86 +++-- arch/arm64/kvm/sys_regs.c | 36 +++- include/linux/perf/arm_pmu.h| 1 + 6 files changed, 126 insertions(+), 20 deletions(-) -- 2.21.0 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v3 1/3] arm64: cpufeature: Extract capped fields
When emulating ID registers there is often a need to cap the version bits of a feature such that the guest will not use features that do not yet exist. Let's add a helper that extracts a field and caps the version to a given value. Signed-off-by: Andrew Murray --- arch/arm64/include/asm/cpufeature.h | 16 1 file changed, 16 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 4261d55e8506..1462fd1101e3 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -447,6 +447,22 @@ cpuid_feature_extract_unsigned_field(u64 features, int field) return cpuid_feature_extract_unsigned_field_width(features, field, 4); } +static inline u64 __attribute_const__ +cpuid_feature_cap_signed_field_width(u64 features, int field, int width, +s64 cap) +{ + s64 val = cpuid_feature_extract_signed_field_width(features, field, + width); + u64 mask = GENMASK_ULL(field + width - 1, field); + + if (val > cap) { + features &= ~mask; + features |= (cap << field) & mask; + } + + return features; +} + static inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp) { return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift); -- 2.21.0 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
[PATCH v3 3/3] arm64: perf: Add support for ARMv8.5-PMU 64-bit counters
At present ARMv8 event counters are limited to 32-bits, though by using the CHAIN event it's possible to combine adjacent counters to achieve 64-bits. The perf config1:0 bit can be set to use such a configuration. With the introduction of ARMv8.5-PMU support, all event counters can now be used as 64-bit counters. Let's enable 64-bit event counters where support exists. Unless the user sets config1:0 we will adjust the counter value such that it overflows upon 32-bit overflow. This follows the same behaviour as the cycle counter which has always been (and remains) 64-bits. Signed-off-by: Andrew Murray Reviewed-by: Suzuki K Poulose --- arch/arm64/include/asm/perf_event.h | 3 +- arch/arm64/kernel/perf_event.c | 86 +++-- include/linux/perf/arm_pmu.h| 1 + 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 2bdbc79bbd01..e7765b62c712 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -176,9 +176,10 @@ #define ARMV8_PMU_PMCR_X (1 << 4) /* Export to ETM */ #define ARMV8_PMU_PMCR_DP (1 << 5) /* Disable CCNT if non-invasive debug*/ #define ARMV8_PMU_PMCR_LC (1 << 6) /* Overflow on 64 bit cycle counter */ +#define ARMV8_PMU_PMCR_LP (1 << 7) /* Long event counter enable */ #defineARMV8_PMU_PMCR_N_SHIFT 11 /* Number of counters supported */ #defineARMV8_PMU_PMCR_N_MASK 0x1f -#defineARMV8_PMU_PMCR_MASK 0x7f /* Mask for writable bits */ +#defineARMV8_PMU_PMCR_MASK 0xff /* Mask for writable bits */ /* * PMOVSR: counters overflow flag status reg diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index e40b65645c86..4e27f90bb89e 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -285,6 +285,17 @@ static struct attribute_group armv8_pmuv3_format_attr_group = { #defineARMV8_IDX_COUNTER_LAST(cpu_pmu) \ (ARMV8_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1) + +/* + * We unconditionally enable ARMv8.5-PMU long event counter support + * (64-bit events) where supported. Indicate if this arm_pmu has long + * event counter support. + */ +static bool armv8pmu_has_long_event(struct arm_pmu *cpu_pmu) +{ + return (cpu_pmu->pmuver > ID_DFR0_EL1_PMUVER_8_4); +} + /* * We must chain two programmable counters for 64 bit events, * except when we have allocated the 64bit cycle counter (for CPU @@ -294,9 +305,11 @@ static struct attribute_group armv8_pmuv3_format_attr_group = { static inline bool armv8pmu_event_is_chained(struct perf_event *event) { int idx = event->hw.idx; + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); return !WARN_ON(idx < 0) && armv8pmu_event_is_64bit(event) && + !armv8pmu_has_long_event(cpu_pmu) && (idx != ARMV8_IDX_CYCLE_COUNTER); } @@ -345,7 +358,7 @@ static inline void armv8pmu_select_counter(int idx) isb(); } -static inline u32 armv8pmu_read_evcntr(int idx) +static inline u64 armv8pmu_read_evcntr(int idx) { armv8pmu_select_counter(idx); return read_sysreg(pmxevcntr_el0); @@ -362,6 +375,44 @@ static inline u64 armv8pmu_read_hw_counter(struct perf_event *event) return val; } +/* + * The cycle counter is always a 64-bit counter. When ARMV8_PMU_PMCR_LP + * is set the event counters also become 64-bit counters. Unless the + * user has requested a long counter (attr.config1) then we want to + * interrupt upon 32-bit overflow - we achieve this by applying a bias. + */ +static bool armv8pmu_event_needs_bias(struct perf_event *event) +{ + struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); + struct hw_perf_event *hwc = &event->hw; + int idx = hwc->idx; + + if (armv8pmu_event_is_64bit(event)) + return false; + + if (armv8pmu_has_long_event(cpu_pmu) || + idx == ARMV8_IDX_CYCLE_COUNTER) + return true; + + return false; +} + +static u64 armv8pmu_bias_long_counter(struct perf_event *event, u64 value) +{ + if (armv8pmu_event_needs_bias(event)) + value |= GENMASK(63, 32); + + return value; +} + +static u64 armv8pmu_unbias_long_counter(struct perf_event *event, u64 value) +{ + if (armv8pmu_event_needs_bias(event)) + value &= ~GENMASK(63, 32); + + return value; +} + static u64 armv8pmu_read_counter(struct perf_event *event) { struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu); @@ -377,10 +428,10 @@ static u64 armv8pmu_read_counter(struct perf_event *event) else value = armv8pmu_read_hw_counter(event); - return value; + return armv8pmu_unbias_long_counter(event, value); } -static inline void armv8pmu_write_evcntr(int idx, u32 value) +static inline void armv8pmu_write_evcntr(int idx, u64 value) {
[PATCH v3 2/3] KVM: arm64: limit PMU version to ARMv8.4
ARMv8.5-PMU introduces 64-bit event counters, however KVM doesn't yet support this. Let's trap the Debug Feature Registers in order to limit PMUVer/PerfMon in the Debug Feature Registers to PMUv3 for ARMv8.4. Signed-off-by: Andrew Murray Reviewed-by: Suzuki K Poulose --- arch/arm64/include/asm/sysreg.h | 4 arch/arm64/kvm/sys_regs.c | 36 +++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 6e919fafb43d..1b74f275a115 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -672,6 +672,10 @@ #define ID_AA64DFR0_TRACEVER_SHIFT 4 #define ID_AA64DFR0_DEBUGVER_SHIFT 0 +#define ID_DFR0_PERFMON_SHIFT 24 + +#define ID_DFR0_EL1_PMUVER_8_4 5 + #define ID_ISAR5_RDM_SHIFT 24 #define ID_ISAR5_CRC32_SHIFT 16 #define ID_ISAR5_SHA2_SHIFT12 diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 9f2165937f7d..61b984d934d1 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -668,6 +668,37 @@ static bool pmu_access_event_counter_el0_disabled(struct kvm_vcpu *vcpu) return check_pmu_access_disabled(vcpu, ARMV8_PMU_USERENR_ER | ARMV8_PMU_USERENR_EN); } +static bool access_id_aa64dfr0_el1(struct kvm_vcpu *vcpu, + struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + if (p->is_write) + return write_to_read_only(vcpu, p, rd); + + /* Limit guests to PMUv3 for ARMv8.4 */ + p->regval = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1); + p->regval = cpuid_feature_cap_signed_field_width(p->regval, + ID_AA64DFR0_PMUVER_SHIFT, + 4, ID_DFR0_EL1_PMUVER_8_4); + + return p->regval; +} + +static bool access_id_dfr0_el1(struct kvm_vcpu *vcpu, struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + if (p->is_write) + return write_to_read_only(vcpu, p, rd); + + /* Limit guests to PMUv3 for ARMv8.4 */ + p->regval = read_sanitised_ftr_reg(SYS_ID_DFR0_EL1); + p->regval = cpuid_feature_cap_signed_field_width(p->regval, + ID_DFR0_PERFMON_SHIFT, + 4, ID_DFR0_EL1_PMUVER_8_4); + + return p->regval; +} + static bool access_pmcr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, const struct sys_reg_desc *r) { @@ -1409,7 +1440,8 @@ static const struct sys_reg_desc sys_reg_descs[] = { /* CRm=1 */ ID_SANITISED(ID_PFR0_EL1), ID_SANITISED(ID_PFR1_EL1), - ID_SANITISED(ID_DFR0_EL1), + { SYS_DESC(SYS_ID_DFR0_EL1), access_id_dfr0_el1 }, + ID_HIDDEN(ID_AFR0_EL1), ID_SANITISED(ID_MMFR0_EL1), ID_SANITISED(ID_MMFR1_EL1), @@ -1448,7 +1480,7 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_UNALLOCATED(4,7), /* CRm=5 */ - ID_SANITISED(ID_AA64DFR0_EL1), + { SYS_DESC(SYS_ID_AA64DFR0_EL1), access_id_aa64dfr0_el1 }, ID_SANITISED(ID_AA64DFR1_EL1), ID_UNALLOCATED(5,2), ID_UNALLOCATED(5,3), -- 2.21.0 ___ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm