Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: x86: Add fixed counters to PMU filter

Updates KVM_CAP_PMU_EVENT_FILTER so it can also whitelist or blacklist
fixed counters.

Signed-off-by: Eric Hankland <ehankland@google.com>
[No need to check padding fields for zero. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Eric Hankland and committed by
Paolo Bonzini
30cd8604 88dddc11

+35 -12
+10 -5
Documentation/virtual/kvm/api.txt
··· 4090 4090 Returns: 0 on success, -1 on error 4091 4091 4092 4092 struct kvm_pmu_event_filter { 4093 - __u32 action; 4094 - __u32 nevents; 4095 - __u64 events[0]; 4093 + __u32 action; 4094 + __u32 nevents; 4095 + __u32 fixed_counter_bitmap; 4096 + __u32 flags; 4097 + __u32 pad[4]; 4098 + __u64 events[0]; 4096 4099 }; 4097 4100 4098 4101 This ioctl restricts the set of PMU events that the guest can program. 4099 4102 The argument holds a list of events which will be allowed or denied. 4100 4103 The eventsel+umask of each event the guest attempts to program is compared 4101 4104 against the events field to determine whether the guest should have access. 4102 - This only affects general purpose counters; fixed purpose counters can 4103 - be disabled by changing the perfmon CPUID leaf. 4105 + The events field only controls general purpose counters; fixed purpose 4106 + counters are controlled by the fixed_counter_bitmap. 4107 + 4108 + No flags are defined yet, the field must be zero. 4104 4109 4105 4110 Valid values for 'action': 4106 4111 #define KVM_PMU_EVENT_ALLOW 0
+6 -3
arch/x86/include/uapi/asm/kvm.h
··· 435 435 436 436 /* for KVM_CAP_PMU_EVENT_FILTER */ 437 437 struct kvm_pmu_event_filter { 438 - __u32 action; 439 - __u32 nevents; 440 - __u64 events[0]; 438 + __u32 action; 439 + __u32 nevents; 440 + __u32 fixed_counter_bitmap; 441 + __u32 flags; 442 + __u32 pad[4]; 443 + __u64 events[0]; 441 444 }; 442 445 443 446 #define KVM_PMU_EVENT_ALLOW 0
+19 -4
arch/x86/kvm/pmu.c
··· 19 19 #include "lapic.h" 20 20 #include "pmu.h" 21 21 22 - /* This keeps the total size of the filter under 4k. */ 23 - #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 63 22 + /* This is enough to filter the vast majority of currently defined events. */ 23 + #define KVM_PMU_EVENT_FILTER_MAX_EVENTS 300 24 24 25 25 /* NOTE: 26 26 * - Each perf counter is defined as "struct kvm_pmc"; ··· 206 206 { 207 207 unsigned en_field = ctrl & 0x3; 208 208 bool pmi = ctrl & 0x8; 209 + struct kvm_pmu_event_filter *filter; 210 + struct kvm *kvm = pmc->vcpu->kvm; 209 211 210 212 pmc_stop_counter(pmc); 211 213 212 214 if (!en_field || !pmc_is_enabled(pmc)) 213 215 return; 216 + 217 + filter = srcu_dereference(kvm->arch.pmu_event_filter, &kvm->srcu); 218 + if (filter) { 219 + if (filter->action == KVM_PMU_EVENT_DENY && 220 + test_bit(idx, (ulong *)&filter->fixed_counter_bitmap)) 221 + return; 222 + if (filter->action == KVM_PMU_EVENT_ALLOW && 223 + !test_bit(idx, (ulong *)&filter->fixed_counter_bitmap)) 224 + return; 225 + } 214 226 215 227 pmc_reprogram_counter(pmc, PERF_TYPE_HARDWARE, 216 228 kvm_x86_ops->pmu_ops->find_fixed_event(idx), ··· 397 385 tmp.action != KVM_PMU_EVENT_DENY) 398 386 return -EINVAL; 399 387 388 + if (tmp.flags != 0) 389 + return -EINVAL; 390 + 400 391 if (tmp.nevents > KVM_PMU_EVENT_FILTER_MAX_EVENTS) 401 392 return -E2BIG; 402 393 ··· 421 406 mutex_unlock(&kvm->lock); 422 407 423 408 synchronize_srcu_expedited(&kvm->srcu); 424 - r = 0; 409 + r = 0; 425 410 cleanup: 426 411 kfree(filter); 427 - return r; 412 + return r; 428 413 }