mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
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 <suzuki.poulose@arm.com> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com> Link: https://lore.kernel.org/r/20231019185618.3442949-3-oliver.upton@linux.dev Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
This commit is contained in:
parent
bc512d6a9b
commit
ae8d3522e5
@ -69,6 +69,11 @@ u64 kvm_pmu_evtyper_mask(struct kvm *kvm)
|
||||
if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL2, pfr0))
|
||||
mask |= ARMV8_PMU_INCLUDE_EL2;
|
||||
|
||||
if (SYS_FIELD_GET(ID_AA64PFR0_EL1, EL3, pfr0))
|
||||
mask |= ARMV8_PMU_EXCLUDE_NS_EL0 |
|
||||
ARMV8_PMU_EXCLUDE_NS_EL1 |
|
||||
ARMV8_PMU_EXCLUDE_EL3;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
@ -596,6 +601,7 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
|
||||
struct perf_event *event;
|
||||
struct perf_event_attr attr;
|
||||
u64 eventsel, reg, data;
|
||||
bool p, u, nsk, nsu;
|
||||
|
||||
reg = counter_index_to_evtreg(pmc->idx);
|
||||
data = __vcpu_sys_reg(vcpu, reg);
|
||||
@ -622,13 +628,18 @@ static void kvm_pmu_create_perf_event(struct kvm_pmc *pmc)
|
||||
!test_bit(eventsel, vcpu->kvm->arch.pmu_filter))
|
||||
return;
|
||||
|
||||
p = data & ARMV8_PMU_EXCLUDE_EL1;
|
||||
u = data & ARMV8_PMU_EXCLUDE_EL0;
|
||||
nsk = data & ARMV8_PMU_EXCLUDE_NS_EL1;
|
||||
nsu = data & ARMV8_PMU_EXCLUDE_NS_EL0;
|
||||
|
||||
memset(&attr, 0, sizeof(struct perf_event_attr));
|
||||
attr.type = arm_pmu->pmu.type;
|
||||
attr.size = sizeof(attr);
|
||||
attr.pinned = 1;
|
||||
attr.disabled = !kvm_pmu_counter_is_enabled(pmc);
|
||||
attr.exclude_user = data & ARMV8_PMU_EXCLUDE_EL0 ? 1 : 0;
|
||||
attr.exclude_kernel = data & ARMV8_PMU_EXCLUDE_EL1 ? 1 : 0;
|
||||
attr.exclude_user = (u != nsu);
|
||||
attr.exclude_kernel = (p != nsk);
|
||||
attr.exclude_hv = 1; /* Don't count EL2 events */
|
||||
attr.exclude_host = 1; /* Don't count host events */
|
||||
attr.config = eventsel;
|
||||
|
@ -234,9 +234,12 @@
|
||||
/*
|
||||
* Event filters for PMUv3
|
||||
*/
|
||||
#define ARMV8_PMU_EXCLUDE_EL1 (1U << 31)
|
||||
#define ARMV8_PMU_EXCLUDE_EL0 (1U << 30)
|
||||
#define ARMV8_PMU_INCLUDE_EL2 (1U << 27)
|
||||
#define ARMV8_PMU_EXCLUDE_EL1 (1U << 31)
|
||||
#define ARMV8_PMU_EXCLUDE_EL0 (1U << 30)
|
||||
#define ARMV8_PMU_EXCLUDE_NS_EL1 (1U << 29)
|
||||
#define ARMV8_PMU_EXCLUDE_NS_EL0 (1U << 28)
|
||||
#define ARMV8_PMU_INCLUDE_EL2 (1U << 27)
|
||||
#define ARMV8_PMU_EXCLUDE_EL3 (1U << 26)
|
||||
|
||||
/*
|
||||
* PMUSERENR: user enable reg
|
||||
|
Loading…
Reference in New Issue
Block a user