Skip to content

Commit b112c84

Browse files
huangweiMarc Zyngier
authored andcommitted
KVM: arm64: Fix the issues when guest PMCCFILTR is configured
KVM calls kvm_pmu_set_counter_event_type() when PMCCFILTR is configured. But this function can't deals with PMCCFILTR correctly because the evtCount bits of PMCCFILTR, which is reserved 0, conflits with the SW_INCR event type of other PMXEVTYPER<n> registers. To fix it, when eventsel == 0, this function shouldn't return immediately; instead it needs to check further if select_idx is ARMV8_PMU_CYCLE_IDX. Another issue is that KVM shouldn't copy the eventsel bits of PMCCFILTER blindly to attr.config. Instead it ought to convert the request to the "cpu cycle" event type (i.e. 0x11). To support this patch and to prevent duplicated definitions, a limited set of ARMv8 perf event types were relocated from perf_event.c to asm/perf_event.h. Cc: stable@vger.kernel.org # 4.6+ Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Wei Huang <wei@redhat.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 9e3f7a2 commit b112c84

3 files changed

Lines changed: 15 additions & 13 deletions

File tree

arch/arm64/include/asm/perf_event.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,15 @@
4646
#define ARMV8_PMU_EVTYPE_MASK 0xc800ffff /* Mask for writable bits */
4747
#define ARMV8_PMU_EVTYPE_EVENT 0xffff /* Mask for EVENT bits */
4848

49-
#define ARMV8_PMU_EVTYPE_EVENT_SW_INCR 0 /* Software increment event */
49+
/*
50+
* PMUv3 event types: required events
51+
*/
52+
#define ARMV8_PMUV3_PERFCTR_SW_INCR 0x00
53+
#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL 0x03
54+
#define ARMV8_PMUV3_PERFCTR_L1D_CACHE 0x04
55+
#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED 0x10
56+
#define ARMV8_PMUV3_PERFCTR_CPU_CYCLES 0x11
57+
#define ARMV8_PMUV3_PERFCTR_BR_PRED 0x12
5058

5159
/*
5260
* Event filters for PMUv3

arch/arm64/kernel/perf_event.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,9 @@
3131

3232
/*
3333
* ARMv8 PMUv3 Performance Events handling code.
34-
* Common event types.
34+
* Common event types (some are defined in asm/perf_event.h).
3535
*/
3636

37-
/* Required events. */
38-
#define ARMV8_PMUV3_PERFCTR_SW_INCR 0x00
39-
#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_REFILL 0x03
40-
#define ARMV8_PMUV3_PERFCTR_L1D_CACHE 0x04
41-
#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED 0x10
42-
#define ARMV8_PMUV3_PERFCTR_CPU_CYCLES 0x11
43-
#define ARMV8_PMUV3_PERFCTR_BR_PRED 0x12
44-
4537
/* At least one of the following is required. */
4638
#define ARMV8_PMUV3_PERFCTR_INST_RETIRED 0x08
4739
#define ARMV8_PMUV3_PERFCTR_INST_SPEC 0x1B

virt/kvm/arm/pmu.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ void kvm_pmu_software_increment(struct kvm_vcpu *vcpu, u64 val)
305305
continue;
306306
type = vcpu_sys_reg(vcpu, PMEVTYPER0_EL0 + i)
307307
& ARMV8_PMU_EVTYPE_EVENT;
308-
if ((type == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
308+
if ((type == ARMV8_PMUV3_PERFCTR_SW_INCR)
309309
&& (enable & BIT(i))) {
310310
reg = vcpu_sys_reg(vcpu, PMEVCNTR0_EL0 + i) + 1;
311311
reg = lower_32_bits(reg);
@@ -379,7 +379,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
379379
eventsel = data & ARMV8_PMU_EVTYPE_EVENT;
380380

381381
/* Software increment event does't need to be backed by a perf event */
382-
if (eventsel == ARMV8_PMU_EVTYPE_EVENT_SW_INCR)
382+
if (eventsel == ARMV8_PMUV3_PERFCTR_SW_INCR &&
383+
select_idx != ARMV8_PMU_CYCLE_IDX)
383384
return;
384385

385386
memset(&attr, 0, sizeof(struct perf_event_attr));
@@ -391,7 +392,8 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
391392
attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
392393
attr.exclude_hv = 1; /* Don't count EL2 events */
393394
attr.exclude_host = 1; /* Don't count host events */
394-
attr.config = eventsel;
395+
attr.config = (select_idx == ARMV8_PMU_CYCLE_IDX) ?
396+
ARMV8_PMUV3_PERFCTR_CPU_CYCLES : eventsel;
395397

396398
counter = kvm_pmu_get_counter_value(vcpu, select_idx);
397399
/* The initial sample period (overflow count) of an event. */

0 commit comments

Comments
 (0)