Skip to content

Commit 7ff7dfe

Browse files
committed
Merge branch kvm-arm64/pmevtyper-filter into kvmarm/next
* kvm-arm64/pmevtyper-filter: : Fixes to KVM's handling of the PMUv3 exception level filtering bits : : - NSH (count at EL2) and M (count at EL3) should be stateful when the : respective EL is advertised in the ID registers but have no effect on : event counting. : : - NSU and NSK modify the event filtering of EL0 and EL1, respectively. : Though the kernel may not use these bits, other KVM guests might. : Implement these bits exactly as written in the pseudocode if EL3 is : advertised. KVM: arm64: Add PMU event filter bits required if EL3 is implemented KVM: arm64: Make PMEVTYPER<n>_EL0.NSH RES0 if EL2 isn't advertised Signed-off-by: Oliver Upton <[email protected]>
2 parents d47dcb6 + ae8d352 commit 7ff7dfe

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

arch/arm64/kvm/pmu-emul.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,23 @@ static u32 kvm_pmu_event_mask(struct kvm *kvm)
6060
return __kvm_pmu_event_mask(pmuver);
6161
}
6262

63+
u64 kvm_pmu_evtyper_mask(struct kvm *kvm)
64+
{
65+
u64 mask = ARMV8_PMU_EXCLUDE_EL1 | ARMV8_PMU_EXCLUDE_EL0 |
66+
kvm_pmu_event_mask(kvm);
67+
u64 pfr0 = IDREG(kvm, SYS_ID_AA64PFR0_EL1);
68+
69+
if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL2, pfr0))
70+
mask |= ARMV8_PMU_INCLUDE_EL2;
71+
72+
if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL3, pfr0))
73+
mask |= ARMV8_PMU_EXCLUDE_NS_EL0 |
74+
ARMV8_PMU_EXCLUDE_NS_EL1 |
75+
ARMV8_PMU_EXCLUDE_EL3;
76+
77+
return mask;
78+
}
79+
6380
/**
6481
* kvm_pmc_is_64bit - determine if counter is 64bit
6582
* @pmc: counter context
@@ -584,6 +601,7 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
584601
struct perf_event *event;
585602
struct perf_event_attr attr;
586603
u64 eventsel, reg, data;
604+
bool p, u, nsk, nsu;
587605

588606
reg = counter_index_to_evtreg(pmc->idx);
589607
data = __vcpu_sys_reg(vcpu, reg);
@@ -610,13 +628,18 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
610628
!test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
611629
return;
612630

631+
p = data & ARMV8_PMU_EXCLUDE_EL1;
632+
u = data & ARMV8_PMU_EXCLUDE_EL0;
633+
nsk = data & ARMV8_PMU_EXCLUDE_NS_EL1;
634+
nsu = data & ARMV8_PMU_EXCLUDE_NS_EL0;
635+
613636
memset(&attr, 0, sizeof(struct perf_event_attr));
614637
attr.type = arm_pmu->pmu.type;
615638
attr.size = sizeof(attr);
616639
attr.pinned = 1;
617640
attr.disabled = !kvm_pmu_counter_is_enabled(pmc);
618-
attr.exclude_user = data & ARMV8_PMU_EXCLUDE_EL0 ? 1 : 0;
619-
attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
641+
attr.exclude_user = (u != nsu);
642+
attr.exclude_kernel = (p != nsk);
620643
attr.exclude_hv = 1; /* Don't count EL2 events */
621644
attr.exclude_host = 1; /* Don't count host events */
622645
attr.config = eventsel;
@@ -657,18 +680,13 @@ void kvm_pmu_set_counter_event_type(struct kvm_vcpu *vcpu, u64 data,
657680
u64 select_idx)
658681
{
659682
struct kvm_pmc *pmc = kvm_vcpu_idx_to_pmc(vcpu, select_idx);
660-
u64 reg, mask;
683+
u64 reg;
661684

662685
if (!kvm_vcpu_has_pmu(vcpu))
663686
return;
664687

665-
mask = ARMV8_PMU_EVTYPE_MASK;
666-
mask &= ~ARMV8_PMU_EVTYPE_EVENT;
667-
mask |= kvm_pmu_event_mask(vcpu->kvm);
668-
669688
reg = counter_index_to_evtreg(pmc->idx);
670-
671-
__vcpu_sys_reg(vcpu, reg) = data & mask;
689+
__vcpu_sys_reg(vcpu, reg) = data & kvm_pmu_evtyper_mask(vcpu->kvm);
672690

673691
kvm_pmu_create_perf_event(pmc);
674692
}

arch/arm64/kvm/sys_regs.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -746,8 +746,12 @@ static u64 reset_pmevcntr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
746746

747747
static u64 reset_pmevtyper(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r)
748748
{
749+
/* This thing will UNDEF, who cares about the reset value? */
750+
if (!kvm_vcpu_has_pmu(vcpu))
751+
return 0;
752+
749753
reset_unknown(vcpu, r);
750-
__vcpu_sys_reg(vcpu, r->reg) &= ARMV8_PMU_EVTYPE_MASK;
754+
__vcpu_sys_reg(vcpu, r->reg) &= kvm_pmu_evtyper_mask(vcpu->kvm);
751755

752756
return __vcpu_sys_reg(vcpu, r->reg);
753757
}
@@ -988,7 +992,7 @@ static bool access_pmu_evtyper(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
988992
kvm_pmu_set_counter_event_type(vcpu, p->regval, idx);
989993
kvm_vcpu_pmu_restore_guest(vcpu);
990994
} else {
991-
p->regval = __vcpu_sys_reg(vcpu, reg) & ARMV8_PMU_EVTYPE_MASK;
995+
p->regval = __vcpu_sys_reg(vcpu, reg);
992996
}
993997

994998
return true;

include/kvm/arm_pmu.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ void kvm_vcpu_pmu_resync_el0(void);
101101
})
102102

103103
u8 kvm_arm_pmu_get_pmuver_limit(void);
104+
u64 kvm_pmu_evtyper_mask(struct kvm *kvm);
104105

105106
#else
106107
struct kvm_pmu {
@@ -172,6 +173,10 @@ static inline u8 kvm_arm_pmu_get_pmuver_limit(void)
172173
{
173174
return 0;
174175
}
176+
static inline u64 kvm_pmu_evtyper_mask(struct kvm *kvm)
177+
{
178+
return 0;
179+
}
175180
static inline void kvm_vcpu_pmu_resync_el0(void) {}
176181

177182
#endif

include/linux/perf/arm_pmuv3.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,12 @@
234234
/*
235235
* Event filters for PMUv3
236236
*/
237-
#define ARMV8_PMU_EXCLUDE_EL1 (1U << 31)
238-
#define ARMV8_PMU_EXCLUDE_EL0 (1U << 30)
239-
#define ARMV8_PMU_INCLUDE_EL2 (1U << 27)
237+
#define ARMV8_PMU_EXCLUDE_EL1 (1U << 31)
238+
#define ARMV8_PMU_EXCLUDE_EL0 (1U << 30)
239+
#define ARMV8_PMU_EXCLUDE_NS_EL1 (1U << 29)
240+
#define ARMV8_PMU_EXCLUDE_NS_EL0 (1U << 28)
241+
#define ARMV8_PMU_INCLUDE_EL2 (1U << 27)
242+
#define ARMV8_PMU_EXCLUDE_EL3 (1U << 26)
240243

241244
/*
242245
* PMUSERENR: user enable reg

0 commit comments

Comments
 (0)