KVM: arm64: Mask out filtered events in PCMEID{0,1}_EL1
authorMarc Zyngier <maz@kernel.org>
Thu, 12 Mar 2020 16:11:24 +0000 (16:11 +0000)
committerMarc Zyngier <maz@kernel.org>
Tue, 29 Sep 2020 13:19:39 +0000 (14:19 +0100)
As we can now hide events from the guest, let's also adjust its view of
PCMEID{0,1}_EL1 so that it can figure out why some common events are not
counting as they should.

The astute user can still look into the TRM for their CPU and find out
they've been cheated, though. Nobody's perfect.

Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/pmu-emul.c
arch/arm64/kvm/sys_regs.c
include/kvm/arm_pmu.h

index 8cd365968af1dfb3f65c35058fa698557b8c6897..ee13c5eecd3d51a2a6c6b0cf8e54bef53accfbcd 100644 (file)
@@ -763,6 +763,35 @@ static int kvm_pmu_probe_pmuver(void)
        return pmuver;
 }
 
+u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
+{
+       unsigned long *bmap = vcpu->kvm->arch.pmu_filter;
+       u64 val, mask = 0;
+       int base, i;
+
+       if (!pmceid1) {
+               val = read_sysreg(pmceid0_el0);
+               base = 0;
+       } else {
+               val = read_sysreg(pmceid1_el0);
+               base = 32;
+       }
+
+       if (!bmap)
+               return val;
+
+       for (i = 0; i < 32; i += 8) {
+               u64 byte;
+
+               byte = bitmap_get_value8(bmap, base + i);
+               mask |= byte << i;
+               byte = bitmap_get_value8(bmap, 0x4000 + base + i);
+               mask |= byte << (32 + i);
+       }
+
+       return val & mask;
+}
+
 bool kvm_arm_support_pmu_v3(void)
 {
        /*
index 077293b5115fa06e6005d9cad8faafc8915a73f0..20ab2a7d37cacf2084a64cea839a992678d48938 100644 (file)
@@ -769,10 +769,7 @@ static bool access_pmceid(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
        if (pmu_access_el0_disabled(vcpu))
                return false;
 
-       if (!(p->Op2 & 1))
-               pmceid = read_sysreg(pmceid0_el0);
-       else
-               pmceid = read_sysreg(pmceid1_el0);
+       pmceid = kvm_pmu_get_pmceid(vcpu, (p->Op2 & 1));
 
        p->regval = pmceid;
 
index 6db030439e29c287ece08ab5353080fcfe0de39f..98cbfe885a537d88a4ce0f03b0b69f1715919737 100644 (file)
@@ -34,6 +34,7 @@ struct kvm_pmu {
 u64 kvm_pmu_get_counter_value(struct kvm_vcpu *vcpu, u64 select_idx);
 void kvm_pmu_set_counter_value(struct kvm_vcpu *vcpu, u64 select_idx, u64 val);
 u64 kvm_pmu_valid_counter_mask(struct kvm_vcpu *vcpu);
+u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1);
 void kvm_pmu_vcpu_init(struct kvm_vcpu *vcpu);
 void kvm_pmu_vcpu_reset(struct kvm_vcpu *vcpu);
 void kvm_pmu_vcpu_destroy(struct kvm_vcpu *vcpu);
@@ -108,6 +109,10 @@ static inline int kvm_arm_pmu_v3_enable(struct kvm_vcpu *vcpu)
 {
        return 0;
 }
+static inline u64 kvm_pmu_get_pmceid(struct kvm_vcpu *vcpu, bool pmceid1)
+{
+       return 0;
+}
 #endif
 
 #endif