Skip to content

Commit ae8d352

Browse files
committed
KVM: arm64: Add PMU event filter bits required if EL3 is implemented
Suzuki noticed that KVM's PMU emulation is oblivious to the NSU and NSK event filter bits. On systems that have EL3 these bits modify the filter behavior in non-secure EL0 and EL1, respectively. Even though the kernel doesn't use these bits, it is entirely possible some other guest OS does. Additionally, it would appear that these and the M bit are required by the architecture if EL3 is implemented. Allow the EL3 event filter bits to be set if EL3 is advertised in the guest's ID register. Implement the behavior of NSU and NSK according to the pseudocode, and entirely ignore the M bit for perf event creation. Reported-by: Suzuki K Poulose <[email protected]> Reviewed-by: Suzuki K Poulose <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Oliver Upton <[email protected]>
1 parent bc512d6 commit ae8d352

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

arch/arm64/kvm/pmu-emul.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ u64 kvm_pmu_evtyper_mask(struct kvm *kvm)
6969
if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL2, pfr0))
7070
mask |= ARMV8_PMU_INCLUDE_EL2;
7171

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+
7277
return mask;
7378
}
7479

@@ -596,6 +601,7 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
596601
struct perf_event *event;
597602
struct perf_event_attr attr;
598603
u64 eventsel, reg, data;
604+
bool p, u, nsk, nsu;
599605

600606
reg = counter_index_to_evtreg(pmc->idx);
601607
data = __vcpu_sys_reg(vcpu, reg);
@@ -622,13 +628,18 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
622628
!test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
623629
return;
624630

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+
625636
memset(&attr, 0, sizeof(struct perf_event_attr));
626637
attr.type = arm_pmu->pmu.type;
627638
attr.size = sizeof(attr);
628639
attr.pinned = 1;
629640
attr.disabled = !kvm_pmu_counter_is_enabled(pmc);
630-
attr.exclude_user = data & ARMV8_PMU_EXCLUDE_EL0 ? 1 : 0;
631-
attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
641+
attr.exclude_user = (u != nsu);
642+
attr.exclude_kernel = (p != nsk);
632643
attr.exclude_hv = 1; /* Don't count EL2 events */
633644
attr.exclude_host = 1; /* Don't count host events */
634645
attr.config = eventsel;

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)